Index: /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/LICENSE
===================================================================
--- /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/LICENSE	(revision 5870)
+++ /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/LICENSE	(revision 5870)
@@ -0,0 +1,12 @@
+All Files of this Software are licensed under the Creative Commons 
+Attribution-NonCommercial-ShareAlike 3.0 Unported 
+License if not stated otherwise in a Files Head. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+
+Alternatively, this plugin may be distributed and executed on hardware which
+is licensed by Dream Multimedia GmbH.
+
+This plugin is NOT free software. It is open source, you are allowed to
+modify it (if you keep the license), but it may not be commercially 
+distributed other than under the conditions noted above.
Index: /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/WerbeZapper.py
===================================================================
--- /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/WerbeZapper.py	(revision 5870)
+++ /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/WerbeZapper.py	(revision 5870)
@@ -0,0 +1,157 @@
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.MessageBox import MessageBox
+
+# Timer
+from enigma import eTimer
+
+class WerbeZapper:
+	"""Simple Plugin to automatically zap back to a Service after a given amount
+	   of time."""
+
+	def __init__(self, session, servicelist, cleanupfnc = None):
+		# Save Session&Servicelist
+		self.session = session
+		self.servicelist = servicelist
+
+		# Create Timer
+		self.zap_timer = eTimer()
+		self.zap_timer.callback.append(self.zap)
+
+		# Initialize services
+		self.zap_service = None
+		self.move_service = None
+		self.root = None
+
+		# Keep Cleanup
+		self.cleanupfnc = cleanupfnc
+
+	def showSelection(self):
+		# Check if timer is active
+		if self.zap_timer.isActive():
+			# Ask if we should stop the running timer
+			self.session.openWithCallback(
+				self.confirmStop,
+				MessageBox,
+				_("Timer already running.\nStop it?")
+			)
+		else:
+			from Screens.ChoiceBox import ChoiceBox
+
+			# Select Timer Length
+			self.session.openWithCallback(
+				self.choiceCallback,
+				ChoiceBox,
+				_("When to Zap back?"),
+				(
+					('1 ' + _('minute'), 1),
+					('2 ' + _('minutes'), 2),
+					('3 ' + _('minutes'), 3),
+					('4 ' + _('minutes'), 4),
+					('5 ' + _('minutes'), 5),
+					('6 ' + _('minutes'), 6),
+					('7 ' + _('minutes'), 7),
+					('8 ' + _('minutes'), 8),
+					('9 ' + _('minutes'), 9),
+					( _("Custom"), 'custom')
+				)
+			)
+
+	def confirmStop(self, result):
+		if result:
+			# Stop Timer
+			self.zap_timer.stop()
+
+			# Reset Vars
+			self.zap_service = None
+			self.move_service = None
+
+			# Clean up if possible
+			if self.cleanupfnc:
+				self.cleanupfnc()
+
+	def choiceCallback(self, result):
+		result = result and result[1]
+		if result == "custom":
+			from Screens.InputBox import InputBox
+			from Components.Input import Input
+
+			self.session.openWithCallback(
+				self.inputCallback,
+				InputBox,
+				title=_("How many minutes to wait until zapping back?"),
+				text="10",
+				maxSize=False,
+				type=Input.NUMBER
+			)
+		elif result is not None:
+			self.confirmStart(result)
+		# Clean up if possible
+		elif self.cleanupfnc:
+			self.cleanupfnc()
+
+	def inputCallback(self, result):
+		if result is not None:
+			self.confirmStart(int(result))
+		# Clean up if possible
+		elif self.cleanupfnc:
+			self.cleanupfnc()
+
+
+	def confirmStart(self, duration):
+		# Remind the User of what he just did
+		self.session.open(
+			MessageBox,
+			_("Zapping back in %d Minutes") % (duration),
+			type = MessageBox.TYPE_INFO,
+			timeout = 3
+		)
+
+		# Keep any service related information (zap_service might not equal move_service -> subservices)
+		self.zap_service = self.session.nav.getCurrentlyPlayingServiceReference()
+		self.move_service = self.servicelist.getCurrentSelection()
+		self.root = self.servicelist.getRoot()
+
+		#import ServiceReference
+		#print [str(ServiceReference.ServiceReference(x)) for x in self.servicelist.getCurrentServicePath()]
+		#print ServiceReference.ServiceReference(self.servicelist.getRoot())
+
+		# Start Timer
+		self.zap_timer.startLongTimer(duration*60)
+
+	def zap(self):
+		if self.zap_service is not None:
+			if self.root:
+				import ServiceReference
+				if not self.servicelist.preEnterPath(str(ServiceReference.ServiceReference(self.root))):
+					if self.servicelist.isBasePathEqual(self.root):
+						self.servicelist.pathUp()
+						self.servicelist.enterPath(self.root)
+					else:
+						currentRoot = self.servicelist.getRoot()
+						if currentRoot is None or currentRoot != self.root:
+							self.servicelist.clearPath()
+							self.servicelist.enterPath(self.root)
+
+			if self.move_service:
+				self.servicelist.setCurrentSelection(self.move_service)
+				self.servicelist.zap()
+
+			# Play zap_service (won't rezap if service equals to move_service)
+			self.session.nav.playService(self.zap_service)
+
+			# Reset services
+			self.zap_service = None
+			self.move_service = None
+			self.root = None
+
+		# Clean up if possible
+		if self.cleanupfnc:
+			self.cleanupfnc()
+
+	def shutdown(self):
+		self.zap_timer.callback.remove(self.zap)
+		self.zap_timer = None
+
Index: /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/__init__.py
===================================================================
--- /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/__init__.py	(revision 5870)
+++ /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/__init__.py	(revision 5870)
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
+from os import environ as os_environ
+import gettext
+
+def localeInit():
+	lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
+	os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
+	gettext.bindtextdomain("WerbeZapper", resolveFilename(SCOPE_PLUGINS, "Extensions/WerbeZapper/locale"))
+
+def _(txt):
+	t = gettext.dgettext("WerbeZapper", txt)
+	if t == txt:
+		print "[WerbeZapper] fallback to default translation for", txt
+		t = gettext.gettext(txt)
+	return t
+
+localeInit()
+language.addCallback(localeInit)
+
Index: /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/maintainer.info
===================================================================
--- /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/maintainer.info	(revision 5870)
+++ /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+moritz.venn@freaque.net
+WerbeZapper
Index: /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/plugin.py
===================================================================
--- /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/plugin.py	(revision 5870)
+++ /ipk/source/swapbrowsers_werbezapper_1_0/var/swap/extensions/WerbeZapper/plugin.py	(revision 5870)
@@ -0,0 +1,33 @@
+# for localized messages
+from . import _
+
+# Plugin
+from Plugins.Plugin import PluginDescriptor
+
+zapperInstance = None
+
+# Mainfunction
+def main(session, servicelist, **kwargs):
+	# Create Instance if none present, show Dialog afterwards
+	global zapperInstance
+	if zapperInstance is None:
+		from WerbeZapper import WerbeZapper
+		zapperInstance = WerbeZapper(session, servicelist, cleanup)
+	zapperInstance.showSelection()
+
+def cleanup():
+	global zapperInstance
+	if zapperInstance is not None:
+		zapperInstance.shutdown()
+		zapperInstance = None
+
+def Plugins(**kwargs):
+ 	return [
+		PluginDescriptor(
+			name = "Werbezapper",
+			description = _("Automatically zaps back to current service after given Time"),
+			where = PluginDescriptor.WHERE_EXTENSIONSMENU,
+			fnc = main
+		)
+	]
+
Index: /ipk/source/swapbrowsers_zaphistorybrowser_1_2/var/swap/extensions/zaphistorybrowser/plugin.py
===================================================================
--- /ipk/source/swapbrowsers_zaphistorybrowser_1_2/var/swap/extensions/zaphistorybrowser/plugin.py	(revision 5870)
+++ /ipk/source/swapbrowsers_zaphistorybrowser_1_2/var/swap/extensions/zaphistorybrowser/plugin.py	(revision 5870)
@@ -0,0 +1,136 @@
+##
+## Zap-History Browser
+## by AliAbdul
+## modded by MC_Ohr from AAF-Digital HD Forum
+##
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.MenuList import MenuList
+from enigma import eServiceCenter
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+
+#--- Civer start Skindetection----
+from enigma import getDesktop
+
+global HDskin
+global KSskin
+HDskin = False
+KSskin = False
+try:
+	skin_w = getDesktop(0).size().width()
+	if skin_w == 1280:
+		HDskin = True
+		KSskin = False
+	elif skin_w == 1024:
+		HDskin = False
+		KSskin = True
+	else:
+		HDskin = False
+		KSskin = False
+except:
+	HDskin = False
+	KSskin = False
+#--- Civer end Skindetection----
+
+################################################
+
+class ZapHistoryBrowser(Screen):
+#--- Civer start (added skinKS and skinHD)----
+	skin = """
+	<screen position="200,80" size="320,440" title="Zap-History Browser" >
+		<ePixmap pixmap="skin_default/buttons/red.png" position="10,0" size="140,40" transparent="1" alphatest="on" />
+		<ePixmap pixmap="skin_default/buttons/green.png" position="170,0" size="140,40" transparent="1" alphatest="on" />
+		<widget name="key_red" position="10,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+		<widget name="key_green" position="170,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+		<widget name="list" position="0,40" size="320,400" scrollbarMode="showOnDemand" />
+	</screen>"""
+	
+	skinKS = """
+	<screen position="352,80" size="320,440" title="Zap-History Browser" >
+		<ePixmap pixmap="skin_default/buttons/red.png" position="10,0" size="140,40" transparent="1" alphatest="on" />
+		<ePixmap pixmap="skin_default/buttons/green.png" position="170,0" size="140,40" transparent="1" alphatest="on" />
+		<widget name="key_red" position="10,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+		<widget name="key_green" position="170,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+		<widget name="list" position="0,40" size="320,400" scrollbarMode="showOnDemand" />
+	</screen>"""
+	
+	skinHD = """
+	<screen position="480,140" size="320,440" title="Zap-History Browser" >
+		<ePixmap pixmap="skin_default/buttons/red.png" position="10,0" size="140,40" transparent="1" alphatest="on" />
+		<ePixmap pixmap="skin_default/buttons/green.png" position="170,0" size="140,40" transparent="1" alphatest="on" />
+		<widget name="key_red" position="10,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+		<widget name="key_green" position="170,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
+		<widget name="list" position="0,40" size="320,400" scrollbarMode="showOnDemand" />
+	</screen>"""
+#--- Civer end (added skinKS and skinHD)----
+
+	def __init__(self, session, servicelist):
+		#---- Civer start skindetection---
+		if HDskin:
+			self.skin = ZapHistoryBrowser.skinHD
+		elif KSskin:
+			self.skin = ZapHistoryBrowser.skinKS
+		else:
+			self.skin = ZapHistoryBrowser.skin
+#---- Civer end skindetection---
+		Screen.__init__(self, session)
+
+		self.servicelist = servicelist
+		self.serviceHandler = eServiceCenter.getInstance()
+
+		self["list"] = MenuList([])
+		self["key_red"] = Label(_("Clear"))
+		self["key_green"] = Label(_("Delete"))
+
+		self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
+			{
+				"ok": self.zap,
+				"cancel": self.close,
+				"red": self.clear,
+				"green": self.delete
+			}, prio=-1)
+
+		self.onLayoutFinish.append(self.buildList)
+
+	def buildList(self):
+		list = []
+		for x in self.servicelist.history:
+			if len(x) == 2:
+				#print "Single-Bouquet!!!"
+				ref = x[1]
+			else:
+				#print "Multi-Bouquet!!!"
+				ref = x[2]
+			info = self.serviceHandler.info(ref)
+			name = info.getName(ref).replace('\xc2\x86', '').replace('\xc2\x87', '')
+			list.append(name)
+		list.reverse()
+		self["list"].setList(list)
+
+	def zap(self):
+		length = len(self.servicelist.history)
+		if length > 0:
+			self.servicelist.history_pos = (length - self["list"].getSelectionIndex()) - 1
+			self.servicelist.setHistoryPath()
+			self.close()
+
+	def clear(self):
+		for i in range(0, len(self.servicelist.history)):
+			del self.servicelist.history[0]
+		self.buildList()
+
+	def delete(self):
+		length = len(self.servicelist.history)
+		if length > 0:
+			idx = (length - self["list"].getSelectionIndex()) - 1
+			del self.servicelist.history[idx]
+			self.buildList()
+
+################################################
+
+def main(session, servicelist, **kwargs):
+	session.open(ZapHistoryBrowser, servicelist)
+
+def Plugins(**kwargs):
+	return PluginDescriptor(name=_("Zap-History Browser"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, fnc=main)
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/LICENSE
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/LICENSE	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/LICENSE	(revision 5870)
@@ -0,0 +1,12 @@
+This plugin is licensed under the Creative Commons 
+Attribution-NonCommercial-ShareAlike 3.0 Unported 
+License. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+
+Alternatively, this plugin may be distributed and executed on hardware which
+is licensed by Dream Multimedia GmbH.
+
+This plugin is NOT free software. It is open source, you are allowed to
+modify it (if you keep the license), but it may not be commercially 
+distributed other than under the conditions noted above.
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/keymap.xml
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/keymap.xml	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/keymap.xml	(revision 5870)
@@ -0,0 +1,45 @@
+<keymap>
+	<map context="CutlistSeekActions">
+<!--		<device name="dreambox remote control (native)">   -->
+			<key id="KEY_YELLOW" mapto="pauseService" flags="m" />
+			<key id="KEY_GREEN" mapto="unPauseService" flags="m" />
+			<key id="KEY_RED" mapto="seekBack" flags="b" />
+			<key id="KEY_BLUE" mapto="seekFwd" flags="b" />
+			<key id="KEY_RED" mapto="seekBackManual" flags="l" />
+			<key id="KEY_BLUE" mapto="seekFwdManual" flags="l" />
+<!--		</device>   -->
+		<device name="dreambox advanced remote control (native)">
+			<key id="KEY_PLAY" mapto="playpauseService" flags="m" />
+			<!--key id="KEY_GREEN" mapto="unPauseService" flags="m" /-->
+			<key id="KEY_PREVIOUSSONG" mapto="seekBack" flags="b" />
+			<key id="KEY_PREVIOUSSONG" mapto="seekBackManual" flags="l" />
+			<key id="KEY_NEXTSONG" mapto="seekFwd" flags="b" />
+			<key id="KEY_NEXTSONG" mapto="seekFwdManual" flags="l" />
+		</device>
+		
+		<key id="KEY_LEFT" mapto="seek:-1" flags="m" />
+		<key id="KEY_RIGHT" mapto="seek:1" flags="m" />
+
+		<key id="KEY_1" mapto="seek:-10" flags="m" />
+		<key id="KEY_3" mapto="seek:10" flags="m" />
+		<key id="KEY_4" mapto="seek:-30" flags="m" />
+		<key id="KEY_6" mapto="seek:30" flags="m" />
+		<key id="KEY_7" mapto="seek:-90" flags="m" />
+		<key id="KEY_9" mapto="seek:90" flags="m" />
+		<key id="KEY_PREVIOUS" mapto="seek:-300" flags="m" />
+		<key id="KEY_NEXT" mapto="seek:300" flags="m" />
+	</map>
+
+	<map context="CutListEditorActions">
+<!--		<key id="KEY_NEXT" mapto="setIn" flags="m" />
+		<key id="KEY_PREVIOUS" mapto="setOut" flags="m" /> -->
+<!--		<key id="KEY_0" mapto="setMark" flags="m" />  -->
+<!--		<key id="KEY_CHANNELUP" mapto="addMark" flags="m" />
+		<key id="KEY_CHANNELDOWN" mapto="removeMark" flags="m" /> -->
+		<key id="KEY_HOME" mapto="leave" flags="m" />
+		<key id="KEY_EXIT" mapto="leave" flags="m" />
+		<key id="KEY_ESC" mapto="leave" flags="m" />
+		<key id="KEY_OK" mapto="showMenu" flags="m" />
+		<key id="KEY_ENTER" mapto="showMenu" flags="m" />
+	</map>
+</keymap>
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/plugin.py
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/plugin.py	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/CutListEditor/plugin.py	(revision 5870)
@@ -0,0 +1,409 @@
+from Plugins.Plugin import PluginDescriptor
+
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Components.ServicePosition import ServicePositionGauge
+from Components.ActionMap import HelpableActionMap
+from Components.MultiContent import MultiContentEntryText
+from Components.ServiceEventTracker import ServiceEventTracker, InfoBarBase
+from Components.VideoWindow import VideoWindow
+from Components.Label import Label
+from Screens.InfoBarGenerics import InfoBarSeek, InfoBarCueSheetSupport
+from Components.GUIComponent import GUIComponent
+from enigma import eListboxPythonMultiContent, eListbox, getDesktop, gFont, iPlayableService, RT_HALIGN_RIGHT
+from Screens.FixedMenu import FixedMenu
+from Screens.HelpMenu import HelpableScreen
+from ServiceReference import ServiceReference
+from Components.Sources.List import List
+
+import bisect
+
+def CutListEntry(where, what):
+	w = where / 90
+	ms = w % 1000
+	s = (w / 1000) % 60
+	m = (w / 60000) % 60
+	h = w / 3600000
+	if what == 0:
+		type = "IN"
+		type_col = 0x004000
+	elif what == 1:
+		type = "OUT"
+		type_col = 0x400000
+	elif what == 2:
+		type = "MARK"
+		type_col = 0x000040
+	elif what == 3:
+		type = "LAST"
+		type_col = 0x000000
+	return ((where, what), "%dh:%02dm:%02ds:%03d" % (h, m, s, ms), type, type_col)
+
+class CutListContextMenu(FixedMenu):
+	RET_STARTCUT = 0
+	RET_ENDCUT = 1
+	RET_DELETECUT = 2
+	RET_MARK = 3
+	RET_DELETEMARK = 4
+	RET_REMOVEBEFORE = 5
+	RET_REMOVEAFTER = 6
+	RET_GRABFRAME = 7
+
+	SHOW_STARTCUT = 0
+	SHOW_ENDCUT = 1
+	SHOW_DELETECUT = 2
+
+	def __init__(self, session, state, nearmark):
+		menu = [(_("back"), self.close)] #, (None, )]
+
+		if state == self.SHOW_STARTCUT:
+			menu.append((_("start cut here"), self.startCut))
+		else:
+			menu.append((_("start cut here"), ))
+
+		if state == self.SHOW_ENDCUT:
+			menu.append((_("end cut here"), self.endCut))
+		else:
+			menu.append((_("end cut here"), ))
+
+		if state == self.SHOW_DELETECUT:
+			menu.append((_("delete cut"), self.deleteCut))
+		else:
+			menu.append((_("delete cut"), ))
+
+		menu.append((_("remove before this position"), self.removeBefore))
+		menu.append((_("remove after this position"), self.removeAfter))
+
+#		menu.append((None, ))
+
+		if not nearmark:
+			menu.append((_("insert mark here"), self.insertMark))
+		else:
+			menu.append((_("remove this mark"), self.removeMark))
+
+		menu.append((_("grab this frame as bitmap"), self.grabFrame))
+		FixedMenu.__init__(self, session, _("Cut"), menu)
+		self.skinName = "Menu"
+
+	def startCut(self):
+		self.close(self.RET_STARTCUT)
+
+	def endCut(self):
+		self.close(self.RET_ENDCUT)
+
+	def deleteCut(self):
+		self.close(self.RET_DELETECUT)
+
+	def insertMark(self):
+		self.close(self.RET_MARK)
+
+	def removeMark(self):
+		self.close(self.RET_DELETEMARK)
+
+	def removeBefore(self):
+		self.close(self.RET_REMOVEBEFORE)
+
+	def removeAfter(self):
+		self.close(self.RET_REMOVEAFTER)
+
+	def grabFrame(self):
+		self.close(self.RET_GRABFRAME)
+
+class CutListEditor(Screen, InfoBarBase, InfoBarSeek, InfoBarCueSheetSupport, HelpableScreen):
+	skin = """
+	<screen position="0,0" size="720,576" title="Cutlist editor" flags="wfNoBorder">
+		<eLabel text="Cutlist editor" position="65,60" size="300,25" font="Regular;20" />
+		<widget source="global.CurrentTime" render="Label" position="268,60" size="394,20" font="Regular;20" halign="right">
+			<convert type="ClockToText">Format:%A %B %d, %H:%M</convert>
+		</widget>
+		<eLabel position="268,98" size="394,304" backgroundColor="#505555" />
+		<widget name="Video" position="270,100" zPosition="1" size="390,300" backgroundColor="transparent" />
+		<widget source="session.CurrentService" render="Label" position="135,405" size="450,50" font="Regular;22" halign="center" valign="center">
+			<convert type="ServiceName">Name</convert>
+		</widget>
+		<widget source="session.CurrentService" render="Label" position="320,450" zPosition="1" size="420,25" font="Regular;20" halign="left" valign="center">
+			<convert type="ServicePosition">Position,Detailed</convert>
+		</widget>
+		<widget name="SeekState" position="210,450" zPosition="1" size="100,25" halign="right" font="Regular;20" valign="center" />
+		<eLabel position="48,98" size="204,274" backgroundColor="#505555" />
+		<eLabel position="50,100" size="200,270" backgroundColor="#000000" />
+		<widget source="cutlist" position="50,100" zPosition="1" size="200,270" scrollbarMode="showOnDemand" transparent="1" render="Listbox" >
+			<convert type="TemplatedMultiContent">
+				{"template": [
+						MultiContentEntryText(size=(125, 20), text = 1, backcolor = MultiContentTemplateColor(3)),
+						MultiContentEntryText(pos=(125,0), size=(50, 20), text = 2, flags = RT_HALIGN_RIGHT, backcolor = MultiContentTemplateColor(3))
+					],
+				 "fonts": [gFont("Regular", 18)],
+				 "itemHeight": 20
+				}
+			</convert>
+		</widget>
+		<widget name="Timeline" position="50,485" size="615,20" backgroundColor="#505555" pointer="skin_default/position_arrow.png:3,5" foregroundColor="black" />
+		<ePixmap pixmap="skin_default/icons/mp_buttons.png" position="305,515" size="109,13" alphatest="on" />
+	</screen>"""
+
+	def __init__(self, session, service):
+		self.skin = CutListEditor.skin
+		Screen.__init__(self, session)
+		InfoBarSeek.__init__(self, actionmap = "CutlistSeekActions")
+		InfoBarCueSheetSupport.__init__(self)
+		InfoBarBase.__init__(self, steal_current_service = True)
+		HelpableScreen.__init__(self)
+		self.old_service = session.nav.getCurrentlyPlayingServiceReference()
+		session.nav.playService(service)
+
+		service = session.nav.getCurrentService()
+		cue = service and service.cueSheet()
+		if cue is not None:
+			# disable cutlists. we want to freely browse around in the movie
+			print "cut lists disabled!"
+			cue.setCutListEnable(0)
+
+		self.downloadCuesheet()
+
+		self["Timeline"] = ServicePositionGauge(self.session.nav)
+		self["cutlist"] = List(self.getCutlist())
+		self["cutlist"].onSelectionChanged.append(self.selectionChanged)
+		self["SeekState"] = Label()
+		self.onPlayStateChanged.append(self.updateStateLabel)
+		self.updateStateLabel(self.seekstate)
+
+		desktopSize = getDesktop(0).size()
+		self["Video"] = VideoWindow(decoder = 0, fb_width=desktopSize.width(), fb_height=desktopSize.height())
+
+		self["actions"] = HelpableActionMap(self, "CutListEditorActions",
+			{
+				"setIn": (self.setIn, _("Make this mark an 'in' point")),
+				"setOut": (self.setOut, _("Make this mark an 'out' point")),
+				"setMark": (self.setMark, _("Make this mark just a mark")),
+				"addMark": (self.__addMark, _("Add a mark")),
+				"removeMark": (self.__removeMark, _("Remove a mark")),
+				"leave": (self.exit, _("Exit editor")),
+				"showMenu": (self.showMenu, _("menu")),
+			}, prio=-4)
+
+		self.tutorial_seen = False
+
+		self.onExecBegin.append(self.showTutorial)
+		self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
+			{
+				iPlayableService.evCuesheetChanged: self.refillList
+			})
+
+		# to track new entries we save the last version of the cutlist
+		self.last_cuts = self.getCutlist()
+		self.cut_start = None
+		self.inhibit_seek = False
+		self.onClose.append(self.__onClose)
+
+	def __onClose(self):
+		self.session.nav.playService(self.old_service)
+
+	def updateStateLabel(self, state):
+		self["SeekState"].setText(state[3].strip())
+
+	def showTutorial(self):
+		if not self.tutorial_seen:
+			self.tutorial_seen = True
+			self.session.open(MessageBox,_("Welcome to the Cutlist editor.\n\nSeek to the start of the stuff you want to cut away. Press OK, select 'start cut'.\n\nThen seek to the end, press OK, select 'end cut'. That's it."), MessageBox.TYPE_INFO)
+
+	def checkSkipShowHideLock(self):
+		pass
+
+	def setType(self, index, type):
+		if len(self.cut_list):
+			self.cut_list[index] = (self.cut_list[index][0], type)
+			self["cutlist"].modifyEntry(index, CutListEntry(*self.cut_list[index]))
+
+	def setIn(self):
+		m = self["cutlist"].getIndex()
+		self.setType(m, 0)
+		self.uploadCuesheet()
+
+	def setOut(self):
+		m = self["cutlist"].getIndex()
+		self.setType(m, 1)
+		self.uploadCuesheet()
+
+	def setMark(self):
+		m = self["cutlist"].getIndex()
+		self.setType(m, 2)
+		self.uploadCuesheet()
+
+	def __addMark(self):
+		self.toggleMark(onlyadd=True, tolerance=90000) # do not allow two marks in <1s
+
+	def __removeMark(self):
+		m = self["cutlist"].getCurrent()
+		m = m and m[0]
+		if m is not None:
+			self.removeMark(m)
+
+	def exit(self):
+		self.close()
+
+	def getCutlist(self):
+		r = [ ]
+		for e in self.cut_list:
+			r.append(CutListEntry(*e))
+		return r
+
+	def selectionChanged(self):
+		if not self.inhibit_seek:
+			where = self["cutlist"].getCurrent()
+			if where is None:
+				print "no selection"
+				return
+			pts = where[0][0]
+			seek = self.getSeek()
+			if seek is None:
+				print "no seek"
+				return
+			seek.seekTo(pts)
+
+	def refillList(self):
+		print "cue sheet changed, refilling"
+		self.downloadCuesheet()
+
+		# get the first changed entry, counted from the end, and select it
+		new_list = self.getCutlist()
+		self["cutlist"].list = new_list
+
+		l1 = len(new_list)
+		l2 = len(self.last_cuts)
+		for i in range(min(l1, l2)):
+			if new_list[l1-i-1] != self.last_cuts[l2-i-1]:
+				self["cutlist"].setIndex(l1-i-1)
+				break
+		self.last_cuts = new_list
+
+	def getStateForPosition(self, pos):
+		state = -1
+		for (where, what) in self.cut_list:
+			if what in [0, 1]:
+				if where < pos:
+					state = what
+				elif where == pos:
+					state = 1
+				elif state == -1:
+					state = 1 - what
+		if state == -1:
+			state = 0
+		return state
+
+	def showMenu(self):
+		curpos = self.cueGetCurrentPosition()
+		if curpos is None:
+			return
+
+		self.setSeekState(self.SEEK_STATE_PAUSE)
+
+		self.context_position = curpos
+
+		self.context_nearest_mark = self.toggleMark(onlyreturn=True)
+
+		cur_state = self.getStateForPosition(curpos)
+		if cur_state == 0:
+			print "currently in 'IN'"
+			if self.cut_start is None or self.context_position < self.cut_start:
+				state = CutListContextMenu.SHOW_STARTCUT
+			else:
+				state = CutListContextMenu.SHOW_ENDCUT
+		else:
+			print "currently in 'OUT'"
+			state = CutListContextMenu.SHOW_DELETECUT
+
+		if self.context_nearest_mark is None:
+			nearmark = False
+		else:
+			nearmark = True
+
+		self.session.openWithCallback(self.menuCallback, CutListContextMenu, state, nearmark)
+
+	def menuCallback(self, *result):
+		if not len(result):
+			return
+		result = result[0]
+
+		if result == CutListContextMenu.RET_STARTCUT:
+			self.cut_start = self.context_position
+		elif result == CutListContextMenu.RET_ENDCUT:
+			# remove in/out marks between the new cut
+			for (where, what) in self.cut_list[:]:
+				if self.cut_start <= where <= self.context_position and what in (0,1):
+					self.cut_list.remove((where, what))
+
+			bisect.insort(self.cut_list, (self.cut_start, 1))
+			bisect.insort(self.cut_list, (self.context_position, 0))
+			self.uploadCuesheet()
+			self.cut_start = None
+		elif result == CutListContextMenu.RET_DELETECUT:
+			out_before = None
+			in_after = None
+
+			for (where, what) in self.cut_list:
+				if what == 1 and where <= self.context_position: # out
+					out_before = (where, what)
+				elif what == 0 and where < self.context_position: # in, before out
+					out_before = None
+				elif what == 0 and where >= self.context_position and in_after is None:
+					in_after = (where, what)
+
+			if out_before is not None:
+				self.cut_list.remove(out_before)
+
+			if in_after is not None:
+				self.cut_list.remove(in_after)
+			self.inhibit_seek = True
+			self.uploadCuesheet()
+			self.inhibit_seek = False
+		elif result == CutListContextMenu.RET_MARK:
+			self.__addMark()
+		elif result == CutListContextMenu.RET_DELETEMARK:
+			self.cut_list.remove(self.context_nearest_mark)
+			self.inhibit_seek = True
+			self.uploadCuesheet()
+			self.inhibit_seek = False
+		elif result == CutListContextMenu.RET_REMOVEBEFORE:
+			# remove in/out marks before current position
+			for (where, what) in self.cut_list[:]:
+				if where <= self.context_position and what in (0,1):
+					self.cut_list.remove((where, what))
+			# add 'in' point
+			bisect.insort(self.cut_list, (self.context_position, 0))
+			self.inhibit_seek = True
+			self.uploadCuesheet()
+			self.inhibit_seek = False
+		elif result == CutListContextMenu.RET_REMOVEAFTER:
+			# remove in/out marks after current position
+			for (where, what) in self.cut_list[:]:
+				if where >= self.context_position and what in (0,1):
+					self.cut_list.remove((where, what))
+			# add 'out' point
+			bisect.insort(self.cut_list, (self.context_position, 1))
+			self.inhibit_seek = True
+			self.uploadCuesheet()
+			self.inhibit_seek = False
+		elif result == CutListContextMenu.RET_GRABFRAME:
+			self.grabFrame()
+
+	# we modify the "play" behavior a bit:
+	# if we press pause while being in slowmotion, we will pause (and not play)
+	def playpauseService(self):
+		if self.seekstate != self.SEEK_STATE_PLAY and not self.isStateSlowMotion(self.seekstate):
+			self.unPauseService()
+		else:
+			self.pauseService()
+
+	def grabFrame(self):
+		path = self.session.nav.getCurrentlyPlayingServiceReference().getPath()
+		from Components.Console import Console
+		grabConsole = Console()
+		cmd = 'grab -vblpr%d "%s"' % (180, path.rsplit('.',1)[0] + ".png")
+		grabConsole.ePopen(cmd)
+		self.playpauseService()
+
+def main(session, service, **kwargs):
+	session.open(CutListEditor, service)
+
+def Plugins(**kwargs):
+ 	return PluginDescriptor(name="Cutlist Editor", description=_("Cutlist editor..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/MovieCut/maintainer.info
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/MovieCut/maintainer.info	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/MovieCut/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+aho@sics.se
+MovieCut-1.2.1
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/MovieCut/plugin.py
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/MovieCut/plugin.py	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/MovieCut/plugin.py	(revision 5870)
@@ -0,0 +1,310 @@
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+from Screens.LocationBox import MovieLocationBox
+import Screens.Standby
+from Components.config import config, ConfigText, ConfigSelection, ConfigNothing, getConfigListEntry
+from Components.ActionMap import ActionMap
+from Components.ConfigList import ConfigList, ConfigListScreen
+from Components.Sources.StaticText import StaticText
+from enigma import eTimer, eServiceCenter, iServiceInformation, eConsoleAppContainer
+from os import access, chmod, X_OK
+
+mcut_path = "/usr/lib/enigma2/python/Plugins/Extensions/MovieCut/bin/mcut"
+# Hack to make sure it is executable
+if not access(mcut_path, X_OK):
+	chmod(mcut_path, 493)
+
+def main(session, service, **kwargs):
+	session.open(MovieCut, service, **kwargs)
+
+def Plugins(**kwargs):
+	return PluginDescriptor(name="MovieCut", description=_("Execute cuts..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
+
+
+class MovieCut(ChoiceBox):
+	def __init__(self, session, service):
+		self.service = service
+		serviceHandler = eServiceCenter.getInstance()
+		path = self.service.getPath()
+		info = serviceHandler.info(self.service)
+		if not info:
+			self.name = path
+		else:
+			self.name = info.getName(self.service)
+		tlist = [
+			(_("Don't cut"), "CALLFUNC", self.confirmed0),
+			(_("Replace the original movie with the cut movie"), "CALLFUNC", self.confirmed1),
+			(_("Place the cut movie in a new file ending with \" cut\""), "CALLFUNC", self.confirmed2),
+			(_("Advanced cut specification..."), "CALLFUNC", self.confirmed3),
+		]
+		ChoiceBox.__init__(self, session, _("How would you like to cut \"%s\"?") % (self.name), list = tlist, selection = 0)
+		self.skinName = "ChoiceBox"
+
+	def confirmed0(self, arg):
+		self.close()
+
+	def confirmed1(self, arg):
+		MovieCutSpawn(self.session, self, [mcut_path, "-r", self.service.getPath()], self.name)
+
+	def confirmed2(self, arg):
+		MovieCutSpawn(self.session, self, [mcut_path, self.service.getPath()], self.name)
+
+	def confirmed3(self, arg):
+		serviceHandler = eServiceCenter.getInstance()
+		info = serviceHandler.info(self.service)
+		path = self.service.getPath()
+		self.name = info.getName(self.service)
+		descr = info.getInfoString(self.service, iServiceInformation.sDescription)
+		self.session.openWithCallback(self.advcutConfirmed, AdvancedCutInput, self.name, path, descr)
+
+	def advcutConfirmed(self, ret):
+		if len(ret) <= 1 or not ret[0]:
+			self.close()
+			return
+		clist = [mcut_path]
+		if ret[1] == True:
+			clist.append("-r")
+		clist.append(self.service.getPath())
+		if ret[2] != False:
+			clist += ["-o", ret[2]]
+		if ret[3] != False:
+			clist += ["-n", ret[3]]
+		if ret[4] != False:
+			clist += ["-d", ret[4]]
+		if ret[5] != False:
+			clist.append("-c")
+			clist += ret[5]
+		MovieCutSpawn(self.session, self, clist, self.name)
+		
+class AdvancedCutInput(Screen, ConfigListScreen):
+	def __init__(self, session, name, path, descr):
+		Screen.__init__(self, session)
+		self.skinName = [ "AdvancedCutInput", "Setup" ]
+
+		self["key_green"] = StaticText(_("OK"))
+		self["key_red"] = StaticText(_("Cancel"))
+
+		if self.baseName(path) == self.baseName(name):
+			title = ""
+		else:
+			title = name
+		dir = self.dirName(path)
+		file = self.baseName(path) + " cut"
+		self.input_replace = ConfigSelection(choices = [("no", _("No")), ("yes", _("Yes"))], default = "no")
+		self.input_file = ConfigText(default = file, fixed_size = False, visible_width = 45)
+		self.input_title = ConfigText(default = title, fixed_size = False, visible_width = 45)
+		self.input_descr = ConfigText(default = descr, fixed_size = False, visible_width = 45)
+		tmp = config.movielist.videodirs.value
+		if not dir in tmp:
+			tmp.append(dir)
+		self.input_dir = ConfigSelection(choices = tmp, default = dir)
+		self.input_manual = ConfigSelection(choices = [("no", _("Cutlist")), ("yes", _("Manual specification"))], default = "no")
+		self.input_space = ConfigNothing()
+		self.input_manualcuts = ConfigText(default = "", fixed_size = False)
+		self.input_manualcuts.setUseableChars(" 0123456789:.")
+
+		self["actions"] = ActionMap(["SetupActions"],
+		{
+			"ok": self.keySelectOrGo,
+			"save": self.keyGo,
+			"cancel": self.keyCancel,
+		}, -2)
+
+		self.list = []
+		ConfigListScreen.__init__(self, self.list)
+		self.entry_replace = getConfigListEntry(_("Replace original:"), self.input_replace)
+		self.entry_file = getConfigListEntry(_("New filename:"), self.input_file)
+		self.entry_title = getConfigListEntry(_("New title:"), self.input_title)
+		self.entry_descr = getConfigListEntry(_("New description:"), self.input_descr)
+		self.entry_dir = getConfigListEntry(_("New location:"), self.input_dir)
+		self.entry_manual = getConfigListEntry(_("Cut source:"), self.input_manual)
+		self.entry_space = getConfigListEntry(_("Cuts (an IN OUT IN OUT ... sequence of hour:min:sec)"), self.input_space)
+		self.entry_manualcuts = getConfigListEntry(":", self.input_manualcuts)
+		self.createSetup(self["config"])
+
+		self.onLayoutFinish.append(self.layoutFinished)
+
+	def layoutFinished(self):
+		self.setTitle(_("Cut Parameter Input"))
+
+	def createSetup(self, configlist):
+		list = [
+			self.entry_replace
+		]
+		if self.input_replace.value == "no":
+			list.extend((
+				self.entry_file,
+				self.entry_dir,
+			))
+		list.extend((
+			self.entry_title,
+			self.entry_descr,
+			self.entry_manual,
+		))
+		if self.input_manual.value == "yes":
+			list.extend((
+				self.entry_space,
+				self.entry_manualcuts,
+			))
+		self.list = list
+		configlist.list = list
+		configlist.l.setList(list)
+
+	def keyLeft(self):
+		ConfigListScreen.keyLeft(self)
+		cc = self["config"].getCurrent()
+		if cc is self.entry_replace or cc is self.entry_manual:
+			self.createSetup(self["config"])
+
+	def keyRight(self):
+		ConfigListScreen.keyRight(self)
+		cc = self["config"].getCurrent()
+		if cc is self.entry_replace or cc is self.entry_manual:
+			self.createSetup(self["config"])
+
+	def pathSelected(self, res):
+		if res is not None:
+			if config.movielist.videodirs.value != self.input_dir.choices:
+				self.input_dir.setChoices(config.movielist.videodirs.value, default=res)
+			self.input_dir.value = res
+
+	def keySelectOrGo(self):
+		if self["config"].getCurrent() == self.entry_dir:
+			self.session.openWithCallback(
+				self.pathSelected,
+				MovieLocationBox,
+				_("Choose target folder"),
+				self.input_dir.value,
+			)
+		else:
+			self.keyGo()
+
+	def keyGo(self):
+		if self.input_replace.value == "yes":
+			path = False
+		else:
+			path = self.rejoinName(self.input_dir.value, self.input_file.value)
+		if self.input_manual.value == "no":
+			cuts = False
+		else:
+			cuts = self.input_manualcuts.value.split(' ')
+			while "" in cuts:
+				cuts.remove("")
+		self.close((True, self.input_replace.value, path, self.input_title.value, self.input_descr.value, cuts))
+
+	def keyCancel(self):
+		self.close((False,))
+
+	def baseName(self, str):
+		name = str.split('/')[-1]
+		if name.endswith(".ts") is True:
+			return name[:-3]
+		else:
+			return name
+
+	def dirName(self, str):
+		return '/'.join(str.split('/')[:-1]) + '/'
+
+	def rejoinName(self, dir, name):
+		name = name.strip()
+		if name.endswith(".ts") is True:
+			return dir + name[:-3]
+		else:
+			return dir + name
+
+class MovieCutQueue:
+	def __init__(self):
+		self.container = eConsoleAppContainer()
+		self.container.appClosed.append(self.runDone)
+		self.queue = []
+		self.running = False
+
+	def enqueue(self, cb, cmd):
+		self.queue.append((cb, cmd))
+		if not self.running:
+			self.running = True
+			self.runNext()
+			return True
+		else:
+			return False
+
+	def runNext(self):
+		if not self.queue:
+			self.running = False
+		else:
+			self.container.execute(*self.queue[0][1])
+
+	def runDone(self, retval):
+		cb = self.queue[0][0]
+		self.queue = self.queue[1:]
+		cb(retval)
+		self.runNext()
+
+global_mcut_errors = [_("The movie \"%s\" is successfully cut"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Bad arguments"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .ts file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .cuts file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open input .ap file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .ts file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .cuts file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Couldn't open output .ap file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Empty .ap file"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("No cuts specified"),
+		      _("Cutting failed for movie \"%s\"")+":\n"+_("Read/write error (disk full?)"),
+		      _("Cutting was aborted for movie \"%s\"")]
+
+global_mcut_queue = MovieCutQueue()
+
+global_mcut_block = False
+
+class MovieCutSpawn:
+	def __init__(self, session, parent, clist, name):
+		global global_mcut_queue
+		global global_mcut_block
+		self.session = session
+		self.parent = parent
+		self.name = name
+		self.clist = [clist[0]] + clist
+		self.mess = ""
+		self.dialog = False
+		self.waitTimer = eTimer()
+		self.waitTimer.callback.append(self.doWaitAck)
+		if global_mcut_queue.enqueue(self.doAck, self.clist):
+			mess = _("The movie \"%s\" is cut in the background.") % (self.name)
+		else:
+			mess = _("Another movie is currently cut.\nThe movie \"%s\" will be cut in the background after it.") % (self.name)
+		global_mcut_block = True
+		self.dialog = self.session.openWithCallback(self.endc, MessageBox, mess, MessageBox.TYPE_INFO)
+
+	def doAck(self, retval):
+		global global_mcut_errors
+#		if WIFEXITED(retval):
+#			self.mess = global_mcut_errors[WEXITSTATUS(retval)] % (self.name)
+#		else:
+#			self.mess = global_mcut_errors[-1] % (self.name)
+		self.mess = global_mcut_errors[retval] % (self.name)
+		self.doWaitAck()
+
+	def doWaitAck(self):
+		global global_mcut_block
+		if Screens.Standby.inStandby or not self.session.in_exec or (global_mcut_block and not self.dialog):
+			self.waitTimer.start(2000, True)
+		else:
+			global_mcut_block = True
+			self.session.openWithCallback(self.endw, MessageBox, self.mess, MessageBox.TYPE_INFO)
+
+	def endw(self, arg = 0):
+		global global_mcut_block
+		global_mcut_block = False
+		if self.session.current_dialog == self.dialog:
+			self.session.current_dialog.close(True)
+			self.endc(arg)
+
+	def endc(self, arg = 0):
+		global global_mcut_block
+		global_mcut_block = False
+		self.dialog = False
+		self.parent.close()
+#		self.session.current_dialog.close()
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/ReconstructApSc/maintainer.info
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/ReconstructApSc/maintainer.info	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/ReconstructApSc/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+aho@sics.se
+ReconstructApSc
Index: /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/ReconstructApSc/plugin.py
===================================================================
--- /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/ReconstructApSc/plugin.py	(revision 5870)
+++ /ipk/source/swapeditors_moviecutlistcollection_1_0/var/swap/extensions/ReconstructApSc/plugin.py	(revision 5870)
@@ -0,0 +1,154 @@
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+import Screens.Standby
+from Components.ActionMap import ActionMap
+from enigma import eTimer, eServiceCenter, iServiceInformation, eConsoleAppContainer
+from os import access, chmod, X_OK
+
+recons_path = "/usr/lib/enigma2/python/Plugins/Extensions/ReconstructApSc/bin/reconstruct_apsc"
+
+def main(session, service, **kwargs):
+	# Hack to make sure it is executable
+	if not access(recons_path, X_OK):
+		chmod(recons_path, 493)
+	session.open(ReconstructApSc, service, **kwargs)
+
+def Plugins(**kwargs):
+	return PluginDescriptor(name="ReconstructApSc", description=_("Reconstruct AP/SC ..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
+
+
+class ReconstructApSc(ChoiceBox):
+	def __init__(self, session, service):
+		self.service = service
+		serviceHandler = eServiceCenter.getInstance()
+		path = self.service.getPath()
+		info = serviceHandler.info(self.service)
+		if not info:
+			self.name = path
+		else:
+			self.name = info.getName(self.service)
+		tlist = [
+			(_("Don't reconstruct"), "CALLFUNC", self.confirmed0),
+			(_("Reconstruct the .ap and .sc files of the selected movie"), "CALLFUNC", self.confirmed1),
+			(_("Reconstruct all missing .ap and .sc files in this directory"), "CALLFUNC", self.confirmed2),
+			(_("Check any running reconstruct process"), "CALLFUNC", self.confirmed3),
+		]
+		ChoiceBox.__init__(self, session, _("What would you like to reconstruct?  (\"%s\")") % (self.name), list = tlist, selection = 0)
+		self.skinName = "ChoiceBox"
+
+	def confirmed0(self, arg):
+		self.close()
+
+	def confirmed1(self, arg):
+		ReconstructApScSpawn(self.session, self, [recons_path, self.service.getPath()], self.name, _("movie"))
+
+	def confirmed2(self, arg):
+		dir = self.dirName(self.service.getPath())
+		ReconstructApScSpawn(self.session, self, [recons_path, "-d", dir], dir, _("directory"))
+
+	def confirmed3(self, arg):
+		output = global_recons_queue.checkOutput()
+		if output == False:
+			mess = "There is no running reconstruction process"
+		else:
+			mess = "Current reconstruction process output:\n%s" % output
+		self.session.openWithCallback(self.close, MessageBox, mess, MessageBox.TYPE_INFO)
+
+	def dirName(self, str):
+		return '/'.join(str.split('/')[:-1]) + '/'
+
+
+class ReconstructApScQueue:
+	def __init__(self):
+		self.container = eConsoleAppContainer()
+		self.container.appClosed.append(self.runDone)
+		self.container.dataAvail.append(self.collOutput)
+		self.queue = []
+		self.output = ""
+		self.running = False
+
+	def enqueue(self, cb, cmd):
+		self.queue.append((cb, cmd))
+		if not self.running:
+			self.runNext()
+			return True
+		else:
+			return False
+
+	def collOutput(self, data):
+		self.output += data
+
+	def checkOutput(self):
+		if not self.running:
+			return False
+		else:
+			return self.output
+
+	def runNext(self):
+		self.output = ""
+		if not self.queue:
+			self.running = False
+		else:
+			self.running = True
+			self.container.execute(*self.queue[0][1])
+
+	def runDone(self, retval):
+		cb = self.queue[0][0]
+		self.queue = self.queue[1:]
+		cb(retval, self.output)
+		self.runNext()
+
+global_recons_errors = [_("The %s \"%s\" is successfully processed:\n%s"),
+		      _("Processing failed for the %s \"%s\":\n%s")]
+
+global_recons_queue = ReconstructApScQueue()
+
+global_recons_block = False
+
+class ReconstructApScSpawn:
+	def __init__(self, session, parent, clist, name, typename):
+		global global_recons_queue
+		global global_recons_block
+		self.session = session
+		self.parent = parent
+		self.name = name
+		self.typename = typename
+		self.clist = [clist[0]] + clist
+		self.mess = ""
+		self.dialog = False
+		self.waitTimer = eTimer()
+		self.waitTimer.callback.append(self.doWaitAck)
+		if global_recons_queue.enqueue(self.doAck, self.clist):
+			mess = _("The %s \"%s\" is processed in the background.") % (self.typename, self.name)
+		else:
+			mess = _("Another movie or directory is currently processed.\nThe %s \"%s\" will be processed in the background after it.") % (self.typename, self.name)
+		global_recons_block = True
+		self.dialog = self.session.openWithCallback(self.endc, MessageBox, mess, MessageBox.TYPE_INFO)
+
+	def doAck(self, retval, output):
+		global global_recons_errors
+		self.mess = global_recons_errors[retval] % (self.typename, self.name, output)
+		self.doWaitAck()
+
+	def doWaitAck(self):
+		global global_recons_block
+		if Screens.Standby.inStandby or not self.session.in_exec or (global_recons_block and not self.dialog):
+			self.waitTimer.start(2000, True)
+		else:
+			global_recons_block = True
+			self.session.openWithCallback(self.endw, MessageBox, self.mess, MessageBox.TYPE_INFO)
+
+	def endw(self, arg = 0):
+		global global_recons_block
+		global_recons_block = False
+		if self.session.current_dialog == self.dialog:
+			self.session.current_dialog.close(True)
+			self.endc(arg)
+
+	def endc(self, arg = 0):
+		global global_recons_block
+		global_recons_block = False
+		self.dialog = False
+		self.parent.close()
Index: /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/__init__.py
===================================================================
--- /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/__init__.py	(revision 5870)
+++ /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/__init__.py	(revision 5870)
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
+from os import environ as os_environ
+import gettext
+
+def localeInit():
+	lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
+	os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
+	gettext.bindtextdomain("MovieRetitle", resolveFilename(SCOPE_PLUGINS, "Extensions/MovieRetitle/locale"))
+
+def _(txt):
+	t = gettext.dgettext("MovieRetitle", txt)
+	if t == txt:
+		print "[MovieRetitle] fallback to default translation for", txt
+		t = gettext.gettext(txt)
+	return t
+
+localeInit()
+language.addCallback(localeInit)
+
Index: /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/maintainer.info
===================================================================
--- /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/maintainer.info	(revision 5870)
+++ /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+aho@sics.se
+MovieRetitle
Index: /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/plugin.py
===================================================================
--- /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/plugin.py	(revision 5870)
+++ /ipk/source/swapeditors_movieretitle_1_0/var/swap/extensions/MovieRetitle/plugin.py	(revision 5870)
@@ -0,0 +1,296 @@
+# for localized messages
+from . import _
+
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.LocationBox import MovieLocationBox
+import Screens.Standby
+from Components.config import config, ConfigText, ConfigSelection, getConfigListEntry
+from Components.ActionMap import ActionMap
+from Components.ConfigList import ConfigListScreen
+from Components.Sources.StaticText import StaticText
+from enigma import eTimer, eServiceCenter, iServiceInformation, eConsoleAppContainer
+from os import path as os_path, rename as os_rename, unlink as os_unlink
+
+def main(session, service, **kwargs):
+	session.open(MovieRetitle, service, session.current_dialog, **kwargs)
+
+def Plugins(**kwargs):
+	return PluginDescriptor(name="MovieRetitle", description=_("change name..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc=main)
+
+
+class MovieRetitle(Screen, ConfigListScreen):
+	def __init__(self, session, service, parent, args = 0):
+		Screen.__init__(self, session, parent = parent)
+		self.skinName = [ "MovieRetitle", "Setup" ]
+
+		serviceHandler = eServiceCenter.getInstance()
+		info = serviceHandler.info(service)
+		path = service.getPath()
+		if path.endswith(".ts") is True:
+			path = path[:-3]
+		self.path = path
+		self.dir = '/'.join(path.split('/')[:-1]) + '/'
+		self.file = self.baseName(path)
+		self.name = info.getName(service)
+		if self.file == self.baseName(self.name):
+			self.orig_title = ""
+		else:
+			self.orig_title = self.name
+		self.descr = info.getInfoString(service, iServiceInformation.sDescription)
+
+		self["key_green"] = StaticText(_("OK"))
+		self["key_red"] = StaticText(_("Cancel"))
+
+		self.input_file = ConfigText(default = self.file, fixed_size = False, visible_width = 42)
+		self.input_title = ConfigText(default = self.orig_title, fixed_size = False, visible_width = 42)
+		self.input_descr = ConfigText(default = self.descr, fixed_size = False, visible_width = 42)
+		tmp = config.movielist.videodirs.value
+		if not self.dir in tmp:
+			tmp.append(self.dir)
+		self.input_dir = ConfigSelection(choices = tmp, default = self.dir)
+
+		self["actions"] = ActionMap(["SetupActions"],
+		{
+			"ok": self.keySelectOrGo,
+			"save": self.keyGo,
+			"cancel": self.keyCancel,
+		}, -2)
+
+		self.locationEl = getConfigListEntry(_("Location"), self.input_dir)
+		l = [
+			getConfigListEntry(_("Filename"), self.input_file),
+			getConfigListEntry(_("Title"), self.input_title),
+			getConfigListEntry(_("Description"), self.input_descr),
+			self.locationEl
+		]
+
+		ConfigListScreen.__init__(self, l)
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+		
+	def setCustomTitle(self):
+		self.setTitle(_("Name and Description Input"))
+
+	def pathSelected(self, res):
+		if res is not None:
+			videodirs = config.movielist.videodirs.value
+			if videodirs != self.input_dir.choices:
+				self.input_dir.setChoices(videodirs, default=res)
+			self.input_dir.value = res
+
+	def keySelectOrGo(self):
+		cur = self["config"].getCurrent()
+		if cur is self.locationEl:
+			self.session.openWithCallback(
+				self.pathSelected,
+				MovieLocationBox,
+				_("Choose target folder"),
+				self.input_dir.value,
+			)
+		else:
+			self.keyGo()
+
+	def keyGo(self):
+		if self.input_title.value != self.orig_title or self.input_descr.value != self.descr:
+			self.setTitleDescr(self.path, self.input_title.value, self.input_descr.value)
+		if self.input_file.value != self.file or self.input_dir.value != self.dir:
+			self.maybeMoveMovieFiles(self.path, self.rejoinName(self.input_dir.value, self.input_file.value))
+		else:
+			self.exitDialog()
+
+	def keyCancel(self):
+		self.close()
+
+	def setTitleDescr(self, file, title, descr):
+		if os_path.exists(file + ".ts.meta"):
+			metafile = open(file + ".ts.meta", "r")
+			sid = metafile.readline()
+			oldtitle = metafile.readline().rstrip()
+			olddescr = metafile.readline().rstrip()
+			rest = metafile.read()
+			metafile.close()
+			if not title and title != "":
+				title = oldtitle
+			if not descr and descr != "":
+				descr = olddescr
+			metafile = open(file + ".ts.meta", "w")
+			metafile.write("%s%s\n%s\n%s" %(sid, title, descr, rest))
+			metafile.close()
+
+	def maybeMoveMovieFiles(self, fr, to):
+		if os_path.exists(to+".ts"):
+			self.inter_fr = fr
+			self.inter_to = to
+			self.session.openWithCallback(self.confirmedReplace, MessageBox, _("Target file %s.ts already exist.\nDo you want to replace it?") % (to), MessageBox.TYPE_YESNO)
+		elif os_path.isdir(os_path.dirname(to)):
+			self.moveMovieFiles(fr, to)
+		else:
+			self.session.openWithCallback(self.exitDialog, MessageBox, _("The target directory is not found. The file is not renamed."), MessageBox.TYPE_ERROR)
+
+	def confirmedReplace(self, answer):
+		if answer == True:
+			self.moveMovieFiles(self.inter_fr, self.inter_to)
+
+	def moveMovieFiles(self, fr, to):
+		try:
+			os_rename(fr + ".ts", to + ".ts")
+		except OSError:
+			print "Moving in background"
+			global_background_mover.enqueue(self.exitDialog, self.session, fr, to)
+		else:
+			print "Moving in foreground"
+			for suff in (".ts.meta", ".ts.cuts", ".ts.ap", ".ts.sc", ".eit"):
+				if os_path.exists(fr + suff):
+					os_rename(fr + suff, to + suff)
+			self.exitDialog()
+
+	def exitDialog(self, dummy=None):
+		self.close()
+		# This will try to get back to an updated movie list.
+		# A proper way to do this should be provided in enigma2.
+		try:
+			parent = self.parent
+			parent.csel.reloadList()
+			parent.close()
+		except AttributeError:
+			try:
+				# when started from MovieSelection Quickbutton Plugin, MovieSelection is parent, not MovieContextMenu --> try again
+				self.parent.reloadList()
+			except: pass
+
+	def baseName(self, str):
+		name = str.split('/')[-1]
+		if name.endswith(".ts") is True:
+			return name[:-3]
+		else:
+			return name
+
+	def rejoinName(self, dir, name):
+		name = name.strip()
+		if name.endswith(".ts") is True:
+			return dir + name[:-3]
+		else:
+			return dir + name
+
+class MovieRetitleBackgroundMover:
+	def __init__(self):
+		self.container = eConsoleAppContainer()
+		self.container.appClosed.append(self.moveNextSuffBG)
+		self.currid = 0;
+		self.queue = []
+		self.running = False
+		self.messageQueue = []
+		self.messageTimer = eTimer()
+		self.messageTimer.callback.append(self.tryLaunchMessage)
+
+	def message(self, session, id, cb, txt):
+		global global_message_block
+		done = False
+		if global_message_block and global_message_block == id:
+			self.messageQueue = [(session, id, txt)] + self.messageQueue
+		else:
+			i = 0
+			for ele in self.messageQueue:
+				if ele[1] == id:
+					self.messageQueue[i] = (session, id, txt)
+					done = True
+					break
+				i += 1
+			if not done:
+				self.messageQueue.append((session, id, txt))
+		self.tryLaunchMessage(callback = cb)
+
+	def tryLaunchMessage(self, dummy=0, callback = None):
+		global global_message_block
+		self.messageTimer.stop()
+		if not self.messageQueue:
+			if callback:
+				callback()
+		elif not Screens.Standby.inStandby and self.messageQueue[0][0].in_exec and (not global_message_block or global_message_block == self.messageQueue[0][1]):
+			self.messageTimer.stop()
+			session = self.messageQueue[0][0]
+			id = self.messageQueue[0][1]
+			mess = self.messageQueue[0][2]
+			self.messageQueue = self.messageQueue[1:]
+			if global_message_block == id:
+				closeprev = session.current_dialog
+			else:
+				closeprev = None
+			global_message_block = id
+			try:
+				session.openWithCallback(lambda x: self.tryLaunchMessageCallback(callback, closeprev), MessageBox, mess, MessageBox.TYPE_INFO)
+			except:
+				global_message_block = False
+				self.tryLaunchMessage()
+		else:
+			self.messageTimer.start(1500, True)
+			if callback:
+				callback()
+
+	def tryLaunchMessageCallback(self, callback, closeprev):
+		global global_message_block
+		global_message_block = False
+		if closeprev:
+			closeprev.close(True)
+		self.tryLaunchMessage(callback = callback)
+
+	def enqueue(self, cb, session, fr, to):
+		self.currid += 1
+		mess = _("The movie is moved in the background from %s to %s.") % (os_path.dirname(fr), os_path.dirname(to))
+		self.message(session, self.currid, cb, mess)
+		self.queue.append((session, self.currid, fr, to))
+		if not self.running:
+			self.running = True
+			self.runNext()
+			return True
+		else:
+			return False
+
+	def runNext(self):
+		if not self.queue:
+			self.running = False
+		else:
+			self.moveMovieFilesBackground(self.queue[0])
+
+	def runDone(self, retval):
+		ele = self.queue[0]
+		self.queue = self.queue[1:]
+		self.runNext()
+
+	def moveMovieFilesBackground(self, ele):
+		self.ele = ele
+		self.sufflst = (".ts.meta", ".ts.cuts", ".ts.ap", ".ts.sc", ".eit", ".ts")
+		self.sufflst2 = self.sufflst
+		self.moveNextSuffBG(0)
+
+	def moveNextSuffBG(self, retval):
+		if self.sufflst and not retval:
+			fr = self.ele[2] + self.sufflst[0]
+			to = self.ele[3] + self.sufflst[0]
+			self.sufflst = self.sufflst[1:]
+			print "Moving %s to %s" % (fr, to)
+			if os_path.exists(fr):
+				self.container.execute("/bin/cp", "/bin/cp", fr, to)
+			else:
+				self.moveNextSuffBG(0)
+		elif retval:
+			for suff in self.sufflst2:
+				if os_path.exists(self.ele[3] + suff) and os_path.exists(self.ele[2] + suff):
+					os_unlink(self.ele[3] + suff)
+			mess = _("Failed to move the movie %s to %s in the background") % (self.ele[2], self.ele[3])
+			self.message(self.ele[0], self.ele[1], None, mess)
+			self.runDone(1)
+		else:
+			for suff in self.sufflst2:
+				if os_path.exists(self.ele[2] + suff) and os_path.exists(self.ele[3] + suff):
+					os_unlink(self.ele[2] + suff)
+			mess = _("Successfully moved the movie %s") % (self.ele[2])
+			self.message(self.ele[0], self.ele[1], None, mess)
+			self.runDone(0)
+
+global_background_mover = MovieRetitleBackgroundMover()
+
+global_message_block = False
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoPoller.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoPoller.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoPoller.py	(revision 5870)
@@ -0,0 +1,41 @@
+# Timer
+from enigma import eTimer
+
+# Config
+from Components.config import config
+
+class AutoPoller:
+	"""Automatically Poll AutoTimer"""
+
+	def __init__(self):
+		# Init Timer
+		self.timer = eTimer()
+
+	def start(self, initial = True):
+		if initial:
+			delay = 2
+		else:
+			delay = config.plugins.autotimer.interval.value*3600
+
+		if self.query not in self.timer.callback:
+			self.timer.callback.append(self.query)
+		self.timer.startLongTimer(delay)
+
+	def stop(self):
+		if self.query in self.timer.callback:
+			self.timer.callback.remove(self.query)
+		self.timer.stop()
+
+	def query(self):
+		from plugin import autotimer
+
+		# Ignore any program errors
+		try:
+			autotimer.parseEPG()
+		except Exception:
+			# Dump error to stdout
+			import traceback, sys
+			traceback.print_exc(file=sys.stdout)
+
+		self.timer.startLongTimer(config.plugins.autotimer.interval.value*3600)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimer.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimer.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimer.py	(revision 5870)
@@ -0,0 +1,334 @@
+# Plugins Config
+from xml.etree.cElementTree import parse as cet_parse
+from os import path as os_path
+from AutoTimerConfiguration import parseConfig, writeConfig
+
+# Navigation (RecordTimer)
+import NavigationInstance
+
+# Timer
+from ServiceReference import ServiceReference
+from RecordTimer import RecordTimerEntry
+from Components.TimerSanityCheck import TimerSanityCheck
+
+# Timespan
+from time import localtime, time
+
+# EPGCache & Event
+from enigma import eEPGCache, eServiceReference
+
+# Enigma2 Config
+from Components.config import config
+
+# AutoTimer Component
+from AutoTimerComponent import AutoTimerComponent
+
+XML_CONFIG = "/etc/enigma2/autotimer.xml"
+
+def getTimeDiff(timer, begin, end):
+	if begin <= timer.begin <= end:
+		return end - timer.begin
+	elif timer.begin <= begin <= timer.end:
+		return timer.end - begin
+	return 0
+
+typeMap = {
+	"exact": eEPGCache.EXAKT_TITLE_SEARCH,
+	"partial": eEPGCache.PARTIAL_TITLE_SEARCH
+}
+
+caseMap = {
+	"sensitive": eEPGCache.CASE_CHECK,
+	"insensitive": eEPGCache.NO_CASE_CHECK
+}
+
+class AutoTimerIgnoreTimerException(Exception):
+	def __init__(self, cause):
+		self.cause = cause
+
+	def __str__(self):
+		return "[AutoTimer] " + str(self.cause)
+
+	def __repr__(self):
+		return str(type(self))
+
+class AutoTimer:
+	"""Read and save xml configuration, query EPGCache"""
+
+	def __init__(self):
+		# Initialize
+		self.timers = []
+		self.configMtime = -1
+		self.uniqueTimerId = 0
+		self.defaultTimer = AutoTimerComponent(
+			0,		# Id
+			"",		# Name
+			"",		# Match
+			True 	# Enabled
+		)
+
+# Configuration
+
+	def readXml(self):
+		# Abort if no config found
+		if not os_path.exists(XML_CONFIG):
+			print "[AutoTimer] No configuration file present"
+			return
+
+		# Parse if mtime differs from whats saved
+		mtime = os_path.getmtime(XML_CONFIG)
+		if mtime == self.configMtime:
+			print "[AutoTimer] No changes in configuration, won't parse"
+			return
+
+		# Save current mtime
+		self.configMtime = mtime
+
+		# Parse Config
+		configuration = cet_parse(XML_CONFIG).getroot()
+
+		# Empty out timers and reset Ids
+		del self.timers[:]
+		self.defaultTimer.clear(-1, True)
+
+		parseConfig(
+			configuration,
+			self.timers,
+			configuration.get("version"),
+			0,
+			self.defaultTimer
+		)
+		self.uniqueTimerId = len(self.timers)
+
+	def writeXml(self):
+		writeConfig(XML_CONFIG, self.defaultTimer, self.timers)
+
+# Manage List
+
+	def add(self, timer):
+		self.timers.append(timer)
+
+	def getEnabledTimerList(self):
+		return [x for x in self.timers if x.enabled]
+
+	def getTimerList(self):
+		return self.timers
+
+	def getTupleTimerList(self):
+		list = self.timers
+		return [(x,) for x in list]
+
+	def getSortedTupleTimerList(self):
+		list = self.timers[:]
+		list.sort()
+		return [(x,) for x in list]
+
+	def getUniqueId(self):
+		self.uniqueTimerId += 1
+		return self.uniqueTimerId
+
+	def remove(self, uniqueId):
+		idx = 0
+		for timer in self.timers:
+			if timer.id == uniqueId:
+				self.timers.pop(idx)
+				return
+			idx += 1
+
+	def set(self, timer):
+		idx = 0
+		for stimer in self.timers:
+			if stimer == timer:
+				self.timers[idx] = timer
+				return
+			idx += 1
+		self.timers.append(timer)
+
+# Main function
+
+	def parseEPG(self, simulateOnly = False):
+		if NavigationInstance.instance is None:
+			print "[AutoTimer] Navigation is not available, can't parse EPG"
+			return (0, 0, 0, [])
+
+		total = 0
+		new = 0
+		modified = 0
+		timers = []
+
+		self.readXml()
+
+		# Save Recordings in a dict to speed things up a little
+		# We include processed timers as we might search for duplicate descriptions
+		recorddict = {}
+		for timer in NavigationInstance.instance.RecordTimer.timer_list + NavigationInstance.instance.RecordTimer.processed_timers:
+			recorddict.setdefault(str(timer.service_ref), []).append(timer)
+
+		# Iterate Timer
+		for timer in self.getEnabledTimerList():
+			# Workaround to allow search for umlauts if we know the encoding
+			match = timer.match
+			if timer.encoding != 'UTF-8':
+				try:
+					match = match.decode('UTF-8').encode(timer.encoding)
+				except UnicodeDecodeError:
+					pass
+
+			# Search EPG, default to empty list
+			epgcache = eEPGCache.getInstance()
+			ret = epgcache.search(('RI', 100, typeMap[timer.searchType], match, caseMap[timer.searchCase])) or ()
+
+			for serviceref, eit in ret:
+				eserviceref = eServiceReference(serviceref)
+
+				evt = epgcache.lookupEventId(eserviceref, eit)
+				if not evt:
+					print "[AutoTimer] Could not create Event!"
+					continue
+
+				# Try to determine real service (we always choose the last one)
+				n = evt.getNumOfLinkageServices()
+				if n > 0:
+					i = evt.getLinkageService(eserviceref, n-1)
+					serviceref = i.toString()
+
+				# Gather Information
+				name = evt.getEventName()
+				description = evt.getShortDescription()
+				begin = evt.getBeginTime()
+				duration = evt.getDuration()
+				end = begin + duration
+
+				# If event starts in less than 60 seconds skip it
+				if begin < time() + 60:
+					continue
+
+				# Convert begin time
+				timestamp = localtime(begin)
+
+				# Update timer
+				timer.update(begin, timestamp)
+
+				# Check Duration, Timespan and Excludes
+				if timer.checkServices(serviceref) \
+					or timer.checkDuration(duration) \
+					or timer.checkTimespan(timestamp) \
+					or timer.checkFilter(name, description,
+						evt.getExtendedDescription(), str(timestamp.tm_wday)):
+					continue
+
+				if timer.hasOffset():
+					# Apply custom Offset
+					begin, end = timer.applyOffset(begin, end)
+				else:
+					# Apply E2 Offset
+					begin -= config.recording.margin_before.value * 60
+					end += config.recording.margin_after.value * 60
+
+				# Eventually change service to alternative
+				if timer.overrideAlternatives:
+					serviceref = timer.getAlternative(serviceref)
+
+				total += 1
+
+				# Append to timerlist and abort if simulating
+				timers.append((name, begin, end, serviceref, timer.name))
+				if simulateOnly:
+					continue
+
+				# Initialize
+				newEntry = None
+				oldExists = False
+
+				# Check for double Timers
+				# We first check eit and if user wants us to guess event based on time
+				# we try this as backup. The allowed diff should be configurable though.
+				for rtimer in recorddict.get(serviceref, ()):
+					if rtimer.eit == eit or config.plugins.autotimer.try_guessing.value and getTimeDiff(rtimer, begin, end) > ((duration/10)*8):
+						oldExists = True
+
+						# Abort if we don't want to modify timers or timer is repeated
+						if config.plugins.autotimer.refresh.value == "none" or rtimer.repeated:
+							print "[AutoTimer] Won't modify existing timer because either no modification allowed or repeated timer"
+							break
+
+						if hasattr(rtimer, "isAutoTimer"):
+								print "[AutoTimer] Modifying existing AutoTimer!"
+						else:
+							if config.plugins.autotimer.refresh.value != "all":
+								print "[AutoTimer] Won't modify existing timer because it's no timer set by us"
+								break
+
+							print "[AutoTimer] Warning, we're messing with a timer which might not have been set by us"
+
+						newEntry = rtimer
+						modified += 1
+
+						# Modify values saved in timer
+						newEntry.name = name
+						newEntry.description = description
+						newEntry.begin = int(begin)
+						newEntry.end = int(end)
+						newEntry.service_ref = ServiceReference(serviceref)
+
+						break
+					elif timer.avoidDuplicateDescription == 1 and rtimer.description == description:
+						oldExists = True
+						print "[AutoTimer] We found a timer with same description, skipping event"
+						break
+
+				# We found no timer we want to edit
+				if newEntry is None:
+					# But there is a match
+					if oldExists:
+						continue
+
+					# We want to search for possible doubles
+					if timer.avoidDuplicateDescription == 2:
+						# I thinks thats the fastest way to do this, though it's a little ugly
+						try:
+							for list in recorddict.values():
+								for rtimer in list:
+									if rtimer.description == description:
+										raise AutoTimerIgnoreTimerException("We found a timer with same description, skipping event")
+						except AutoTimerIgnoreTimerException, etite:
+							print etite
+							continue
+
+					if timer.checkCounter(timestamp):
+						continue
+
+					print "[AutoTimer] Adding an event."
+					newEntry = RecordTimerEntry(ServiceReference(serviceref), begin, end, name, description, eit)
+
+					# Mark this entry as AutoTimer (only AutoTimers will have this Attribute set)
+					newEntry.isAutoTimer = True
+
+				# Apply afterEvent
+ 				if timer.hasAfterEvent():
+ 					afterEvent = timer.getAfterEventTimespan(localtime(end))
+ 					if afterEvent is None:
+ 						afterEvent = timer.getAfterEvent()
+ 					if afterEvent is not None:
+ 						newEntry.afterEvent = afterEvent
+
+				newEntry.dirname = timer.destination
+				newEntry.justplay = timer.justplay
+				newEntry.tags = timer.tags
+
+				if oldExists:
+					# XXX: this won't perform a sanity check, but do we actually want to do so?
+					NavigationInstance.instance.RecordTimer.timeChanged(newEntry)
+				else:
+					conflicts = NavigationInstance.instance.RecordTimer.record(newEntry)
+					if conflicts and config.plugins.autotimer.disabled_on_conflict.value:
+						newEntry.disabled = True
+						# We might want to do the sanity check locally so we don't run it twice - but I consider this workaround a hack anyway
+						conflicts = NavigationInstance.instance.RecordTimer.record(newEntry)
+					if conflicts is None:
+						timer.decrementCounter()
+						new += 1
+						recorddict.setdefault(serviceref, []).append(newEntry)
+
+		return (total, new, modified, timers)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerComponent.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerComponent.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerComponent.py	(revision 5870)
@@ -0,0 +1,609 @@
+# Format counter
+from time import strftime
+
+# regular expression
+from re import compile as re_compile
+
+# Alternatives and service restriction
+from enigma import eServiceReference, eServiceCenter
+
+class AutoTimerComponent(object):
+	"""AutoTimer Component which also handles validity checks"""
+
+	"""
+	 Initiate
+	"""
+	def __init__(self, id, name, match, enabled, *args, **kwargs):
+		self.id = id
+		self._afterevent = []
+		self.setValues(name, match, enabled, *args, **kwargs)
+
+	"""
+	 Unsets all Attributes
+	"""
+	def clear(self, id = -1, enabled = False):
+		self.id = id
+		self.setValues('', '', enabled)
+
+	"""
+	 Create a deep copy of this instance
+	"""
+	def clone(self):
+		return self.__deepcopy__({})
+
+	"""
+	 Hook needed for WebIf
+	"""
+	def getEntry(self):
+		return self
+
+	"""
+	 Keeps init small and helps setting many values at once
+	"""
+	def setValues(self, name, match, enabled, timespan = None, services = None, offset = None, \
+			afterevent = [], exclude = None, maxduration = None, destination = None, \
+			include = None, matchCount = 0, matchLeft = 0, matchLimit = '', matchFormatString = '', \
+			lastBegin = 0, justplay = False, avoidDuplicateDescription = 0, bouquets = None, \
+			tags = None, encoding = 'UTF-8', searchType = "partial", searchCase = "insensitive", \
+			overrideAlternatives = False):
+		self.name = name
+		self.match = match
+		self.enabled = enabled
+		self.timespan = timespan
+		self.services = services
+		self.offset = offset
+		self.afterevent = afterevent
+		self.exclude = exclude
+		self.maxduration = maxduration
+		self.destination = destination
+		self.include = include
+		self.matchCount = matchCount
+		self.matchLeft = matchLeft
+		self.matchLimit = matchLimit
+		self.matchFormatString = matchFormatString
+		self.lastBegin = lastBegin
+		self.justplay = justplay
+		self.avoidDuplicateDescription = avoidDuplicateDescription
+		self.bouquets = bouquets
+		self.tags = tags or []
+		self.encoding = encoding
+		self.searchType = searchType
+		self.searchCase = searchCase
+		self.overrideAlternatives = overrideAlternatives
+
+### Attributes / Properties
+
+	def setAfterEvent(self, afterevent):
+		if afterevent is not self._afterevent:
+			del self._afterevent[:]
+
+		Len = len(afterevent)
+		if Len:
+			for x in range(0, Len):
+				action, timespan = afterevent[x]
+
+				# Remove original entry
+				del afterevent[x]
+				# If the second argument is a tuple we assume the entry is already parsed
+				if isinstance(timespan, tuple):
+					self._afterevent.insert(x, (action, timespan))
+				elif timespan is None:
+					self._afterevent.insert(x, (action, (None,)))
+				else:
+					self._afterevent.insert(x, (action, self.calculateDayspan(*timespan)))
+
+	afterevent = property(lambda self: self._afterevent, setAfterEvent)
+
+	def setBouquets(self, bouquets):
+		if bouquets:
+			self._bouquets = bouquets
+		else:
+			self._bouquets = []
+
+	bouquets = property(lambda self: self._bouquets , setBouquets)
+
+	def setEncoding(self, encoding):
+		if encoding:
+			self._encoding = encoding
+
+	encoding = property(lambda self: self._encoding, setEncoding)
+
+	def setExclude(self, exclude):
+		if exclude:
+			self._exclude = (
+				[re_compile(x) for x in exclude[0]],
+				[re_compile(x) for x in exclude[1]],
+				[re_compile(x) for x in exclude[2]],
+				exclude[3]
+			)
+		else:
+			self._exclude = ([], [], [], [])
+
+	exclude = property(lambda self: self._exclude, setExclude)
+
+	def setInclude(self, include):
+		if include:
+			self._include = (
+				[re_compile(x) for x in include[0]],
+				[re_compile(x) for x in include[1]],
+				[re_compile(x) for x in include[2]],
+				include[3]
+			)
+		else:
+			self._include = ([], [], [], [])
+
+	include = property(lambda self: self._include, setInclude)
+
+	def setSearchCase(self, case):
+		assert case in ("sensitive", "insensitive"), "search case must be sensitive or insensitive"
+		self._searchCase = case
+
+	searchCase = property(lambda self: self._searchCase, setSearchCase)
+
+	def setSearchType(self, type):
+		assert type in ("exact", "partial"), "search type must be exact or partial"
+		self._searchType = type
+
+	searchType = property(lambda self: self._searchType, setSearchType)
+
+	def setServices(self, services):
+		if services:
+			self._services = services
+		else:
+			self._services = []
+
+	services = property(lambda self: self._services, setServices)
+
+	def setTimespan(self, timespan):
+		if timespan is None or len(timespan) and timespan[0] is None:
+			self._timespan = (None,)
+		else:
+			self._timespan = self.calculateDayspan(*timespan)
+
+	timespan = property(lambda self: self._timespan, setTimespan)
+
+### See if Attributes are set
+
+	def hasAfterEvent(self):
+		return len(self.afterevent)
+
+	def hasAfterEventTimespan(self):
+		for afterevent in self.afterevent:
+			if afterevent[1][0] is not None:
+				return True
+		return False
+
+	def hasCounter(self):
+		return self.matchCount != 0
+
+	def hasCounterFormatString(self):
+		return self.matchFormatString != ''
+
+	def hasDestination(self):
+		return self.destination is not None
+
+	def hasDuration(self):
+		return self.maxduration is not None
+
+	def hasTags(self):
+		return len(self.tags) > 0
+
+	def hasTimespan(self):
+		return self.timespan[0] is not None
+
+	def hasOffset(self):
+		return self.offset is not None
+
+### Helper
+
+	"""
+	 Returns a tulple of (input begin, input end, begin earlier than end)
+	"""
+	def calculateDayspan(self, begin, end, ignore = None):
+		if end[0] < begin[0] or (end[0] == begin[0] and end[1] <= begin[1]):
+			return (begin, end, True)
+		else:
+			return (begin, end, False)
+
+	"""
+	 Returns if a given timestruct is in a timespan
+	"""
+	def checkAnyTimespan(self, time, begin = None, end = None, haveDayspan = False):
+		if begin is None:
+			return False
+
+		# Check if we span a day
+		if haveDayspan:
+			# Check if begin of event is later than our timespan starts
+			if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
+				# If so, event is in our timespan
+				return False
+			# Check if begin of event is earlier than our timespan end
+			if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
+				# If so, event is in our timespan
+				return False
+			return True
+		else:
+			# Check if event begins earlier than our timespan starts
+			if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
+				# Its out of our timespan then
+				return True
+			# Check if event begins later than our timespan ends
+			if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
+				# Its out of our timespan then
+				return True
+			return False
+
+	"""
+	 Returns a list of all allowed services by listing the bouquets
+	"""
+	def getFullServices(self):
+		list = self.services[:]
+
+		from enigma import eServiceReference, eServiceCenter
+		serviceHandler = eServiceCenter.getInstance()
+		for bouquet in self.bouquets:
+			myref = eServiceReference(str(bouquet))
+			mylist = serviceHandler.list(myref)
+			if mylist is not None:
+				while 1:
+					s = mylist.getNext()
+					# TODO: I wonder if its sane to assume we get services here (and not just new lists)
+					# We can ignore markers & directorys here because they won't match any event's service :-)
+					if s.valid():
+						# strip all after last :
+						value = s.toString()
+						pos = value.rfind(':')
+						if pos != -1:
+							value = value[:pos+1]
+
+						list.append(value)
+					else:
+						break
+
+		return list
+
+	"""
+	 Called when a timer based on this component was added
+	"""
+	def update(self, begin, timestamp):
+		# Only update limit when we have new begin
+		if begin > self.lastBegin:
+			self.lastBegin = begin
+
+			# Update Counter:
+			# %m is Month, %U is week (sunday), %W is week (monday)
+			newLimit = strftime(self.matchFormatString, timestamp)
+
+			if newLimit != self.matchLimit:
+				self.matchLeft = self.matchCount
+				self.matchLimit = newLimit
+
+### Makes saving Config easier
+
+	getAvoidDuplicateDescription = lambda self: self.avoidDuplicateDescription
+
+	getBouquets = lambda self: self._bouquets
+
+	getCompleteAfterEvent = lambda self: self._afterevent
+
+	getCounter = lambda self: self.matchCount
+	getCounterFormatString = lambda self: self.matchFormatString
+	getCounterLeft = lambda self: self.matchLeft
+	getCounterLimit = lambda self: self.matchLimit
+
+	# XXX: as this function was not added by me (ritzMo) i'll leave it like this but i'm not really sure if this is right ;-)
+	getDestination = lambda self: self.destination is not None
+
+	getDuration = lambda self: self.maxduration/60
+
+	getEnabled = lambda self: self.enabled and "yes" or "no"
+
+	getExclude = lambda self: self._exclude
+	getExcludedDays = lambda self: self.exclude[3]
+	getExcludedDescription = lambda self: [x.pattern for x in self.exclude[2]]
+	getExcludedShort = lambda self: [x.pattern for x in self.exclude[1]]
+	getExcludedTitle = lambda self: [x.pattern for x in self.exclude[0]]
+
+	getInclude = lambda self: self._include
+	getIncludedTitle = lambda self: [x.pattern for x in self.include[0]]
+	getIncludedShort = lambda self: [x.pattern for x in self.include[1]]
+	getIncludedDescription = lambda self: [x.pattern for x in self.include[2]]
+	getIncludedDays = lambda self: self.include[3]
+
+	getJustplay = lambda self: self.justplay and "1" or "0"
+
+	getLastBegin = lambda self: self.lastBegin
+
+	getMatch = lambda self: self.match
+	getName = lambda self: self.name
+
+	getOffsetBegin = lambda self: self.offset[0]/60
+	getOffsetEnd = lambda self: self.offset[1]/60
+
+	getOverrideAlternatives = lambda self: self.overrideAlternatives and "1" or "0"
+
+	getServices = lambda self: self._services
+
+	getTags = lambda self: self.tags
+
+	getTimespan = lambda self: self._timespan
+	getTimespanBegin = lambda self: '%02d:%02d' % (self.timespan[0][0], self.timespan[0][1])
+	getTimespanEnd = lambda self: '%02d:%02d' % (self.timespan[1][0], self.timespan[1][1])
+
+	isOffsetEqual = lambda self: self.offset[0] == self.offset[1]
+
+### Actual functionality
+
+	def applyOffset(self, begin, end):
+		if self.offset is None:
+			return (begin, end)
+		return (begin - self.offset[0], end + self.offset[1])
+
+	def checkCounter(self, timestamp):
+		# 0-Count is considered "unset"
+		if self.matchCount == 0:
+			return False
+
+		# Check if event is in current timespan (we can only manage one!)
+		limit = strftime(self.matchFormatString, timestamp)
+		if limit != self.matchLimit:
+			return True
+
+		if self.matchLeft > 0:
+			return False
+		return True
+
+	def checkDuration(self, length):
+		if self.maxduration is None:
+			return False
+		return length > self.maxduration
+
+	def checkExcluded(self, title, short, extended, dayofweek):
+		if self.exclude[3]:
+			list = [x for x in self.exclude[3]]
+			if "weekend" in list:
+				list.extend(["5", "6"])
+			if "weekday" in list:
+				list.extend(["0", "1", "2", "3", "4"])
+			if dayofweek in list:
+				return True
+
+		for exclude in self.exclude[0]:
+			if exclude.search(title):
+				return True
+		for exclude in self.exclude[1]:
+			if exclude.search(short):
+				return True
+		for exclude in self.exclude[2]:
+			if exclude.search(extended):
+				return True
+		return False
+
+	def checkFilter(self, title, short, extended, dayofweek):
+		if self.checkExcluded(title, short, extended, dayofweek):
+			return True
+
+		return self.checkIncluded(title, short, extended, dayofweek)
+
+	def checkIncluded(self, title, short, extended, dayofweek):
+		if self.include[3]:
+			list = [x for x in self.include[3]]
+			if "weekend" in list:
+				list.extend(["5", "6"])
+			if "weekday" in list:
+				list.extend(["0", "1", "2", "3", "4"])
+			if dayofweek not in list:
+				return True
+
+		for include in self.include[0]:
+			if not include.search(title):
+				return True
+		for include in self.include[1]:
+			if not include.search(short):
+				return True
+		for include in self.include[2]:
+			if not include.search(extended):
+				return True
+
+		return False
+
+	def checkServices(self, check_service):
+		services = self.services
+		bouquets = self.bouquets
+		if services or bouquets:
+			addbouquets = []
+
+			for service in services:
+				if service == check_service:
+					return False
+
+				myref = eServiceReference(str(service))
+				if myref.flags & eServiceReference.isGroup:
+					addbouquets.append(service)
+
+			serviceHandler = eServiceCenter.getInstance()
+			for bouquet in bouquets + addbouquets:
+				myref = eServiceReference(str(bouquet))
+				mylist = serviceHandler.list(myref)
+				if mylist is not None:
+					while 1:
+						s = mylist.getNext()
+						# TODO: I wonder if its sane to assume we get services here (and not just new lists)
+						# We can ignore markers & directorys here because they won't match any event's service :-)
+						if s.valid():
+							# strip all after last :
+							value = s.toString()
+							pos = value.rfind(':')
+							if pos != -1:
+								value = value[:pos+1]
+
+							if value == check_service:
+								return False
+						else:
+							break
+			return True
+		return False
+
+	"""
+	Return alternative service including a given ref.
+	Note that this only works for alternatives that the autotimer is restricted to.
+	"""
+	def getAlternative(self, override_service):
+		services = self.services
+		if services:
+			serviceHandler = eServiceCenter.getInstance()
+
+			for service in services:
+				myref = eServiceReference(str(service))
+				if myref.flags & eServiceReference.isGroup:
+					mylist = serviceHandler.list(myref)
+					if mylist is not None:
+						while 1:
+							s = mylist.getNext()
+							if s.valid():
+								# strip all after last :
+								value = s.toString()
+								pos = value.rfind(':')
+								if pos != -1:
+									value = value[:pos+1]
+
+								if value == override_service:
+									return service
+							else:
+								break
+		return override_service
+
+	def checkTimespan(self, begin):
+		return self.checkAnyTimespan(begin, *self.timespan)
+
+	def decrementCounter(self):
+		if self.matchCount and self.matchLeft > 0:
+			self.matchLeft -= 1
+
+	def getAfterEvent(self):
+		for afterevent in self.afterevent:
+			if afterevent[1][0] is None:
+				return afterevent[0]
+		return None
+
+	def getAfterEventTimespan(self, end):
+		for afterevent in self.afterevent:
+			if not self.checkAnyTimespan(end, *afterevent[1]):
+				return afterevent[0]
+		return None
+
+### Misc
+
+	def __copy__(self):
+		return self.__class__(
+			self.id,
+			self.name,
+			self.match,
+			self.enabled,
+			timespan = self.timespan,
+			services = self.services,
+			offset = self.offset,
+			afterevent = self.afterevent,
+			exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.getExcludedDays()),
+			maxduration = self.maxduration,
+			destination = self.destination,
+			include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.getIncludedDays()),
+			matchCount = self.matchCount,
+			matchLeft = self.matchLeft,
+			matchLimit = self.matchLimit,
+			matchFormatString = self.matchFormatString,
+			lastBegin = self.lastBegin,
+			justplay = self.justplay,
+			avoidDuplicateDescription = self.avoidDuplicateDescription,
+			bouquets = self.bouquets,
+			tags = self.tags,
+			encoding = self.encoding,
+			searchType = self.searchType,
+			searchCase = self.searchCase,
+			overrideAlternatives = self.overrideAlternatives
+		)
+
+	def __deepcopy__(self, memo):
+		return self.__class__(
+			self.id,
+			self.name,
+			self.match,
+			self.enabled,
+			timespan = self.timespan,
+			services = self.services[:],
+			offset = self.offset and self.offset[:],
+			afterevent = self.afterevent[:],
+			exclude = (self.getExcludedTitle(), self.getExcludedShort(), self.getExcludedDescription(), self.exclude[3][:]),
+			maxduration = self.maxduration,
+			destination = self.destination,
+			include = (self.getIncludedTitle(), self.getIncludedShort(), self.getIncludedDescription(), self.include[3][:]),
+			matchCount = self.matchCount,
+			matchLeft = self.matchLeft,
+			matchLimit = self.matchLimit,
+			matchFormatString = self.matchFormatString,
+			lastBegin = self.lastBegin,
+			justplay = self.justplay,
+			avoidDuplicateDescription = self.avoidDuplicateDescription,
+			bouquets = self.bouquets[:],
+			tags = self.tags[:],
+			encoding = self.encoding,
+			searchType = self.searchType,
+			searchCase = self.searchCase,
+			overrideAlternatives = self.overrideAlternatives
+		)
+
+	def __eq__(self, other):
+		if isinstance(other, AutoTimerComponent):
+			return self.id == other.id
+		return False
+
+	def __lt__(self, other):
+		if isinstance(other, AutoTimerComponent):
+			return self.name.lower() < other.name.lower()
+		return False
+
+	def __ne__(self, other):
+		return not self.__eq__(other)
+
+	def __repr__(self):
+		return ''.join((
+			'<AutomaticTimer ',
+			self.name,
+			' (',
+			', '.join((
+					str(self.match),
+					str(self.encoding),
+					str(self.searchCase),
+					str(self.searchType),
+			 		str(self.timespan),
+			 		str(self.services),
+			 		str(self.offset),
+			 		str(self.afterevent),
+			 		str(([x.pattern for x in self.exclude[0]],
+						[x.pattern for x in self.exclude[1]],
+						[x.pattern for x in self.exclude[2]],
+						self.exclude[3]
+					)),
+			 		str(([x.pattern for x in self.include[0]],
+						[x.pattern for x in self.include[1]],
+						[x.pattern for x in self.include[2]],
+						self.include[3]
+					)),
+			 		str(self.maxduration),
+			 		str(self.enabled),
+			 		str(self.destination),
+			 		str(self.matchCount),
+			 		str(self.matchLeft),
+			 		str(self.matchLimit),
+			 		str(self.matchFormatString),
+			 		str(self.lastBegin),
+			 		str(self.justplay),
+			 		str(self.avoidDuplicateDescription),
+					str(self.bouquets),
+					str(self.tags),
+					str(self.overrideAlternatives),
+			 )),
+			 ")>"
+		))
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerConfiguration.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerConfiguration.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerConfiguration.py	(revision 5870)
@@ -0,0 +1,708 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
+from AutoTimerComponent import AutoTimerComponent
+from RecordTimer import AFTEREVENT
+from Tools.XMLTools import stringToXML
+from ServiceReference import ServiceReference
+
+from enigma import eServiceReference
+
+CURRENT_CONFIG_VERSION = "5"
+
+def getValue(definitions, default):
+	# Initialize Output
+	ret = ""
+
+	# How many definitions are present
+	if isinstance(definitions, list):
+		Len = len(definitions)
+		if Len > 0:
+			childNodes = definitions[Len-1].text
+		else:
+			childNodes = ""
+	else:
+		ret = definitions.text
+
+	# Return stripped output or (if empty) default
+	return ret.strip() or default
+
+def parseConfig(configuration, list, version = None, uniqueTimerId = 0, defaultTimer = None):
+	if version != CURRENT_CONFIG_VERSION:
+		parseConfigOld(configuration, list, uniqueTimerId)
+		return
+
+	if defaultTimer is not None:
+		# Read in defaults for a new timer
+		for defaults in configuration.findall("defaults"):
+			parseEntry(defaults, defaultTimer, True)
+
+	for timer in configuration.findall("timer"):
+		uniqueTimerId += 1
+		baseTimer = AutoTimerComponent(
+			uniqueTimerId,
+			'',
+			'',
+			True
+		)
+
+		if parseEntry(timer, baseTimer):
+			list.append(baseTimer)
+
+def parseEntry(element, baseTimer, defaults = False):
+	if not defaults:
+		# Read out match
+		baseTimer.match = element.get("match", "").encode("UTF-8")
+		if not baseTimer.match:
+			print '[AutoTimer] Erroneous config is missing attribute "match", skipping entry'
+			return False
+
+		# Read out name
+		baseTimer.name = element.get("name", "").encode("UTF-8")
+		if not baseTimer.name:
+			print '[AutoTimer] Timer is missing attribute "name", defaulting to match'
+			baseTimer.name = baseTimer.match
+
+		# Read out enabled
+		enabled = element.get("enabled", "yes")
+		if enabled == "no":
+			baseTimer.enabled = False
+		elif enabled == "yes":
+			baseTimer.enabled = True
+		else:
+			print '[AutoTimer] Erroneous config contains invalid value for "enabled":', enabled,', disabling'
+			baseTimer.enabled = False
+
+	# Read out encoding (won't change if no value is set)
+	baseTimer.encoding = element.get("encoding")
+
+	# Read out search type/case
+	baseTimer.searchType = element.get("searchType", baseTimer.searchType)
+	baseTimer.searchCase = element.get("searchCase", baseTimer.searchCase)
+
+	# Read out if we should change to alternative services
+	baseTimer.overrideAlternatives = int(element.get("overrideAlternatives", baseTimer.overrideAlternatives))
+
+	# Read out timespan
+	start = element.get("from")
+	end = element.get("to")
+	if start and end:
+		start = [int(x) for x in start.split(':')]
+		end = [int(x) for x in end.split(':')]
+		baseTimer.timespan = (start, end)
+
+	# Read out max length
+	maxduration = element.get("maxduration")
+	if maxduration:
+		baseTimer.maxduration = int(maxduration)*60
+
+	# Read out recording path
+	default = baseTimer.destination or ""
+	baseTimer.destination = element.get("location", default).encode("UTF-8") or None
+
+	# Read out offset
+	offset = element.get("offset")
+	if offset:
+		offset = offset.split(",")
+		if len(offset) == 1:
+			before = after = int(offset[0] or 0) * 60
+		else:
+			before = int(offset[0] or 0) * 60
+			after = int(offset[1] or 0) * 60
+		baseTimer.offset = (before, after)
+
+	# Read out counter
+	baseTimer.matchCount = int(element.get("counter", 0))
+	baseTimer.matchFormatString = element.get("counterFormat", "")
+	if not defaults:
+		baseTimer.matchLeft = int(element.get("left", baseTimer.matchCount))
+		baseTimer.matchLimit = element.get("lastActivation", "")
+		baseTimer.lastBegin = int(element.get("lastBegin", 0))
+
+	# Read out justplay
+	baseTimer.justplay = int(element.get("justplay", 0))
+
+	# Read out avoidDuplicateDescription
+	baseTimer.avoidDuplicateDescription = int(element.get("avoidDuplicateDescription", 0))
+
+	# Read out allowed services
+	l = element.findall("serviceref")
+	if l:
+		servicelist = []
+
+		for service in l:
+			value = service.text
+			if value:
+				myref = eServiceReference(str(value))
+				if not (myref.flags & eServiceReference.isGroup):
+					# strip all after last :
+					pos = value.rfind(':')
+					if pos != -1:
+						value = value[:pos+1]
+
+				servicelist.append(value)
+		baseTimer.services = servicelist
+
+	# Read out allowed bouquets
+	l = element.findall("bouquet")
+	if l:
+		bouquets = []
+		for bouquet in l:
+			value = bouquet.text
+			if value:
+				bouquets.append(value)
+		baseTimer.bouquets = bouquets
+
+	# Read out afterevent
+	l = element.findall("afterevent")
+	if l:
+		idx = {
+			"none": AFTEREVENT.NONE,
+			"deepstandby": AFTEREVENT.DEEPSTANDBY,
+			"shutdown": AFTEREVENT.DEEPSTANDBY,
+			"standby": AFTEREVENT.STANDBY,
+			"auto": AFTEREVENT.AUTO
+		}
+		afterevents = []
+		for afterevent in l:
+			value = afterevent.text
+
+			if idx.has_key(value):
+				value = idx[value]
+			else:
+				print '[AutoTimer] Erroneous config contains invalid value for "afterevent":', afterevent,', ignoring definition'
+				continue
+
+			start = afterevent.get("from")
+			end = afterevent.get("to")
+			if start and end:
+				start = [int(x) for x in start.split(':')]
+				end = [int(x) for x in end.split(':')]
+				afterevents.append((value, (start, end)))
+			else:
+				afterevents.append((value, None))
+		baseTimer.afterevent = afterevents
+
+	# Read out exclude
+	l = element.findall("exclude")
+	idx = {"title": 0, "shortdescription": 1, "description": 2, "dayofweek": 3}
+	if l:
+		excludes = ([], [], [], [])
+		for exclude in l:
+			where = exclude.get("where")
+			value = exclude.text
+			if not (value and where):
+				continue
+
+			if idx.has_key(where):
+				excludes[idx[where]].append(value.encode("UTF-8"))
+		baseTimer.exclude = excludes
+
+	# Read out includes (use same idx)
+	l = element.findall("include")
+	if l:
+		includes = ([], [], [], [])
+		for include in l:
+			where = include.get("where")
+			value = include.text
+			if not (value and where):
+				continue
+
+			if idx.has_key(where):
+				includes[idx[where]].append(value.encode("UTF-8"))
+		baseTimer.include = includes
+
+	# Read out recording tags
+	l =  element.findall("tag")
+	if l:
+		tags = []
+		for tag in l:
+			value = tag.text
+			if not value:
+				continue
+
+			tags.append(value.encode("UTF-8"))
+		baseTimer.tags = tags
+
+	return True
+
+def parseConfigOld(configuration, list, uniqueTimerId = 0):
+	print "[AutoTimer] Trying to parse old config"
+
+	# Iterate Timers
+	for timer in configuration.findall("timer"):
+		# Increment uniqueTimerId
+		uniqueTimerId += 1
+
+		# Get name (V2+)
+		name = timer.get("name")
+		if name:
+			name = name.encode("UTF-8")
+		# Get name (= match) (V1)
+		else:
+			# Read out name
+			name = getValue(timer.findall("name"), "").encode("UTF-8")
+
+		if not name:
+			print '[AutoTimer] Erroneous config is missing attribute "name", skipping entry'
+			continue
+
+		# Read out match (V3+)
+		match = timer.get("match")
+		if match:
+			# Read out match
+			match = match.encode("UTF-8")
+			if not match:
+				print '[AutoTimer] Erroneous config contains empty attribute "match", skipping entry'
+				continue
+		# V2-
+		else:
+			# Setting match to name
+			match = name
+
+
+		# See if Timer is ensabled (V2+)
+		enabled = timer.get("enabled")
+		if enabled:
+			if enabled == "no":
+				enabled = False
+			elif enabled == "yes":
+				enabled = True
+			else:
+				print '[AutoTimer] Erroneous config contains invalid value for "enabled":', enabled,', skipping entry'
+				enabled = False
+		# V1
+		else:
+			elements = timer.findall("enabled")
+			if elements:
+				if getValue(elements, "yes") == "no":
+					enabled = False
+				else:
+					enabled = True
+			else:
+				enabled = True
+
+		# Read out timespan (V4+; Falling back on missing definition should be OK)
+		start = timer.get("from")
+		end = timer.get("to")
+		if start and end:
+			start = [int(x) for x in start.split(':')]
+			end = [int(x) for x in end.split(':')]
+			timetuple = (start, end)
+		# V3-
+		else:
+			elements = timer.findall("timespan")
+			Len = len(elements)
+			if Len:
+				# Read out last definition
+				start = elements[Len-1].get("from")
+				end = elements[Len-1].get("to")
+				if start and end:
+					start = [int(x) for x in start.split(':')]
+					end = [int(x) for x in end.split(':')]
+					timetuple = (start, end)
+				else:
+					print '[AutoTimer] Erroneous config contains invalid definition of "timespan", ignoring definition'
+					timetuple = None
+			else:
+				timetuple = None
+
+		# Read out allowed services (V*)
+		elements = timer.findall("serviceref")
+		if elements:
+			servicelist = []
+			for service in elements:
+				value = service.text
+				if value:
+					myref = eServiceReference(str(value))
+					if not (myref.flags & eServiceReference.isGroup):
+						# strip all after last :
+						pos = value.rfind(':')
+						if pos != -1:
+							value = value[:pos+1]
+
+					servicelist.append(value)
+		else:
+			servicelist = None
+
+		# Read out allowed bouquets (V* though officially supported since V4)
+		bouquets = []
+		for bouquet in timer.findall("bouquet"):
+			value = bouquet.text
+			if value:
+				bouquets.append(value)
+
+		# Read out offset (V4+)
+		offset = timer.get("offset")
+		if offset:
+			offset = offset.split(",")
+			if len(offset) == 1:
+				before = after = int(offset[0] or 0) * 60
+			else:
+				before = int(offset[0] or 0) * 60
+				after = int(offset[1] or 0) * 60
+			offset = (before, after)
+		# V3-
+		else:
+			elements = timer.findall("offset")
+			Len = len(elements)
+			if Len:
+				value = elements[Len-1].get("both")
+				if value == '':
+					before = int(elements[Len-1].get("before", 0)) * 60
+					after = int(elements[Len-1].get("after", 0)) * 60
+				else:
+					before = after = int(value) * 60
+				offset = (before, after)
+			else:
+				offset = None
+
+		# Read out counter
+		counter = int(timer.get("counter", '0'))
+		counterLeft = int(timer.get("left", counter))
+		counterLimit = timer.get("lastActivation")
+		counterFormat = timer.get("counterFormat", "")
+		lastBegin = int(timer.get("lastBegin", 0))
+
+		# Read out justplay
+		justplay = int(timer.get("justplay", '0'))
+
+		# Read out avoidDuplicateDescription
+		avoidDuplicateDescription = int(timer.get("avoidDuplicateDescription", 0))
+
+		# Read out afterevent (compatible to V* though behaviour for V3- is different as V4+ allows multiple afterevents while the last definication was chosen before)
+		idx = {
+			"none": AFTEREVENT.NONE,
+			"deepstandby": AFTEREVENT.DEEPSTANDBY,
+			"shutdown": AFTEREVENT.DEEPSTANDBY,
+			"standby": AFTEREVENT.STANDBY,
+			"auto": AFTEREVENT.AUTO
+		}
+		afterevent = []
+		for element in timer.findall("afterevent"):
+			value = element.text
+
+			if idx.has_key(value):
+				value = idx[value]
+			else:
+				print '[AutoTimer] Erroneous config contains invalid value for "afterevent":', afterevent,', ignoring definition'
+				continue
+
+			start = element.get("from")
+			end = element.get("to")
+			if start and end:
+				start = [int(x) for x in start.split(':')]
+				end = [int(x) for x in end.split(':')]
+				afterevent.append((value, (start, end)))
+			else:
+				afterevent.append((value, None))
+
+		# Read out exclude (V*)
+		idx = {"title": 0, "shortdescription": 1, "description": 2, "dayofweek": 3}
+		excludes = ([], [], [], [])
+		for exclude in timer.findall("exclude"):
+			where = exclude.get("where")
+			value = exclude.text
+			if not (value and where):
+				continue
+
+			if idx.has_key(where):
+				excludes[idx[where]].append(value.encode("UTF-8"))
+
+		# Read out includes (use same idx) (V4+ feature, should not harm V3-)
+		includes = ([], [], [], [])
+		for include in timer.findall("include"):
+			where = include.get("where")
+			value = include.text
+			if not (value and where):
+				continue
+
+			if idx.has_key(where):
+				includes[idx[where]].append(value.encode("UTF-8"))
+
+		# Read out max length (V4+)
+		maxlen = timer.get("maxduration")
+		if maxlen:
+			maxlen = int(maxlen)*60
+		# V3-
+		else:
+			elements = timer.findall("maxduration")
+			if elements:
+				maxlen = getValue(elements, None)
+				if maxlen is not None:
+					maxlen = int(maxlen)*60
+			else:
+				maxlen = None
+
+		# Read out recording path
+		destination = timer.get("destination", "").encode("UTF-8") or None
+
+		# Read out recording tags
+		tags = []
+		for tag in timer.findall("tag"):
+			value = tag.text
+			if not value:
+				continue
+
+			tags.append(value.encode("UTF-8"))
+
+		# Finally append timer
+		list.append(AutoTimerComponent(
+				uniqueTimerId,
+				name,
+				match,
+				enabled,
+				timespan = timetuple,
+				services = servicelist,
+				offset = offset,
+				afterevent = afterevent,
+				exclude = excludes,
+				include = includes,
+				maxduration = maxlen,
+				destination = destination,
+				matchCount = counter,
+				matchLeft = counterLeft,
+				matchLimit = counterLimit,
+				matchFormatString = counterFormat,
+				lastBegin = lastBegin,
+				justplay = justplay,
+				avoidDuplicateDescription = avoidDuplicateDescription,
+				bouquets = bouquets,
+				tags = tags
+		))
+
+def writeConfig(filename, defaultTimer, timers):
+	# Generate List in RAM
+	list = ['<?xml version="1.0" ?>\n<autotimer version="', CURRENT_CONFIG_VERSION, '">\n\n']
+
+	# This gets deleted afterwards if we do not have set any defaults
+	list.append(' <defaults')
+
+	# Timespan
+	if defaultTimer.hasTimespan():
+		list.extend((' from="', defaultTimer.getTimespanBegin(), '" to="', defaultTimer.getTimespanEnd(), '"'))
+
+	# Duration
+	if defaultTimer.hasDuration():
+		list.extend((' maxduration="', str(defaultTimer.getDuration()), '"'))
+
+	# Destination
+	if defaultTimer.hasDestination():
+		list.extend((' location="', stringToXML(defaultTimer.destination), '"'))
+
+	# Offset
+	if defaultTimer.hasOffset():
+		if defaultTimer.isOffsetEqual():
+			list.extend((' offset="', str(defaultTimer.getOffsetBegin()), '"'))
+		else:
+			list.extend((' offset="', str(defaultTimer.getOffsetBegin()), ',', str(defaultTimer.getOffsetEnd()), '"'))
+
+	# Counter
+	if defaultTimer.hasCounter():
+		list.extend((' counter="', str(defaultTimer.getCounter()), '"'))
+		if defaultTimer.hasCounterFormatString():
+			list.extend((' counterFormat="', str(defaultTimer.getCounterFormatString()), '"'))
+
+	# Duplicate Description
+	if defaultTimer.getAvoidDuplicateDescription():
+		list.append(' avoidDuplicateDescription="1" ')
+
+	# Only display justplay if true
+	if defaultTimer.justplay:
+		list.extend((' justplay="', str(defaultTimer.getJustplay()), '"'))
+
+	# Only display encoding if != utf-8
+	if defaultTimer.encoding != 'UTF-8':
+		list.extend((' encoding="', str(defaultTimer.encoding), '"'))
+
+	# Only display searchType if exact
+	if defaultTimer.searchType == "exact":
+		list.extend((' searchType="', str(defaultTimer.searchType), '"'))
+
+	# Only display searchCase if sensitive
+	if defaultTimer.searchCase == "sensitive":
+		list.extend((' searchCase="', str(defaultTimer.searchCase), '"'))
+
+	# Close still opened defaults tag
+	list.append('>\n')
+
+	# Services
+	for serviceref in defaultTimer.services:
+		list.extend(('  <serviceref>', serviceref, '</serviceref>'))
+		ref = ServiceReference(str(serviceref))
+		list.extend((' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'))
+
+	# Bouquets
+	for bouquet in defaultTimer.bouquets:
+		list.extend(('  <bouquet>', str(bouquet), '</bouquet>'))
+		ref = ServiceReference(str(bouquet))
+		list.extend((' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'))
+
+	# AfterEvent
+	if defaultTimer.hasAfterEvent():
+		idx = {
+			AFTEREVENT.NONE: "none",
+			AFTEREVENT.STANDBY: "standby",
+			AFTEREVENT.DEEPSTANDBY: "shutdown",
+			AFTEREVENT.AUTO: "auto"
+		}
+		for afterevent in defaultTimer.afterevent:
+			action, timespan = afterevent
+			list.append('  <afterevent')
+			if timespan[0] is not None:
+				list.append(' from="%02d:%02d" to="%02d:%02d"' % (timespan[0][0], timespan[0][1], timespan[1][0], timespan[1][1]))
+			list.extend(('>', idx[action], '</afterevent>\n'))
+
+	# Excludes
+	for title in defaultTimer.getExcludedTitle():
+		list.extend(('  <exclude where="title">', stringToXML(title), '</exclude>\n'))
+	for short in defaultTimer.getExcludedShort():
+		list.extend(('  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'))
+	for desc in defaultTimer.getExcludedDescription():
+		list.extend(('  <exclude where="description">', stringToXML(desc), '</exclude>\n'))
+	for day in defaultTimer.getExcludedDays():
+		list.extend(('  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'))
+
+	# Includes
+	for title in defaultTimer.getIncludedTitle():
+		list.extend(('  <include where="title">', stringToXML(title), '</include>\n'))
+	for short in defaultTimer.getIncludedShort():
+		list.extend(('  <include where="shortdescription">', stringToXML(short), '</include>\n'))
+	for desc in defaultTimer.getIncludedDescription():
+		list.extend(('  <include where="description">', stringToXML(desc), '</include>\n'))
+	for day in defaultTimer.getIncludedDays():
+		list.extend(('  <include where="dayofweek">', stringToXML(day), '</include>\n'))
+
+	# Tags
+	for tag in defaultTimer.tags:
+		list.extend(('  <tag>', stringToXML(tag), '</tag>\n'))
+
+	# Keep the list clean
+	if len(list) == 5:
+		list.pop() # >
+		list.pop() # <defaults
+	else:
+		list.append(' </defaults>\n\n')
+
+	# Iterate timers
+	for timer in timers:
+		# Common attributes (match, enabled)
+		list.extend((' <timer name="', stringToXML(timer.name), '" match="', stringToXML(timer.match), '" enabled="', timer.getEnabled(), '"'))
+
+		# Timespan
+		if timer.hasTimespan():
+			list.extend((' from="', timer.getTimespanBegin(), '" to="', timer.getTimespanEnd(), '"'))
+
+		# Duration
+		if timer.hasDuration():
+			list.extend((' maxduration="', str(timer.getDuration()), '"'))
+
+		# Destination
+		if timer.hasDestination():
+			list.extend((' location="', stringToXML(timer.destination), '"'))
+
+		# Offset
+		if timer.hasOffset():
+			if timer.isOffsetEqual():
+				list.extend((' offset="', str(timer.getOffsetBegin()), '"'))
+			else:
+				list.extend((' offset="', str(timer.getOffsetBegin()), ',', str(timer.getOffsetEnd()), '"'))
+
+		# Counter
+		if timer.hasCounter():
+			list.extend((' lastBegin="', str(timer.getLastBegin()), '" counter="', str(timer.getCounter()), '" left="', str(timer.getCounterLeft()) ,'"'))
+			if timer.hasCounterFormatString():
+				list.extend((' lastActivation="', str(timer.getCounterLimit()), '"'))
+				list.extend((' counterFormat="', str(timer.getCounterFormatString()), '"'))
+
+		# Duplicate Description
+		if timer.getAvoidDuplicateDescription():
+			list.extend((' avoidDuplicateDescription="', str(timer.getAvoidDuplicateDescription()), '"'))
+
+		# Only display justplay if true
+		if timer.justplay:
+			list.extend((' justplay="', str(timer.getJustplay()), '"'))
+
+		# Only display encoding if != utf-8
+		if timer.encoding != 'UTF-8':
+			list.extend((' encoding="', str(timer.encoding), '"'))
+
+		# Only display searchType if exact
+		if timer.searchType == "exact":
+			list.extend((' searchType="', str(timer.searchType), '"'))
+
+		# Only display searchCase if sensitive
+		if timer.searchCase == "sensitive":
+			list.extend((' searchCase="', str(timer.searchCase), '"'))
+
+		# Only display overrideAlternatives if true
+		if timer.overrideAlternatives:
+			list.extend((' overrideAlternatives="', str(timer.getOverrideAlternatives()), '"'))
+
+		# Close still opened timer tag
+		list.append('>\n')
+
+		# Services
+		for serviceref in timer.services:
+			list.extend(('  <serviceref>', serviceref, '</serviceref>'))
+			ref = ServiceReference(str(serviceref))
+			list.extend((' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'))
+
+		# Bouquets
+		for bouquet in timer.bouquets:
+			list.extend(('  <bouquet>', str(bouquet), '</bouquet>'))
+			ref = ServiceReference(str(bouquet))
+			list.extend((' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'))
+
+		# AfterEvent
+		if timer.hasAfterEvent():
+			idx = {
+				AFTEREVENT.NONE: "none",
+				AFTEREVENT.STANDBY: "standby",
+				AFTEREVENT.DEEPSTANDBY: "shutdown",
+				AFTEREVENT.AUTO: "auto"
+			}
+			for afterevent in timer.afterevent:
+				action, timespan = afterevent
+				list.append('  <afterevent')
+				if timespan[0] is not None:
+					list.append(' from="%02d:%02d" to="%02d:%02d"' % (timespan[0][0], timespan[0][1], timespan[1][0], timespan[1][1]))
+				list.extend(('>', idx[action], '</afterevent>\n'))
+
+		# Excludes
+		for title in timer.getExcludedTitle():
+			list.extend(('  <exclude where="title">', stringToXML(title), '</exclude>\n'))
+		for short in timer.getExcludedShort():
+			list.extend(('  <exclude where="shortdescription">', stringToXML(short), '</exclude>\n'))
+		for desc in timer.getExcludedDescription():
+			list.extend(('  <exclude where="description">', stringToXML(desc), '</exclude>\n'))
+		for day in timer.getExcludedDays():
+			list.extend(('  <exclude where="dayofweek">', stringToXML(day), '</exclude>\n'))
+
+		# Includes
+		for title in timer.getIncludedTitle():
+			list.extend(('  <include where="title">', stringToXML(title), '</include>\n'))
+		for short in timer.getIncludedShort():
+			list.extend(('  <include where="shortdescription">', stringToXML(short), '</include>\n'))
+		for desc in timer.getIncludedDescription():
+			list.extend(('  <include where="description">', stringToXML(desc), '</include>\n'))
+		for day in timer.getIncludedDays():
+			list.extend(('  <include where="dayofweek">', stringToXML(day), '</include>\n'))
+
+		# Tags
+		for tag in timer.tags:
+			list.extend(('  <tag>', stringToXML(tag), '</tag>\n'))
+
+		# End of Timer
+		list.append(' </timer>\n\n')
+
+	# End of Configuration
+	list.append('</autotimer>\n')
+
+	# Save to Flash
+	file = open(filename, 'w')
+	file.writelines(list)
+
+	file.close()
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerEditor.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerEditor.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerEditor.py	(revision 5870)
@@ -0,0 +1,1260 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Components.ConfigList import ConfigListScreen
+from Screens.ChannelSelection import SimpleChannelSelection
+from Screens.EpgSelection import EPGSelection
+from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+
+# GUI (Summary)
+from Screens.Setup import SetupSummary
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Button import Button
+
+# Configuration
+from Components.config import getConfigListEntry, ConfigEnableDisable, \
+	ConfigYesNo, ConfigText, ConfigClock, ConfigNumber, ConfigSelection, \
+	config, NoSave
+
+# Timer
+from RecordTimer import AFTEREVENT
+
+# Needed to convert our timestamp back and forth
+from time import localtime, mktime
+
+# Show ServiceName instead of ServiceReference
+from ServiceReference import ServiceReference
+
+# addAutotimerFromService, AutoTimerChannelSelection
+from enigma import eServiceCenter, eServiceReference, iServiceInformation
+
+# Default Record Directory
+from Tools import Directories
+
+# Tags
+from Screens.MovieSelection import getPreferredTagEditor
+
+weekdays = [
+	("0", _("Monday")),
+	("1", _("Tuesday")),
+	("2", _("Wednesday")),
+	("3", _("Thursday")),
+	("4", _("Friday")),
+	("5", _("Saturday")),
+	("6", _("Sunday")),
+	("weekend", _("Weekend")),
+	("weekday", _("Weekday"))
+]
+
+class ExtendedConfigText(ConfigText):
+	def __init__(self, default = "", fixed_size = True, visible_width = False):
+		ConfigText.__init__(self, default = default, fixed_size = fixed_size, visible_width = visible_width)
+
+		# Workaround some characters currently not "typeable" using NumericalTextInput
+		mapping = self.mapping
+		if mapping:
+			if "&" not in mapping[0]:
+				mapping[0] += "&"
+			if ";" not in mapping[0]:
+				mapping[0] += ";"
+			if "%" not in mapping[0]:
+				mapping[0] += "%"
+
+class SimpleBouquetSelection(SimpleChannelSelection):
+	def __init__(self, session, title):
+		SimpleChannelSelection.__init__(self, session, title)
+		self.skinName = "SimpleChannelSelection"
+
+	def channelSelected(self):
+		ref = self.getCurrentSelection()
+		if (ref.flags & 7) == 7:
+			self.close(ref)
+		else:
+			# We return the currently active path here
+			# Asking the user if this is what he wants might be better though
+			self.close(self.servicePath[-1])
+
+class AutoTimerChannelSelection(SimpleChannelSelection):
+	def __init__(self, session, autotimer):
+		SimpleChannelSelection.__init__(self, session, _("Channel Selection"))
+		self.skinName = "SimpleChannelSelection"
+		self.autotimer = autotimer
+
+		self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
+			{
+				"showEPGList": self.channelSelected
+			}
+		)
+
+	def channelSelected(self):
+		ref = self.getCurrentSelection()
+		if (ref.flags & 7) == 7:
+			self.enterPath(ref)
+		elif not (ref.flags & eServiceReference.isMarker):
+			self.session.open(
+				AutoTimerEPGSelection,
+				ref
+			)
+
+class AutoTimerEPGSelection(EPGSelection):
+	def __init__(self, *args):
+		EPGSelection.__init__(self, *args)
+		self.skinName = "EPGSelection"
+
+	def infoKeyPressed(self):
+		self.timerAdd()
+
+	def timerAdd(self):
+		cur = self["list"].getCurrent()
+		evt = cur[0]
+		sref = cur[1]
+		if not evt:
+			return
+
+		addAutotimerFromEvent(self.session, evt = evt, service = sref)
+
+	def onSelectionChanged(self):
+		pass
+
+class AutoTimerEditorBase:
+	""" Base Class for all Editors """
+	def __init__(self, timer, editingDefaults = False):
+		# Keep Timer
+		self.timer = timer
+		self.editingDefaults = editingDefaults
+
+		# See if we are filtering some strings
+		excludes = (
+			timer.getExcludedTitle(),
+			timer.getExcludedShort(),
+			timer.getExcludedDescription(),
+			timer.getExcludedDays()
+		)
+		includes = (
+			timer.getIncludedTitle(),
+			timer.getIncludedShort(),
+			timer.getIncludedDescription(),
+			timer.getIncludedDays()
+		)
+		if excludes[0] or excludes[1] \
+				or excludes[2] or excludes[3] \
+				or includes[0] or includes[1] \
+				or includes[2] or includes[3]:
+			self.filterSet = True
+		else:
+			self.filterSet = False
+		self.excludes = excludes
+		self.includes = includes
+
+		# See if services are restricted
+		self.services = timer.services
+		self.bouquets = timer.bouquets
+		if self.services or self.bouquets:
+			self.serviceRestriction = True
+		else:
+			self.serviceRestriction = False
+
+		self.createSetup(timer)
+
+	def createSetup(self, timer):
+		# Name
+		self.name = NoSave(ExtendedConfigText(default = timer.name, fixed_size = False))
+
+		# Match
+		self.match = NoSave(ExtendedConfigText(default = timer.match, fixed_size = False))
+
+		# Encoding
+		default = timer.encoding
+		selection = ['UTF-8', 'ISO8859-15']
+		if default not in selection:
+			selection.append(default)
+		self.encoding = NoSave(ConfigSelection(choices = selection, default = default))
+
+		# ...
+		self.searchType = NoSave(ConfigSelection(choices = [("partial", _("partial match")), ("exact", _("exact match"))], default = timer.searchType))
+		self.searchCase = NoSave(ConfigSelection(choices = [("sensitive", _("case-sensitive search")), ("insensitive", _("case-insensitive search"))], default = timer.searchCase))
+
+		# Alternatives override
+		self.overrideAlternatives = NoSave(ConfigYesNo(default = timer.overrideAlternatives))
+
+		# Justplay
+		self.justplay = NoSave(ConfigSelection(choices = [("zap", _("zap")), ("record", _("record"))], default = {0: "record", 1: "zap"}[int(timer.justplay)]))
+
+		# Timespan
+		now = [x for x in localtime()]
+		if timer.hasTimespan():
+			default = True
+			now[3] = timer.timespan[0][0]
+			now[4] = timer.timespan[0][1]
+			begin = mktime(now)
+			now[3] = timer.timespan[1][0]
+			now[4] = timer.timespan[1][1]
+			end = mktime(now)
+		else:
+			default = False
+			now[3] = 20
+			now[4] = 15
+			begin = mktime(now)
+			now[3] = 23
+			now[4] = 15
+			end = mktime(now)
+		self.timespan = NoSave(ConfigEnableDisable(default = default))
+		self.timespanbegin = NoSave(ConfigClock(default = begin))
+		self.timespanend = NoSave(ConfigClock(default = end))
+
+		# Services have their own Screen
+
+		# Offset
+		if timer.hasOffset():
+			default = True
+			begin = timer.getOffsetBegin()
+			end = timer.getOffsetEnd()
+		else:
+			default = False
+			begin = 5
+			end = 5
+		self.offset = NoSave(ConfigEnableDisable(default = default))
+		self.offsetbegin = NoSave(ConfigNumber(default = begin))
+		self.offsetend = NoSave(ConfigNumber(default = end))
+
+		# AfterEvent
+		if timer.hasAfterEvent():
+			default = {
+				None: "default",
+				AFTEREVENT.NONE: "nothing",
+				AFTEREVENT.DEEPSTANDBY: "deepstandby",
+				AFTEREVENT.STANDBY: "standby",
+				AFTEREVENT.AUTO: "auto"
+			}[timer.afterevent[0][0]]
+		else:
+			default = "default"
+		self.afterevent = NoSave(ConfigSelection(choices = [
+			("default", _("standard")), ("nothing", _("do nothing")),
+			("standby", _("go to standby")),
+			("deepstandby", _("go to deep standby")),
+			("auto", _("auto"))], default = default))
+
+		# AfterEvent (Timespan)
+		if timer.hasAfterEvent() and timer.afterevent[0][1][0] is not None:
+			default = True
+			now[3] = timer.afterevent[0][1][0][0]
+			now[4] = timer.afterevent[0][1][0][1]
+			begin = mktime(now)
+			now[3] = timer.afterevent[0][1][1][0]
+			now[4] = timer.afterevent[0][1][1][1]
+			end = mktime(now)
+		else:
+			default = False
+			now[3] = 23
+			now[4] = 15
+			begin = mktime(now)
+			now[3] = 7
+			now[4] = 0
+			end = mktime(now)
+		self.afterevent_timespan = NoSave(ConfigEnableDisable(default = default))
+		self.afterevent_timespanbegin = NoSave(ConfigClock(default = begin))
+		self.afterevent_timespanend = NoSave(ConfigClock(default = end))
+
+		# Enabled
+		self.enabled = NoSave(ConfigYesNo(default = timer.enabled))
+
+		# Maxduration
+		if timer.hasDuration():
+			default = True
+			duration = timer.getDuration()
+		else:
+			default = False
+			duration =70
+		self.duration = NoSave(ConfigEnableDisable(default = default))
+		self.durationlength = NoSave(ConfigNumber(default = duration))
+
+		# Counter
+		if timer.hasCounter():
+			default = timer.matchCount
+		else:
+			default = 0
+		self.counter = NoSave(ConfigNumber(default = default))
+		self.counterLeft = NoSave(ConfigNumber(default = timer.matchLeft))
+		default = timer.getCounterFormatString()
+		selection = [("", _("Never")), ("%m", _("Monthly")), ("%U", _("Weekly (Sunday)")), ("%W", _("Weekly (Monday)"))]
+		if default not in ('', '%m', '%U', '%W'):
+			selection.append((default, _("Custom (%s)") % (default)))
+		self.counterFormatString = NoSave(ConfigSelection(selection, default = default))
+
+		# Avoid Duplicate Description
+		self.avoidDuplicateDescription = NoSave(ConfigSelection([
+				("0", _("No")),
+				("1", _("On same service")),
+				("2", _("On any service")),
+			],
+			default = str(timer.getAvoidDuplicateDescription())
+		))
+
+		# Custom Location
+		if timer.hasDestination():
+			default = True
+		else:
+			default = False
+
+		self.useDestination = NoSave(ConfigYesNo(default = default))
+
+		default = timer.destination or Directories.resolveFilename(Directories.SCOPE_HDD)
+		choices = config.movielist.videodirs.value
+
+		if default not in choices:
+			choices.append(default)
+		self.destination = NoSave(ConfigSelection(default = default, choices = choices))
+
+		# Tags
+		self.timerentry_tags = timer.tags
+		self.tags = NoSave(ConfigSelection(choices = [len(self.timerentry_tags) == 0 and _("None") or ' '.join(self.timerentry_tags)]))
+
+	def pathSelected(self, res):
+		if res is not None:
+			# I'm pretty sure this will always fail
+			if config.movielist.videodirs.value != self.destination.choices:
+					self.destination.setChoices(config.movielist.videodirs.value, default = res)
+			self.destination.value = res
+
+	def chooseDestination(self):
+		from Screens.LocationBox import MovieLocationBox
+
+		self.session.openWithCallback(
+			self.pathSelected,
+			MovieLocationBox,
+			_("Choose target folder"),
+			self.destination.value,
+			minFree = 100 # Same requirement as in Screens.TimerEntry
+		)
+
+	def tagEditFinished(self, ret):
+		if ret is not None:
+			self.timerentry_tags = ret
+			self.tags.setChoices([len(ret) == 0 and _("None") or ' '.join(ret)])
+
+	def chooseTags(self):
+		preferredTagEditor = getPreferredTagEditor()
+		if preferredTagEditor:
+			self.session.openWithCallback(
+				self.tagEditFinished,
+				preferredTagEditor,
+				self.timerentry_tags
+			)
+
+class AutoTimerEditor(Screen, ConfigListScreen, AutoTimerEditorBase):
+	"""Edit AutoTimer"""
+
+	skin = """<screen name="AutoTimerEdit" title="Edit AutoTimer" position="center,center" size="565,280">
+		<widget name="config" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
+		<ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session, timer, editingDefaults = False):
+		Screen.__init__(self, session)
+
+		AutoTimerEditorBase.__init__(self, timer, editingDefaults)
+
+		# Summary
+		self.setup_title = _("AutoTimer Editor")
+		self.onChangedEntry = []
+
+		# We might need to change shown items, so add some notifiers
+		self.timespan.addNotifier(self.reloadList, initial_call = False)
+		self.offset.addNotifier(self.reloadList, initial_call = False)
+		self.duration.addNotifier(self.reloadList, initial_call = False)
+		self.afterevent.addNotifier(self.reloadList, initial_call = False)
+		self.afterevent_timespan.addNotifier(self.reloadList, initial_call = False)
+		self.counter.addNotifier(self.reloadList, initial_call = False)
+		self.useDestination.addNotifier(self.reloadList, initial_call = False)
+
+		self.refresh()
+
+		ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("OK"))
+		self["key_yellow"] = Button()
+ 		self["key_blue"] = Button()
+
+		# Set Button texts
+		self.renameServiceButton()
+		self.renameFilterButton()
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+			{
+				"cancel": self.cancel,
+				"save": self.maybeSave,
+				"ok": self.ok,
+				"yellow": self.editFilter,
+				"blue": self.editServices
+			}, -2
+		)
+
+		# Trigger change
+		self.changed()
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Edit AutoTimer"))
+
+	def renameFilterButton(self):
+		if self.filterSet:
+			self["key_yellow"].setText(_("Edit Filters"))
+		else:
+			self["key_yellow"].setText(_("Add Filters"))
+
+	def renameServiceButton(self):
+		if self.serviceRestriction:
+			self["key_blue"].setText(_("Edit Services"))
+		else:
+			self["key_blue"].setText(_("Add Services"))
+
+	def changed(self):
+		for x in self.onChangedEntry:
+			try:
+				x()
+			except Exception:
+				pass
+
+	def getCurrentEntry(self):
+		return self["config"].getCurrent()[0]
+
+	def getCurrentValue(self):
+		return str(self["config"].getCurrent()[1].getText())
+
+	def createSummary(self):
+		return SetupSummary
+
+	def refresh(self):
+		# First three entries are only showed when not editing defaults
+		list = []
+		if not self.editingDefaults:
+			list.extend((
+				getConfigListEntry(_("Enabled"), self.enabled),
+				getConfigListEntry(_("Description"), self.name),
+				getConfigListEntry(_("Match Title"), self.match),
+			))
+
+		list.extend((
+			getConfigListEntry(_("EPG Encoding"), self.encoding),
+			getConfigListEntry(_("Search Type"), self.searchType),
+			getConfigListEntry(_("Search strictness"), self.searchCase),
+			getConfigListEntry(_("Timer Type"), self.justplay),
+			getConfigListEntry(_("Override found with alternative Service"), self.overrideAlternatives),
+			getConfigListEntry(_("Only match during Timespan"), self.timespan)
+		))
+
+		# Only allow editing timespan when it's enabled
+		if self.timespan.value:
+			list.extend((
+				getConfigListEntry(_("Begin of Timespan"), self.timespanbegin),
+				getConfigListEntry(_("End of Timespan"), self.timespanend)
+			))
+
+		list.append(getConfigListEntry(_("Custom offset"), self.offset))
+
+		# Only allow editing offsets when it's enabled
+		if self.offset.value:
+			list.extend((
+				getConfigListEntry(_("Offset before recording (in m)"), self.offsetbegin),
+				getConfigListEntry(_("Offset after recording (in m)"), self.offsetend)
+			))
+
+		list.append(getConfigListEntry(_("Set maximum Duration"), self.duration))
+
+		# Only allow editing maxduration when it's enabled
+		if self.duration.value:
+			list.append(getConfigListEntry(_("Maximum Duration (in m)"), self.durationlength))
+
+		list.append(getConfigListEntry(_("After event"), self.afterevent))
+
+		# Only allow setting afterevent timespan when afterevent is active
+		if self.afterevent.value != "default":
+			list.append(getConfigListEntry(_("Execute after Event during Timespan"), self.afterevent_timespan))
+
+			# Only allow editing timespan when it's enabled
+			if self.afterevent_timespan.value:
+				list.extend((
+					getConfigListEntry(_("Begin of after Event Timespan"), self.afterevent_timespanbegin),
+					getConfigListEntry(_("End of after Event Timespan"), self.afterevent_timespanend)
+				))
+
+		list.append(getConfigListEntry(_("Record a maximum of x times"), self.counter))
+
+		# Only allow setting matchLeft when counting hits
+		if self.counter.value:
+			if not self.editingDefaults:
+				list.append(getConfigListEntry(_("Ammount of recordings left"), self.counterLeft))
+			list.append(getConfigListEntry(_("Reset Count"), self.counterFormatString))
+
+		list.append(getConfigListEntry(_("Require Description to be unique"), self.avoidDuplicateDescription))
+
+		# We always add this option though its expert only in enigma2
+		list.append(getConfigListEntry(_("Use a custom location"), self.useDestination))
+		if self.useDestination.value:
+			list.append(getConfigListEntry(_("Custom Location"), self.destination))
+
+		list.append(getConfigListEntry(_("Tags"), self.tags))
+
+		self.list = list
+
+	def reloadList(self, value):
+		self.refresh()
+		self["config"].setList(self.list)
+
+	def editFilter(self):
+		self.session.openWithCallback(
+			self.editFilterCallback,
+			AutoTimerFilterEditor,
+			self.filterSet,
+			self.excludes,
+			self.includes
+		)
+
+	def editFilterCallback(self, ret):
+		if ret:
+			self.filterSet = ret[0]
+			self.excludes = ret[1]
+			self.includes = ret[2]
+			self.renameFilterButton()
+
+	def editServices(self):
+		self.session.openWithCallback(
+			self.editServicesCallback,
+			AutoTimerServiceEditor,
+			self.serviceRestriction,
+			self.services,
+			self.bouquets
+		)
+
+	def editServicesCallback(self, ret):
+		if ret:
+			self.serviceRestriction = ret[0]
+			self.services = ret[1][0]
+			self.bouquets = ret[1][1]
+			self.renameServiceButton()
+
+	def ok(self):
+		cur = self["config"].getCurrent()
+		cur = cur and cur[1]
+		if cur == self.destination:
+			self.chooseDestination()
+		elif cur == self.tags:
+			self.chooseTags()
+		else:
+			ConfigListScreen.keyOK(self)
+
+	def cancel(self):
+		if self["config"].isChanged():
+			self.session.openWithCallback(
+				self.cancelConfirm,
+				MessageBox,
+				_("Really close without saving settings?")
+			)
+		else:
+			self.close(None)
+
+	def cancelConfirm(self, ret):
+		if ret:
+			self.close(None)
+
+	def maybeSave(self):
+		if self.editingDefaults:
+			self.save()
+			return
+		# Check if any match is set
+		if not self.match.value.strip():
+			self.session.open(
+					MessageBox,
+					_("The match attribute is mandatory."),
+					type = MessageBox.TYPE_ERROR,
+					timeout = 5
+			)
+		# Check if we have a trailing whitespace
+		elif self.match.value[-1:] == " ":
+			self.session.openWithCallback(
+				self.saveCallback,
+				MessageBox,
+				_('You entered "%s" as Text to match.\nDo you want to remove trailing whitespaces?') % (self.match.value)
+			)
+		# Just save else
+		else:
+			self.save()
+
+	def saveCallback(self, ret):
+		if ret is not None:
+			if ret:
+				self.match.value = self.match.value.rstrip()
+			self.save()
+		# Don't to anything if MessageBox was canceled!
+
+	def save(self):
+		# Match
+		self.timer.match = self.match.value
+
+		# Name
+		self.timer.name = self.name.value.strip() or self.timer.match
+
+		# Encoding
+		self.timer.encoding = self.encoding.value
+
+		# ...
+		self.timer.searchType = self.searchType.value
+		self.timer.searchCase = self.searchCase.value
+
+		# Alternatives
+		self.timer.overrideAlternatives = self.overrideAlternatives.value
+
+		# Enabled
+		self.timer.enabled = self.enabled.value
+
+		# Justplay
+		self.timer.justplay = self.justplay.value == "zap"
+
+		# Timespan
+		if self.timespan.value:
+			start = self.timespanbegin.value
+			end = self.timespanend.value
+			self.timer.timespan = (start, end)
+		else:
+			self.timer.timespan = None
+
+		# Services
+		if self.serviceRestriction:
+			self.timer.services = self.services
+			self.timer.bouquets = self.bouquets
+		else:
+			self.timer.services = None
+			self.timer.bouquets = None
+
+		# Offset
+		if self.offset.value:
+			self.timer.offset = (self.offsetbegin.value*60, self.offsetend.value*60)
+		else:
+			self.timer.offset = None
+
+		# AfterEvent
+		if self.afterevent.value == "default":
+			self.timer.afterevent = []
+		else:
+			afterevent = {
+				"nothing": AFTEREVENT.NONE,
+				"deepstandby": AFTEREVENT.DEEPSTANDBY,
+				"standby": AFTEREVENT.STANDBY,
+				"auto": AFTEREVENT.AUTO
+			}[self.afterevent.value]
+			# AfterEvent Timespan
+			if self.afterevent_timespan.value:
+				start = self.afterevent_timespanbegin.value
+				end = self.afterevent_timespanend.value
+				self.timer.afterevent = [(afterevent, (start, end))]
+			else:
+				self.timer.afterevent = [(afterevent, None)]
+
+		# Maxduration
+		if self.duration.value:
+			self.timer.maxduration = self.durationlength.value*60
+		else:
+			self.timer.maxduration = None
+
+		# Ex-&Includes
+		if self.filterSet:
+			self.timer.exclude = self.excludes
+			self.timer.include = self.includes
+		else:
+			self.timer.exclude = None
+			self.timer.include = None
+
+		# Counter
+		if self.counter.value:
+			self.timer.matchCount = self.counter.value
+			if self.counterLeft.value <= self.counter.value:
+				self.timer.matchLeft = self.counterLeft.value
+			else:
+				self.timer.matchLeft = self.counter.value
+			if self.counterFormatString.value:
+				self.timer.matchFormatString = self.counterFormatString.value
+			else:
+				self.timer.matchFormatString = ''
+		else:
+			self.timer.matchCount = 0
+			self.timer.matchLeft = 0
+			self.timer.matchFormatString = ''
+
+		self.timer.avoidDuplicateDescription = int(self.avoidDuplicateDescription.value)
+
+		if self.useDestination.value:
+			self.timer.destination = self.destination.value
+		else:
+			self.timer.destination = None
+
+		self.timer.tags = self.timerentry_tags
+
+		# Close
+		self.close(self.timer)
+
+class AutoTimerFilterEditor(Screen, ConfigListScreen):
+	"""Edit AutoTimer Filter"""
+
+	skin = """<screen name="AutoFilterEditor" title="Edit AutoTimer Filters" position="center,center" size="565,245">
+		<widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
+		<ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session, filterset, excludes, includes):
+		Screen.__init__(self, session)
+
+		# Summary
+		self.setup_title = _("AutoTimer Filters")
+		self.onChangedEntry = []
+
+		self.typeSelection = NoSave(ConfigSelection(choices = [
+			("title", _("in Title")),
+			("short", _("in Shortdescription")),
+			("desc", _("in Description")),
+			("day", _("on Weekday"))]
+		))
+		self.typeSelection.addNotifier(self.refresh, initial_call = False)
+
+		self.enabled = NoSave(ConfigEnableDisable(default = filterset))
+
+		self.excludes = excludes
+		self.includes = includes
+
+		self.reloadList()
+
+		ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("Save"))
+		self["key_yellow"] = Button(_("delete"))
+		self["key_blue"] = Button(_("New"))
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+			{
+				"cancel": self.cancel,
+				"save": self.save,
+				"yellow": self.remove,
+				"blue": self.new
+			}
+		)
+
+		# Trigger change
+		self.changed()
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Edit AutoTimer Filters"))
+
+
+	def changed(self):
+		for x in self.onChangedEntry:
+			try:
+				x()
+			except Exception:
+				pass
+
+	def getCurrentEntry(self):
+		return self["config"].getCurrent()[0]
+
+	def getCurrentValue(self):
+		return str(self["config"].getCurrent()[1].getText())
+
+	def createSummary(self):
+		return SetupSummary
+
+	def saveCurrent(self):
+		del self.excludes[self.idx][:]
+		del self.includes[self.idx][:]
+
+		# Warning, accessing a ConfigListEntry directly might be considered evil!
+
+		idx = -1
+		for item in self["config"].getList()[:]:
+			idx += 1
+			# Skip empty entries (and those which are no filters)
+			if item[1].value == "" or idx < 2:
+				continue
+			elif idx < self.lenExcludes:
+				self.excludes[self.idx].append(item[1].value.encode("UTF-8"))
+			else:
+				self.includes[self.idx].append(item[1].value.encode("UTF-8"))
+
+	def refresh(self, *args, **kwargs):
+		self.saveCurrent()
+
+		self.reloadList()
+		self["config"].setList(self.list)
+
+	def reloadList(self):
+		self.list = [
+			getConfigListEntry(_("Enable Filtering"), self.enabled),
+			getConfigListEntry(_("Filter"), self.typeSelection)
+		]
+
+		if self.typeSelection.value == "day":
+			self.idx = 3
+
+			# Weekdays are presented as ConfigSelection
+			self.list.extend([
+				getConfigListEntry(_("Exclude"), NoSave(ConfigSelection(choices = weekdays, default = x)))
+					for x in self.excludes[3]
+			])
+			self.lenExcludes = len(self.list)
+			self.list.extend([
+				getConfigListEntry(_("Include"), NoSave(ConfigSelection(choices = weekdays, default = x)))
+					for x in self.includes[3]
+			])
+			return
+		elif self.typeSelection.value == "title":
+			self.idx = 0
+		elif self.typeSelection.value == "short":
+			self.idx = 1
+		else: # self.typeSelection.value == "desc":
+			self.idx = 2
+
+		self.list.extend([
+			getConfigListEntry(_("Exclude"), NoSave(ExtendedConfigText(default = x, fixed_size = False)))
+				for x in self.excludes[self.idx]
+		])
+		self.lenExcludes = len(self.list)
+		self.list.extend([
+			getConfigListEntry(_("Include"), NoSave(ExtendedConfigText(default = x, fixed_size = False)))
+				for x in self.includes[self.idx]
+		])
+
+	def remove(self):
+		idx = self["config"].getCurrentIndex()
+		if idx and idx > 1:
+			if idx < self.lenExcludes:
+				self.lenExcludes -= 1
+
+			list = self["config"].getList()
+			list.remove(self["config"].getCurrent())
+			self["config"].setList(list)
+
+	def new(self):
+		self.session.openWithCallback(
+			self.typeSelected,
+			ChoiceBox,
+			_("Select type of Filter"),
+			[
+				(_("Exclude"), 0),
+				(_("Include"), 1),
+			]
+		)
+
+	def typeSelected(self, ret):
+		if ret is not None:
+			list = self["config"].getList()
+
+			if ret[1] == 0:
+				pos = self.lenExcludes
+				self.lenExcludes += 1
+				text = ret[0]
+			else:
+				pos = len(self.list)
+				text = ret[0]
+
+			if self.typeSelection.value == "day":
+				entry = getConfigListEntry(text, NoSave(ConfigSelection(choices = weekdays)))
+			else:
+				entry = getConfigListEntry(text, NoSave(ExtendedConfigText(fixed_size = False)))
+
+			list.insert(pos, entry)
+			self["config"].setList(list)
+
+	def cancel(self):
+		if self["config"].isChanged():
+			self.session.openWithCallback(
+				self.cancelConfirm,
+				MessageBox,
+				_("Really close without saving settings?")
+			)
+		else:
+			self.close(None)
+
+	def cancelConfirm(self, ret):
+		if ret:
+			self.close(None)
+
+	def save(self):
+		self.refresh()
+
+		self.close((
+			self.enabled.value,
+			self.excludes,
+			self.includes
+		))
+
+class AutoTimerServiceEditor(Screen, ConfigListScreen):
+	"""Edit allowed Services of a AutoTimer"""
+
+	skin = """<screen name="AutoTimerServiceEditor" title="Edit AutoTimer Services" position="center,center" size="565,245">
+		<widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
+		<ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session, servicerestriction, servicelist, bouquetlist):
+		Screen.__init__(self, session)
+
+		# Summary
+		self.setup_title = _("AutoTimer Services")
+		self.onChangedEntry = []
+
+		self.services = (
+			servicelist[:],
+			bouquetlist[:]
+		)
+
+		self.enabled = NoSave(ConfigEnableDisable(default = servicerestriction))
+		self.typeSelection = NoSave(ConfigSelection(choices = [
+			("channels", _("Channels")),
+			("bouquets", _("Bouquets"))]
+		))
+		self.typeSelection.addNotifier(self.refresh, initial_call = False)
+
+		self.reloadList()
+
+		ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("OK"))
+		self["key_yellow"] = Button(_("delete"))
+		self["key_blue"] = Button(_("New"))
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+			{
+				"cancel": self.cancel,
+				"save": self.save,
+				"yellow": self.remove,
+				"blue": self.new
+			}
+		)
+
+		# Trigger change
+		self.changed()
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Edit AutoTimer Services"))
+
+	def saveCurrent(self):
+		del self.services[self.idx][:]
+
+		# Warning, accessing a ConfigListEntry directly might be considered evil!
+
+		myl = self["config"].getList()[:]
+		myl.pop(0) # Enabled
+		myl.pop(0) # Type
+		for item in myl:
+			self.services[self.idx].append(item[1].value)
+
+	def refresh(self, *args, **kwargs):
+		self.saveCurrent()
+
+		self.reloadList()
+		self["config"].setList(self.list)
+
+	def reloadList(self):
+		self.list = [
+			getConfigListEntry(_("Enable Service Restriction"), self.enabled),
+			getConfigListEntry(_("Editing"), self.typeSelection)
+		]
+
+		if self.typeSelection.value == "channels":
+			self.idx = 0
+		else: # self.typeSelection.value == "bouquets":
+			self.idx = 1
+
+		self.list.extend([
+			getConfigListEntry(_("Record on"), NoSave(ConfigSelection(choices = [(str(x), ServiceReference(str(x)).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))])))
+				for x in self.services[self.idx]
+		])
+
+	def changed(self):
+		for x in self.onChangedEntry:
+			try:
+				x()
+			except Exception:
+				pass
+
+	def getCurrentEntry(self):
+		return self["config"].getCurrent()[0]
+
+	def getCurrentValue(self):
+		return str(self["config"].getCurrent()[1].getText())
+
+	def createSummary(self):
+		return SetupSummary
+
+	def remove(self):
+		if self["config"].getCurrentIndex() != 0:
+			list = self["config"].getList()
+			list.remove(self["config"].getCurrent())
+			self["config"].setList(list)
+
+	def new(self):
+		if self.typeSelection.value == "channels":
+			self.session.openWithCallback(
+				self.finishedServiceSelection,
+				SimpleChannelSelection,
+				_("Select channel to record on")
+			)
+		else: # self.typeSelection.value == "bouquets":
+			self.session.openWithCallback(
+				self.finishedServiceSelection,
+				SimpleBouquetSelection,
+				_("Select bouquet to record on")
+			)
+
+	def finishedServiceSelection(self, *args):
+		if args:
+			list = self["config"].getList()
+			sname = args[0].toString()
+
+			if self.typeSelection.value == "channels" and not (args[0].flags & eServiceReference.isGroup):
+				# strip all after last : when adding a (non alternative) channel
+				pos = sname.rfind(':')
+				if pos != -1:
+					sname = sname[:pos+1]
+
+			list.append(getConfigListEntry(_("Record on"), NoSave(ConfigSelection(choices = [(sname, ServiceReference(args[0]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))]))))
+			self["config"].setList(list)
+
+	def cancel(self):
+		if self["config"].isChanged():
+			self.session.openWithCallback(
+				self.cancelConfirm,
+				MessageBox,
+				_("Really close without saving settings?")
+			)
+		else:
+			self.close(None)
+
+	def cancelConfirm(self, ret):
+		if ret:
+			self.close(None)
+
+	def save(self):
+		self.refresh()
+
+		self.close((
+			self.enabled.value,
+			self.services
+		))
+
+def addAutotimerFromSearchString(session, match):
+	from AutoTimerComponent import AutoTimerComponent
+	from AutoTimerImporter import AutoTimerImporter
+	from plugin import autotimer
+
+	# Create instance if needed
+	if autotimer is None:
+		from AutoTimer import AutoTimer
+		autotimer = AutoTimer()
+		autotimer.readXml()
+
+	session.openWithCallback(
+		importerCallback,
+		AutoTimerImporter,
+		AutoTimerComponent(
+			autotimer.getUniqueId(),
+			match,
+			'',		# Match
+			True	# Enabled
+		),
+		match,		# Proposed Match
+		None,		# Proposed Begin
+		None,		# Proposed End
+		None,		# Proposed Disabled
+		None,		# Proposed ServiceReference
+		None,		# Proposed afterEvent
+		None,		# Proposed justplay
+		None,		# Proposed dirname, can we get anything useful here?
+		[]			# Proposed tags
+	)
+
+def addAutotimerFromEvent(session, evt = None, service = None):
+	from AutoTimerComponent import AutoTimerComponent
+	from AutoTimerImporter import AutoTimerImporter
+	from plugin import autotimer
+
+	# Create instance if needed
+	if autotimer is None:
+		from AutoTimer import AutoTimer
+		autotimer = AutoTimer()
+		autotimer.readXml()
+
+	match = evt and evt.getEventName() or ""
+	name = match or "New AutoTimer"
+	sref = None
+	if service is not None:
+		service = str(service)
+		myref = eServiceReference(service)
+		if not (myref.flags & eServiceReference.isGroup):
+			# strip all after last :
+			pos = service.rfind(':')
+			if pos != -1:
+				service = service[:pos+1]
+
+		sref = ServiceReference(myref)
+	if evt:
+		# timespan defaults to +- 1h
+		begin = evt.getBeginTime()-3600
+		end = begin + evt.getDuration()+7200
+	else:
+		begin = end = 0
+
+	# XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
+
+	session.openWithCallback(
+		importerCallback,
+		AutoTimerImporter,
+		AutoTimerComponent(
+			autotimer.getUniqueId(),
+			name,
+			'',		# Match
+			True	# Enabled
+		),
+		match,		# Proposed Match
+		begin,		# Proposed Begin
+		end,		# Proposed End
+		None,		# Proposed Disabled
+		sref,		# Proposed ServiceReference
+		None,		# Proposed afterEvent
+		None,		# Proposed justplay
+		None,		# Proposed dirname, can we get anything useful here?
+		[]			# Proposed tags
+	)
+
+def addAutotimerFromService(session, service = None):
+	from AutoTimerComponent import AutoTimerComponent
+	from AutoTimerImporter import AutoTimerImporter
+	from plugin import autotimer
+
+	# Create instance if needed
+	if autotimer is None:
+		from AutoTimer import AutoTimer
+		autotimer = AutoTimer()
+		autotimer.readXml()
+
+	serviceHandler = eServiceCenter.getInstance()
+	info = serviceHandler.info(service)
+
+	match = info and info.getName(service) or ""
+	name = match or "New AutoTimer"
+	sref = info and info.getInfoString(service, iServiceInformation.sServiceref)
+	if sref:
+		# strip all after last :
+		pos = sref.rfind(':')
+		if pos != -1:
+			sref = sref[:pos+1]
+
+		sref = ServiceReference(sref)
+	if info:
+		begin = info.getInfo(service, iServiceInformation.sTimeCreate)
+		end = begin + info.getLength(service)
+	else:
+		begin = end = 0
+
+	from os.path import dirname
+	path = dirname(service.getPath())
+	if not path == '/':
+		path += '/'
+
+	tags = info.getInfoString(service, iServiceInformation.sTags)
+	tags = tags and tags.split(' ') or []
+
+	# XXX: we might want to make sure that we actually collected any data because the importer does not do so :-)
+
+	session.openWithCallback(
+		importerCallback,
+		AutoTimerImporter,
+		AutoTimerComponent(
+			autotimer.getUniqueId(),
+			name,
+			'',		# Match
+			True	# Enabled
+		),
+		match,		# Proposed Match
+		begin,		# Proposed Begin
+		end,		# Proposed End
+		None,		# Proposed Disabled
+		sref,		# Proposed ServiceReference
+		None,		# Proposed afterEvent
+		None,		# Proposed justplay
+		path,		# Proposed dirname
+		tags		# Proposed tags
+	)
+
+def importerCallback(ret):
+	if ret:
+		ret, session = ret
+
+		session.openWithCallback(
+			editorCallback,
+			AutoTimerEditor,
+			ret
+		)
+	else:
+		# Remove instance if not running in background
+		if not config.plugins.autotimer.autopoll.value:
+			from plugin import autotimer
+			autotimer = None
+
+def editorCallback(ret):
+	if ret:
+		from plugin import autotimer
+
+		# Create instance if needed (should have been created by addAutotimerFrom* above though)
+		if autotimer is None:
+			from AutoTimer import AutoTimer
+			autotimer = AutoTimer()
+			autotimer.readXml()
+
+		autotimer.add(ret)
+
+		# Save modified xml
+		autotimer.writeXml()
+
+	# Remove instance if not running in background
+	if not config.plugins.autotimer.autopoll.value:
+		autotimer = None
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerImporter.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerImporter.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerImporter.py	(revision 5870)
@@ -0,0 +1,306 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Screens.InputBox import InputBox
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Button import Button
+from Components.TimerList import TimerList
+from Components.SelectionList import SelectionList, SelectionEntryComponent
+
+# Timer
+from RecordTimer import AFTEREVENT
+
+# Needed to convert our timestamp back and forth
+from time import localtime
+
+from enigma import eServiceReference
+
+afterevent = {
+	AFTEREVENT.NONE: _("do nothing"),
+	AFTEREVENT.DEEPSTANDBY: _("go to deep standby"),
+	AFTEREVENT.STANDBY: _("go to standby"),
+	AFTEREVENT.AUTO: _("auto")
+}
+
+class AutoTimerImportSelector(Screen):
+	def __init__(self, session, autotimer):
+		Screen.__init__(self, session)
+		self.skinName = "TimerEditList"
+
+		self.autotimer = autotimer
+
+		self.list = []
+		self.fillTimerList()
+
+		self["timerlist"] = TimerList(self.list)
+
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("OK"))
+		self["key_yellow"] = Button("")
+		self["key_blue"] = Button("")
+
+		self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
+		{
+			"ok": self.openImporter,
+			"cancel": self.cancel,
+			"green": self.openImporter,
+			"red": self.cancel
+		}, -1)
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Select a Timer to Import"))
+
+	def fillTimerList(self):
+		l = self.list
+		del l[:]
+
+		for timer in self.session.nav.RecordTimer.timer_list:
+			l.append((timer, False))
+
+		for timer in self.session.nav.RecordTimer.processed_timers:
+			l.append((timer, True))
+		l.sort(key = lambda x: x[0].begin)
+
+	def importerClosed(self, ret):
+		ret = ret and ret[0]
+		if ret is not None:
+			ret.name = ret.match
+		self.close(ret)
+
+	def openImporter(self):
+		cur=self["timerlist"].getCurrent()
+		if cur:
+			self.session.openWithCallback(
+				self.importerClosed,
+				AutoTimerImporter,
+				self.autotimer,
+				cur.name,
+				cur.begin,
+				cur.end,
+				cur.disabled,
+				cur.service_ref,
+				cur.afterEvent,
+				cur.justplay,
+				cur.dirname,
+				cur.tags
+			)
+
+	def cancel(self):
+		self.close(None)
+
+class AutoTimerImporter(Screen):
+	"""Import AutoTimer from Timer"""
+
+	skin = """<screen name="AutoTimerImporter" title="Import AutoTimer" position="center,center" size="565,280">
+		<widget name="list" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
+		<ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session, autotimer, name, begin, end, disabled, sref, afterEvent, justplay, dirname, tags):
+		Screen.__init__(self, session)
+
+		# Keep AutoTimer
+		self.autotimer = autotimer
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("OK"))
+		self["key_yellow"] = Button()
+ 		self["key_blue"] = Button()
+
+		list = []
+
+		if disabled is not None:
+			list.append(
+				SelectionEntryComponent(
+					': '.join((_("Enabled"), {True: _("disable"), False: _("enable")}[bool(disabled)])),
+					not disabled,
+					0,
+					True
+			))
+
+		if name != "":
+			list.extend([
+				SelectionEntryComponent(
+					_("Match title: %s") % (name),
+					name,
+					1,
+					True
+				),
+				SelectionEntryComponent(
+					_("Exact match"),
+					True,
+					8,
+					True
+				)
+			])
+
+		if begin and end:
+			begin = localtime(begin)
+			end = localtime(end)
+			list.append(
+				SelectionEntryComponent(
+					_("Match Timespan: %02d:%02d - %02d:%02d") % (begin[3], begin[4], end[3], end[4]),
+					((begin[3], begin[4]), (end[3], end[4])),
+					2,
+					True
+			))
+
+		if sref:
+			list.append(
+				SelectionEntryComponent(
+					_("Only on Service: %s") % (sref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')),
+					str(sref),
+					3,
+					True
+			))
+
+		if afterEvent is not None:
+			list.append(
+				SelectionEntryComponent(
+					': '.join((_("After event"), afterevent[afterEvent])),
+					afterEvent,
+					4,
+					True
+			))
+
+		if justplay is not None:
+			list.append(
+				SelectionEntryComponent(
+					': '.join((_("Timer Type"), {0: _("record"), 1: _("zap")}[int(justplay)])),
+					int(justplay),
+					5,
+					True
+			))
+
+		if dirname is not None:
+			list.append(
+				SelectionEntryComponent(
+					': '.join((_("Location"), dirname or "/hdd/movie/")),
+					dirname,
+					6,
+					True
+			))
+
+		if tags:
+			list.append(
+				SelectionEntryComponent(
+					': '.join((_("Tags"), ', '.join(tags))),
+					tags,
+					7,
+					True
+			))
+
+		self["list"] = SelectionList(list)
+
+		# Define Actions
+		self["actions"] = ActionMap(["OkCancelActions", "ColorActions"],
+		{
+			"ok": self["list"].toggleSelection,
+			"cancel": self.cancel,
+			"red": self.cancel,
+			"green": self.accept
+		}, -1)
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Import AutoTimer"))
+
+	def cancel(self):
+		self.session.openWithCallback(
+			self.cancelConfirm,
+			MessageBox,
+			_("Really close without saving settings?")
+		)
+
+	def cancelConfirm(self, ret):
+		if ret:
+			self.close(None)
+
+	def gotCustomMatch(self, ret):
+		if ret:
+			self.autotimer.match = ret
+			# Check if we have a trailing whitespace
+			if ret[-1:] == " ":
+				self.session.openWithCallback(
+					self.trailingWhitespaceRemoval,
+					MessageBox,
+					_('You entered "%s" as Text to match.\nDo you want to remove trailing whitespaces?') % (ret)
+				)
+			# Just confirm else
+			else:
+				self.close((
+				self.autotimer,
+				self.session
+			))
+
+	def trailingWhitespaceRemoval(self, ret):
+		if ret is not None:
+			if ret:
+				self.autotimer.match = self.autotimer.match.rstrip()
+			self.close((
+				self.autotimer,
+				self.session
+			))
+
+	def accept(self):
+		list = self["list"].getSelectionsList()
+		autotimer = self.autotimer
+
+		for item in list:
+			if item[2] == 0: # Enable
+				autotimer.enabled = item[1]
+			elif item[2] == 1: # Match
+				autotimer.match = item[1]
+			elif item[2] == 2: # Timespan
+				autotimer.timespan = item[1]
+			elif item[2] == 3: # Service
+				value = item[1]
+
+				myref = eServiceReference(value)
+				if not (myref.flags & eServiceReference.isGroup):
+					# strip all after last :
+					pos = value.rfind(':')
+					if pos != -1:
+						value = value[:pos+1]
+
+				autotimer.services = [value]
+			elif item[2] == 4: # AfterEvent
+				autotimer.afterevent = [(item[1], None)]
+			elif item[2] == 5: # Justplay
+				autotimer.justplay = item[1]
+			elif item[2] == 6: # Location
+				autotimer.destination = item[1]
+			elif item[2] == 7: # Tags
+				autotimer.tags = item[1]
+			elif item[2] == 8: # Exact match
+				autotimer.searchType = "exact"
+				autotimer.searchCase = "sensitive"
+
+		if autotimer.match == "":
+			self.session.openWithCallback(
+					self.gotCustomMatch,
+					InputBox,
+					title = _("Please provide a Text to match")
+			)
+		else:
+			self.close((
+				autotimer,
+				self.session
+			))
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerList.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerList.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerList.py	(revision 5870)
@@ -0,0 +1,66 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
+# GUI (Components)
+from Components.MenuList import MenuList
+from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT
+
+from skin import parseColor, parseFont
+
+class AutoTimerList(MenuList):
+	"""Defines a simple Component to show Timer name"""
+
+	def __init__(self, entries):
+		MenuList.__init__(self, entries, False, content = eListboxPythonMultiContent)
+
+		self.l.setFont(0, gFont("Regular", 22))
+		self.l.setBuildFunc(self.buildListboxEntry)
+		self.l.setItemHeight(25)
+		self.colorDisabled = 12368828
+
+	def applySkin(self, desktop, parent):
+		attribs = [ ] 
+		if self.skinAttributes is not None:
+			for (attrib, value) in self.skinAttributes:
+				if attrib == "font":
+					self.l.setFont(0, parseFont(value, ((1,1),(1,1))))
+				elif attrib == "itemHeight":
+					self.l.setItemHeight(int(value))
+				elif attrib == "colorDisabled":
+					self.colorDisabled = int(parseColor(value))
+				else:
+					attribs.append((attrib, value))
+		self.skinAttributes = attribs
+		return MenuList.applySkin(self, desktop, parent)
+
+	#
+	#  | <Name of AutoTimer> |
+	#
+	def buildListboxEntry(self, timer):
+		size = self.l.getItemSize()
+
+		color = None
+		if not timer.enabled:
+			color = self.colorDisabled
+
+		return [
+			None,
+			(eListboxPythonMultiContent.TYPE_TEXT, 5, 0, size.width() - 5, size.height(), 0, RT_HALIGN_LEFT, timer.name, color, color)
+		]
+
+	def getCurrent(self):
+		cur = self.l.getCurrentSelection()
+		return cur and cur[0]
+
+	def moveToEntry(self, entry):
+		if entry is None:
+			return
+
+		idx = 0
+		for x in self.list:
+			if x[0] == entry:
+				self.instance.moveSelectionTo(idx)
+				break
+			idx += 1
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerOverview.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerOverview.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerOverview.py	(revision 5870)
@@ -0,0 +1,243 @@
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Screens.HelpMenu import HelpableScreen
+from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+from AutoTimerEditor import AutoTimerEditor, AutoTimerChannelSelection
+from AutoTimerSettings import AutoTimerSettings
+from AutoTimerPreview import AutoTimerPreview
+from AutoTimerImporter import AutoTimerImportSelector
+from AutoTimerWizard import AutoTimerWizard
+
+# GUI (Components)
+from AutoTimerList import AutoTimerList
+from Components.ActionMap import HelpableActionMap
+from Components.Button import Button
+from Components.config import config
+
+# Plugin
+from AutoTimerComponent import AutoTimerComponent
+
+class AutoTimerOverview(Screen, HelpableScreen):
+	"""Overview of AutoTimers"""
+
+	skin = """<screen name="AutoTimerOverview" position="center,center" size="460,265" title="AutoTimer Overview">
+			<widget name="entries" position="5,5" size="450,200" scrollbarMode="showOnDemand" />
+			<ePixmap position="0,220" zPosition="1" size="140,40" pixmap="skin_default/buttons/green.png" alphatest="on" />
+			<ePixmap position="140,220" zPosition="1" size="140,40" pixmap="skin_default/buttons/yellow.png" alphatest="on" />
+			<ePixmap position="280,220" zPosition="1" size="140,40" pixmap="skin_default/buttons/blue.png" alphatest="on" />
+			<ePixmap position="422,230" zPosition="1" size="35,25" pixmap="skin_default/buttons/key_menu.png" alphatest="on" />
+			<widget name="key_green" position="0,220" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;21" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+			<widget name="key_yellow" position="140,220" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;21" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+			<widget name="key_blue" position="280,220" zPosition="2" size="140,40" halign="center" valign="center" font="Regular;21" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
+		</screen>"""
+
+	def __init__(self, session, autotimer):
+		Screen.__init__(self, session)
+		HelpableScreen.__init__(self)
+
+		# Save autotimer
+		self.autotimer = autotimer
+
+		self.changed = False
+
+		# Button Labels
+		self["key_green"] = Button(_("Save"))
+		self["key_yellow"] = Button(_("Delete"))
+		self["key_blue"] = Button(_("Add"))
+
+		# Create List of Timers
+		self["entries"] = AutoTimerList(autotimer.getSortedTupleTimerList())
+
+		# Define Actions
+		self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
+			{
+				"ok": (self.ok, _("Edit selected AutoTimer")),
+				"cancel": (self.cancel, _("Close and forget changes")),
+			}
+		)
+
+		self["MenuActions"] = HelpableActionMap(self, "MenuActions",
+			{
+				"menu": (self.menu, _("Open Context Menu"))
+			}
+		)
+
+		self["ColorActions"] = HelpableActionMap(self, "ColorActions",
+			{
+				"green": (self.save, _("Close and save changes")),
+				"yellow": (self.remove, _("Remove selected AutoTimer")),
+				"blue": (self.add, _("Add new AutoTimer")),
+			}
+		)
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("AutoTimer Overview"))
+
+	def add(self):
+		newTimer = self.autotimer.defaultTimer.clone()
+		newTimer.id = self.autotimer.getUniqueId()
+
+		if config.plugins.autotimer.editor.value == "wizard":
+			self.session.openWithCallback(
+				self.addCallback,
+				AutoTimerWizard,
+				newTimer
+			)
+		else:
+			self.session.openWithCallback(
+				self.addCallback,
+				AutoTimerEditor,
+				newTimer
+			)
+
+	def editCallback(self, ret):
+		if ret:
+			self.changed = True
+			self.refresh()
+
+	def addCallback(self, ret):
+		if ret:
+			self.changed = True
+			self.autotimer.add(ret)
+			self.refresh()
+
+	def importCallback(self, ret):
+		if ret:
+			self.session.openWithCallback(
+				self.addCallback,
+				AutoTimerEditor,
+				ret
+			)
+
+	def refresh(self, res = None):
+		# Re-assign List
+		cur = self["entries"].getCurrent()
+		self["entries"].setList(self.autotimer.getSortedTupleTimerList())
+		self["entries"].moveToEntry(cur)
+
+	def ok(self):
+		# Edit selected Timer
+		current = self["entries"].getCurrent()
+		if current is not None:
+			self.session.openWithCallback(
+				self.editCallback,
+				AutoTimerEditor,
+				current
+			)
+
+	def remove(self):
+		# Remove selected Timer
+		cur = self["entries"].getCurrent()
+		if cur is not None:
+			self.session.openWithCallback(
+				self.removeCallback,
+				MessageBox,
+				_("Do you really want to delete %s?") % (cur.name),
+			)
+
+	def removeCallback(self, ret):
+		cur = self["entries"].getCurrent()
+		if ret and cur:
+			self.autotimer.remove(cur.id)
+			self.refresh()
+
+	def cancel(self):
+		if self.changed:
+			self.session.openWithCallback(
+				self.cancelConfirm,
+				MessageBox,
+				_("Really close without saving settings?")
+			)
+		else:
+			self.close(None)
+
+	def cancelConfirm(self, ret):
+		if ret:
+			# Invalidate config mtime to force re-read on next run
+			self.autotimer.configMtime = -1
+
+			# Close and indicated that we canceled by returning None
+			self.close(None)
+
+	def menu(self):
+		list = [
+			(_("Preview"), "preview"),
+			(_("Import existing Timer"), "import"),
+			(_("Import from EPG"), "import_epg"),
+			(_("Setup"), "setup"),
+			(_("Edit new timer defaults"), "defaults"),
+		]
+
+		if config.plugins.autotimer.editor.value == "wizard":
+			list.append((_("Create a new timer using the classic editor"), "newplain"))
+		else:
+			list.append((_("Create a new timer using the wizard"), "newwizard"))
+
+		self.session.openWithCallback(
+			self.menuCallback,
+			ChoiceBox,
+			list = list,
+		)
+
+	def menuCallback(self, ret):
+		ret = ret and ret[1]
+		if ret:
+			if ret == "preview":
+				total, new, modified, timers = self.autotimer.parseEPG(simulateOnly = True)
+				self.session.open(
+					AutoTimerPreview,
+					timers
+				)
+			elif ret == "import":
+				newTimer = self.autotimer.defaultTimer.clone()
+				newTimer.id = self.autotimer.getUniqueId()
+
+				self.session.openWithCallback(
+					self.importCallback,
+					AutoTimerImportSelector,
+					newTimer
+				)
+			elif ret == "import_epg":
+				self.session.open(
+					AutoTimerChannelSelection,
+					self.autotimer
+				)
+			elif ret == "setup":
+				self.session.open(
+					AutoTimerSettings
+				)
+			elif ret == "defaults":
+				self.session.open(
+					AutoTimerEditor,
+					self.autotimer.defaultTimer,
+					editingDefaults = True
+				)
+			elif ret == "newwizard":
+				newTimer = self.autotimer.defaultTimer.clone()
+				newTimer.id = self.autotimer.getUniqueId()
+
+				self.session.openWithCallback(
+					self.addCallback, # XXX: we could also use importCallback... dunno what seems more natural
+					AutoTimerWizard,
+					newTimer
+				)
+			elif ret == "newplain":
+				newTimer = self.autotimer.defaultTimer.clone()
+				newTimer.id = self.autotimer.getUniqueId()
+
+				self.session.openWithCallback(
+					self.addCallback,
+					AutoTimerEditor,
+					newTimer
+				)
+
+	def save(self):
+		# Just close here, saving will be done by cb
+		self.close(self.session)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerPreview.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerPreview.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerPreview.py	(revision 5870)
@@ -0,0 +1,106 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Button import Button
+from Components.Sources.List import List
+
+from ServiceReference import ServiceReference
+from Tools.FuzzyDate import FuzzyTime
+
+class AutoTimerPreview(Screen):
+	"""Preview Timers which would be set"""
+
+	skin = """<screen name="AutoTimerPreview" title="Preview AutoTimer" position="center,center" size="565,265">
+		<widget source="timerlist" render="Listbox" position="5,5" size="555,210" scrollbarMode="showOnDemand">
+			<convert type="TemplatedMultiContent">
+				{"template": [
+						MultiContentEntryText(pos=(2,2), size=(550,24), text = 3, font = 0, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER),
+						MultiContentEntryText(pos=(2,26), size=(555,30), text = 0, font = 1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER),
+						MultiContentEntryText(pos=(2,50), size=(400,20), text = 4, font = 1, flags = RT_HALIGN_LEFT|RT_VALIGN_CENTER),
+						MultiContentEntryText(pos=(290,50), size=(233,20), text = 2, font = 1, flags = RT_HALIGN_RIGHT|RT_VALIGN_CENTER),
+					],
+				 "fonts": [gFont("Regular", 20),gFont("Regular", 18)],
+				 "itemHeight": 72
+				}
+			</convert>
+		</widget>
+		<ePixmap position="0,220" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="280,220" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="0,220" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="280,220" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session, timers):
+		Screen.__init__(self, session)
+
+		# Sort timers by begin
+		timers.sort(key = lambda x: x[1])
+		self.sort_type = 0
+
+		# name, begin, end, serviceref, timername -> name, begin, timername, sname, timestr
+		self.timers = [
+			(x[0], x[1], x[4],
+			ServiceReference(x[3]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '').encode('utf-8', 'ignore'),
+			(("%s, %s ... %s (%d " + _("mins") + ")") % (FuzzyTime(x[1]) + FuzzyTime(x[2])[1:] + ((x[2] - x[1]) / 60,))))
+			for x in timers
+		]
+
+		self["timerlist"] = List(self.timers)
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_yellow"] = Button()
+
+		self.setSortDescription()
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+			{
+				"cancel": self.cancel,
+				"save": self.save,
+				"yellow": self.sort
+			}
+		)
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Preview AutoTimer"))
+
+	def setSortDescription(self):
+		if self.sort_type == 1:
+			self["key_yellow"].setText(_("Sort Time"))
+		else:
+			self["key_yellow"].setText(_("Sort AutoTimer"))
+
+	def sort(self):
+		timers = self.timers
+		if timers:
+			current = self["timerlist"].current
+			idx = 0
+			for timer in timers:
+				if timer == current:
+					break
+				idx += 1
+			if self.sort_type == 1:
+				timers.sort(key=lambda x: x[1])
+				self.sort_type = 0
+			else:
+				timers.sort(key = lambda x: x[4].lower())
+				self.sort_type = 1
+			self["timerlist"].updateList(timers)
+			self["timerlist"].index = idx
+			self.setSortDescription()
+
+	def cancel(self):
+		self.close(None)
+
+	def save(self):
+		self.close(True)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerResource.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerResource.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerResource.py	(revision 5870)
@@ -0,0 +1,27 @@
+from twisted.web2 import resource, responsecode, http
+from AutoTimer import AutoTimer
+from . import _
+
+# pretty basic resource which is just present to have a way to start a
+# forced run through the webif
+class AutoTimerResource(resource.Resource):
+	def __init__(self):
+		resource.Resource.__init__(self)
+
+	def render(self, req):
+		from plugin import autotimer
+		remove = False
+		if autotimer is None:
+			autotimer = AutoTimer()
+			remove = True
+
+		if req.args.has_key("parse"):
+			ret = autotimer.parseEPG()
+			output = _("Found a total of %d matching Events.\n%d Timer were added and %d modified.") % (ret[0], ret[1], ret[2])
+		else:
+			output = "unknown command"
+
+		if remove:
+			autotimer = None
+		return http.Response(responsecode.OK ,stream = output)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerSettings.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerSettings.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerSettings.py	(revision 5870)
@@ -0,0 +1,79 @@
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Components.ConfigList import ConfigListScreen
+
+# GUI (Summary)
+from Screens.Setup import SetupSummary
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.Sources.StaticText import StaticText
+from Components.Pixmap import Pixmap
+
+# Configuration
+from Components.config import config, getConfigListEntry
+
+class AutoTimerSettings(Screen, ConfigListScreen):
+	def __init__(self, session):
+		Screen.__init__(self, session)
+		self.skinName = "Setup"
+
+		# Summary
+		self.setup_title = _("AutoTimer Settings")
+		self.onChangedEntry = []
+
+		ConfigListScreen.__init__(
+			self,
+			[
+				getConfigListEntry(_("Poll automatically"), config.plugins.autotimer.autopoll),
+				getConfigListEntry(_("Poll Interval (in h)"), config.plugins.autotimer.interval),
+				getConfigListEntry(_("Show in Extensionmenu"), config.plugins.autotimer.show_in_extensionsmenu),
+				getConfigListEntry(_("Modify existing Timers"), config.plugins.autotimer.refresh),
+				getConfigListEntry(_("Guess existing Timer based on Begin/End"), config.plugins.autotimer.try_guessing),
+				getConfigListEntry(_("Add timer as disabled on conflict"), config.plugins.autotimer.disabled_on_conflict),
+				getConfigListEntry(_("Editor for new AutoTimers"), config.plugins.autotimer.editor),
+			],
+			session = session,
+			on_change = self.changed
+		)
+
+		# Initialize widgets
+		self["key_green"] = StaticText(_("OK"))
+		self["key_red"] = StaticText(_("Cancel"))
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions"],
+			{
+				"cancel": self.keyCancel,
+				"save": self.keySave,
+			}
+		)
+
+		# Trigger change
+		self.changed()
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Configure AutoTimer behavior"))
+
+	def changed(self):
+		for x in self.onChangedEntry:
+			try:
+				x()
+			except Exception:
+				pass
+
+	def getCurrentEntry(self):
+		return self["config"].getCurrent()[0]
+
+	def getCurrentValue(self):
+		return str(self["config"].getCurrent()[1].getText())
+
+	def createSummary(self):
+		return SetupSummary
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerWizard.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerWizard.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/AutoTimerWizard.py	(revision 5870)
@@ -0,0 +1,175 @@
+# l10n
+from . import _
+
+# GUI (Screens)
+from Screens.WizardLanguage import WizardLanguage
+from Screens.Rc import Rc
+from AutoTimerEditor import AutoTimerEditorBase, AutoTimerServiceEditor, \
+		AutoTimerFilterEditor
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Pixmap import Pixmap
+
+# Configuration
+from Components.config import getConfigListEntry, KEY_0, KEY_DELETE, \
+		KEY_BACKSPACE
+
+# Wizard XML Path
+from Tools import Directories
+
+class AutoTimerWizard(WizardLanguage, AutoTimerEditorBase, Rc):
+	STEP_ID_BASIC = 2
+	STEP_ID_TIMESPAN = 5
+	STEP_ID_SERVICES = 7
+	STEP_ID_FILTER = 8
+
+	def __init__(self, session, newTimer):
+		self.xmlfile = Directories.resolveFilename(Directories.SCOPE_PLUGINS, "Extensions/AutoTimer/autotimerwizard.xml")
+
+		WizardLanguage.__init__(self, session, showSteps = True, showStepSlider = True)
+		AutoTimerEditorBase.__init__(self, newTimer)
+		Rc.__init__(self)
+
+		self.skinName = "StartWizard"
+		self["wizard"] = Pixmap()
+
+		self.doCancel = False
+		self.emptyMatch = False
+		self.tailingWhitespacesMatch = False
+
+		# We might need to change shown items, so add some notifiers
+		self.timespan.addNotifier(self.regenTimespanList, initial_call = False)
+		self.generateTimespanList()
+
+		self.servicesDlg = self.session.instantiateDialog(
+				AutoTimerServiceEditor,
+				self.serviceRestriction, self.services, self.bouquets
+		)
+
+		self.filterDlg = self.session.instantiateDialog(
+				AutoTimerFilterEditor,
+				self.filterSet, self.excludes, self.includes
+		)
+
+		self["TextEntryActions"] = ActionMap(["TextEntryActions"],
+			{
+				"deleteForward": self.deleteForward,
+				"deleteBackward": self.deleteBackward
+			}, -2
+		)
+
+	def getTranslation(self, text):
+		return _(text)
+
+	def regenTimespanList(self, *args, **kwargs):
+		self.generateTimespanList()
+		if self.currStep == AutoTimerWizard.STEP_ID_TIMESPAN:
+			self["config"].setList(self.timespanList)
+
+	def generateTimespanList(self):
+		self.timespanList = [
+			getConfigListEntry(_("Only match during Timespan"), self.timespan)
+		]
+
+		# Only allow editing timespan when it's enabled
+		if self.timespan.value:
+			self.timespanList.extend([
+				getConfigListEntry(_("Begin of Timespan"), self.timespanbegin),
+				getConfigListEntry(_("End of Timespan"), self.timespanend)
+			])
+
+	def getConfigList(self):
+		if self.currStep == AutoTimerWizard.STEP_ID_BASIC: # Basic
+			return [
+				getConfigListEntry(_("Enabled"), self.enabled),
+				getConfigListEntry(_("Description"), self.name),
+				getConfigListEntry(_("Match Title"), self.match),
+				getConfigListEntry(_("Timer Type"), self.justplay),
+			]
+		elif self.currStep == AutoTimerWizard.STEP_ID_TIMESPAN: # Timespan
+			return self.timespanList
+		elif self.currStep == AutoTimerWizard.STEP_ID_SERVICES: # Services
+			return self.servicesDlg["config"].getList()
+		elif self.currStep == AutoTimerWizard.STEP_ID_FILTER: # Filters
+			return self.filterDlg["config"].getList()
+		return []
+
+	def selectionMade(self):
+		timer = self.timer
+		if self.currStep == AutoTimerWizard.STEP_ID_BASIC: # Basic
+			timer.enabled = self.enabled.value
+			timer.name = self.name.value.strip() or self.match.value
+			timer.match = self.match.value
+			timer.justplay = self.justplay.value == "zap"
+			self.emptyMatch = not timer.match.strip()
+			self.trailingWhitespacesMatch = (timer.match[-1:] == " ")
+		elif self.currStep == AutoTimerWizard.STEP_ID_TIMESPAN: # Timespan
+			if self.timespan.value:
+				start = self.timespanbegin.value
+				end = self.timespanend.value
+				timer.timespan = (start, end)
+			else:
+				timer.timespan = None
+		elif self.currStep == AutoTimerWizard.STEP_ID_SERVICES: # Services
+			self.servicesDlg.refresh()
+
+			if self.servicesDlg.enabled.value:
+				timer.services = self.servicesDlg.services[0]
+				timer.bouquets = self.servicesDlg.services[1]
+			else:
+				timer.services = []
+				timer.bouquets = []
+		elif self.currStep == AutoTimerWizard.STEP_ID_FILTER: # Filters
+			self.filterDlg.refresh()
+
+			if self.filterDlg.enabled.value:
+				timer.includes = self.filterDlg.includes
+				timer.excludes = self.filterDlg.excludes
+			else:
+				timer.includes = []
+				timer.excludes = []
+
+	def keyNumberGlobal(self, number):
+		if self.currStep == AutoTimerWizard.STEP_ID_BASIC or self.currStep == AutoTimerWizard.STEP_ID_TIMESPAN:
+			self["config"].handleKey(KEY_0 + number)
+		else:
+			WizardLanguage.keyNumberGlobal(self, number)
+
+	def blue(self):
+		if self.currStep == AutoTimerWizard.STEP_ID_SERVICES:
+			self.servicesDlg.new()
+		elif self.currStep == AutoTimerWizard.STEP_ID_FILTER:
+			self.filterDlg.new()
+
+	def yellow(self):
+		if self.currStep == AutoTimerWizard.STEP_ID_SERVICES:
+			self.servicesDlg.remove()
+		elif self.currStep == AutoTimerWizard.STEP_ID_FILTER:
+			self.filterDlg.remove()
+
+	def maybeRemoveWhitespaces(self):
+		# XXX: Hack alert
+		if self["list"].current[1] == "removeTrailingWhitespaces":
+			print "Next step would be to remove trailing whitespaces, removing them and redirecting to 'conf2'"
+			self.timer.match = self.timer.match.rstrip()
+			self.match.value = self.match.value.rstrip()
+			self.currStep = self.getStepWithID("conf2")
+		self.trailingWhitespacesMatch = False
+
+	def deleteForward(self):
+		self["config"].handleKey(KEY_DELETE)
+
+	def deleteBackward(self):
+		self["config"].handleKey(KEY_BACKSPACE)
+
+	def cancel(self):
+		self.doCancel = True
+		self.currStep = len(self.wizard)
+
+	def close(self, *args, **kwargs):
+		if self.doCancel:
+			WizardLanguage.close(self, None)
+		else:
+			WizardLanguage.close(self, self.timer)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/LICENSE
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/LICENSE	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/LICENSE	(revision 5870)
@@ -0,0 +1,12 @@
+All Files of this Software are licensed under the Creative Commons 
+Attribution-NonCommercial-ShareAlike 3.0 Unported 
+License if not stated otherwise in a Files Head. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+
+Alternatively, this plugin may be distributed and executed on hardware which
+is licensed by Dream Multimedia GmbH.
+
+This plugin is NOT free software. It is open source, you are allowed to
+modify it (if you keep the license), but it may not be commercially 
+distributed other than under the conditions noted above.
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/__init__.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/__init__.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/__init__.py	(revision 5870)
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
+from os import environ as os_environ
+import gettext
+
+def localeInit():
+	lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
+	os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
+	gettext.bindtextdomain("AutoTimer", resolveFilename(SCOPE_PLUGINS, "Extensions/AutoTimer/locale"))
+
+def _(txt):
+	t = gettext.dgettext("AutoTimer", txt)
+	if t == txt:
+		print "[AutoTimer] fallback to default translation for", txt
+		t = gettext.gettext(txt)
+	return t
+
+localeInit()
+language.addCallback(localeInit)
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/autotimerwizard.xml
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/autotimerwizard.xml	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/autotimerwizard.xml	(revision 5870)
@@ -0,0 +1,151 @@
+<wizard>
+		<step id="welcome">
+			<text value="Welcome.\n\nThis Wizard will help you to create a new AutoTimer by providing descriptions for common settings." />
+			<list>
+				<listentry caption="Create a new AutoTimer." step="conf1" />
+				<listentry caption="Abort this Wizard." step="abort" />
+			</list>
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+		</step>
+
+		<!-- Name / Match / Enabled / Justplay -->
+		<step id="conf1" nextstep="conf2">
+			<text value="You can set the basic properties of an AutoTimer here.\nWhile 'Name' is just a human-readable name displayed in the Overview, 'Match in title' is what is looked for in the EPG." />
+			<config type="dynamic" source="getConfigList" evaluation="selectionMade" />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+			<!-- A sanity check is done in selectionMade combined with some helper versions of conf2 -->
+		</step>
+
+		<!-- Sanity check basic properties
+			They ruin the wizards history for now but better than nothing :D -->
+		<step id="conf2" nextstep="conf1">
+			<condition>
+self.condition = self.emptyMatch
+			</condition>
+			<text value="You did not provide a valid 'Match in title' Attribute for your new AutoTimer.\nAs this is a mandatory Attribute you cannot continue without doing so." />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+		</step>
+
+		<step id="conf2">
+			<condition>
+self.condition = self.trailingWhitespacesMatch
+			</condition>
+			<text value="Your 'Match in title' Attribute ends with a Whitespace.\nPlease confirm if this was intentional, if not they will be removed." />
+			<list>
+				<listentry caption="Yes, keep them." step="conf2" />
+				<listentry caption="No, remove them." step="removeTrailingWhitespaces" />
+			</list>
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+			<code pos="after">
+self.maybeRemoveWhitespaces()
+			</code>
+		</step>
+
+		<!-- Timespan -->
+		<step id="conf2" nextstep="conf4">
+			<condition>
+self.condition = not self.emptyMatch and not self.trailingWhitespacesMatch
+			</condition>
+			<text value="The Timespan of an AutoTimer is the first 'advanced' attribute. If a timespan is specified an event will only match this AutoTimer if it lies inside of this timespan." />
+			<config type="dynamic" source="getConfigList" evaluation="selectionMade" />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+			</code>
+		</step>
+
+		<!-- Offset / AfterEvent / Match --> <!-- CURRENTLY INACTIVE -->
+		<step id="conf3" nextstep="conf4">
+			<text value="" />
+			<config type="dynamic" source="getConfigList" evaluation="selectionMade" />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+		</step>
+
+		<!-- Services/Bouquets -->
+		<step id="conf4" nextstep="conf5">
+			<text value="It's possible to restrict an AutoTimer to certain Services or Bouquets or to deny specific ones.\nAn Event will only match this AutoTimer if it's on a specific and not denied Service (inside a Bouquet).\nPress BLUE to add a new restriction and YELLOW to remove the selected one." />
+			<config type="dynamic" source="getConfigList" evaluation="selectionMade" />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+self.selectKey("BLUE")
+self.selectKey("YELLOW")
+			</code>
+		</step>
+
+		<!-- Include / Exclude -->
+		<step id="conf5" nextstep="justbeforeend">
+			<text value="Filters are another powerful tool when matching events. An AutoTimer can be restricted to certain Weekdays or only match an event with a text inside eg it's Description.\nPress BLUE to add a new restriction and YELLOW to remove the selected one." />
+			<config type="dynamic" source="getConfigList" evaluation="selectionMade" />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("LEFT")
+self.selectKey("RIGHT")
+self.selectKey("BLUE")
+self.selectKey("YELLOW")
+			</code>
+		</step>
+
+		<!-- Maxduration / avoidDuplicate / Destination ?! -->
+		<!--
+		<step id="conf6" nextstep="end">
+			<text value="" />
+			<config type="dynamic" source="getConfigList" evaluation="selectionMade" />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+		</step>
+		-->
+
+		<step id="justbeforeend">
+			<text value="You successfully configured a new AutoTimer. Do you want to add it to the list?\n\nYou can go back a step by pressing EXIT on your remote." />
+			<list>
+				<listentry caption="Yes" step="end" />
+				<listentry caption="No" step="abort" />
+			</list>
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+self.selectKey("EXIT")
+			</code>
+		</step>
+
+		<step id="abort">
+			<text value="The Timer will not be added to the List.\nPlease press OK to close this Wizard." />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+			<code pos="after">
+self.cancel()
+			</code>
+		</step>
+
+		<step id="end">
+			<text value="Thank you for using the wizard. Your new AutoTimer has been added to the List.\nPlease press OK to continue." />
+			<code>
+self.clearSelectedKeys()
+self.selectKey("OK")
+			</code>
+		</step>
+</wizard>
+
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/maintainer.info
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/maintainer.info	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+moritz.venn@freaque.net
+AutoTimer
Index: /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/plugin.py
===================================================================
--- /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/plugin.py	(revision 5870)
+++ /ipk/source/swapepg_autotimer_1_0/var/swap/extensions/AutoTimer/plugin.py	(revision 5870)
@@ -0,0 +1,170 @@
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.MessageBox import MessageBox
+
+# Config
+from Components.config import config, ConfigSubsection, ConfigEnableDisable, \
+	ConfigNumber, ConfigSelection, ConfigYesNo
+
+# Plugin
+from Components.PluginComponent import plugins
+from Plugins.Plugin import PluginDescriptor
+
+# Initialize Configuration
+config.plugins.autotimer = ConfigSubsection()
+config.plugins.autotimer.autopoll = ConfigEnableDisable(default = False)
+config.plugins.autotimer.interval = ConfigNumber(default = 3)
+config.plugins.autotimer.refresh = ConfigSelection(choices = [
+		("none", _("None")),
+		("auto", _("Only AutoTimers created during this Session")),
+		("all", _("All non-repeating Timers"))
+	], default = "none"
+)
+config.plugins.autotimer.try_guessing = ConfigEnableDisable(default = True)
+config.plugins.autotimer.editor = ConfigSelection(choices = [
+		("plain", _("Classic")),
+		("wizard", _("Wizard"))
+	], default = "wizard"
+)
+config.plugins.autotimer.disabled_on_conflict = ConfigEnableDisable(default = False)
+config.plugins.autotimer.show_in_extensionsmenu = ConfigYesNo(default = False)
+
+autotimer = None
+autopoller = None
+
+# Autostart
+def autostart(reason, **kwargs):
+	global autotimer
+	global autopoller
+
+	# Startup
+	if config.plugins.autotimer.autopoll.value and reason == 0:
+		# Initialize AutoTimer
+		from AutoTimer import AutoTimer
+		autotimer = AutoTimer()
+
+		# Start Poller
+		from AutoPoller import AutoPoller
+		autopoller = AutoPoller()
+		autopoller.start()
+	# Shutdown
+	elif reason == 1:
+		# Stop Poller
+		if autopoller is not None:
+			autopoller.stop()
+			autopoller = None
+
+		if autotimer is not None:
+			# We re-read the config so we won't save wrong information
+			try:
+				autotimer.readXml()
+			except:
+				# XXX: we should at least dump the error
+				pass
+
+			# Save xml
+			autotimer.writeXml()
+
+			# Remove AutoTimer
+			autotimer = None
+
+# Mainfunction
+def main(session, **kwargs):
+	global autotimer
+	global autopoller
+
+	if autotimer is None:
+		from AutoTimer import AutoTimer
+		autotimer = AutoTimer()
+
+	try:
+		autotimer.readXml()
+	except SyntaxError, se:
+		session.open(
+			MessageBox,
+			_("Your config file is not well-formed:\n%s") % (str(se)),
+			type = MessageBox.TYPE_ERROR,
+			timeout = 10
+		)
+		return
+
+	# Do not run in background while editing, this might screw things up
+	if autopoller is not None:
+		autopoller.stop()
+
+	from AutoTimerOverview import AutoTimerOverview
+	session.openWithCallback(
+		editCallback,
+		AutoTimerOverview,
+		autotimer
+	)
+
+def editCallback(session):
+	global autotimer
+	global autopoller
+
+	# XXX: canceling of GUI (Overview) won't affect config values which might have been changed - is this intended?
+
+	# Don't parse EPG if editing was canceled
+	if session is not None:
+		# Poll EPGCache
+		ret = autotimer.parseEPG()
+		session.open(
+			MessageBox,
+			_("Found a total of %d matching Events.\n%d Timer were added and %d modified.") % (ret[0], ret[1], ret[2]),
+			type = MessageBox.TYPE_INFO,
+			timeout = 10
+		)
+
+		# Save xml
+		autotimer.writeXml()
+
+	# Start autopoller again if wanted
+	if config.plugins.autotimer.autopoll.value:
+		if autopoller is None:
+			from AutoPoller import AutoPoller
+			autopoller = AutoPoller()
+		autopoller.start(initial = False)
+	# Remove instance if not running in background
+	else:
+		autopoller = None
+		autotimer = None
+
+# Movielist
+def movielist(session, service, **kwargs):
+	from AutoTimerEditor import addAutotimerFromService
+	addAutotimerFromService(session, service)
+
+# Event Info
+def eventinfo(session, servicelist, **kwargs):
+	from AutoTimerEditor import AutoTimerEPGSelection
+	ref = session.nav.getCurrentlyPlayingServiceReference()
+	session.open(AutoTimerEPGSelection, ref)
+
+# XXX: we need this helper function to identify the descriptor
+# Extensions menu
+def extensionsmenu(session, **kwargs):
+	main(session, **kwargs)
+
+def housekeepingExtensionsmenu(el):
+	if el.value:
+		plugins.addPlugin(extDescriptor)
+	else:
+		plugins.removePlugin(extDescriptor)
+
+config.plugins.autotimer.show_in_extensionsmenu.addNotifier(housekeepingExtensionsmenu, initial_call = False, immediate_feedback = False)
+extDescriptor = PluginDescriptor(name="AutoTimer", description = _("Edit Timers and scan for new Events"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc = extensionsmenu)
+
+def Plugins(**kwargs):
+	l = [
+		PluginDescriptor(where = PluginDescriptor.WHERE_AUTOSTART, fnc = autostart),
+		PluginDescriptor(name="AutoTimer", description = _("Edit Timers and scan for new Events"), where = PluginDescriptor.WHERE_PLUGINMENU, icon = "plugin.png", fnc = main),
+		PluginDescriptor(name="AutoTimer", description= _("Add AutoTimer..."), where = PluginDescriptor.WHERE_MOVIELIST, fnc = movielist),
+		PluginDescriptor(name="AutoTimer", description= _("Add AutoTimer..."), where = PluginDescriptor.WHERE_EVENTINFO, fnc = eventinfo),
+	]
+	if config.plugins.autotimer.show_in_extensionsmenu.value:
+		l.append(extDescriptor)
+	return l
+
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefresh.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefresh.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefresh.py	(revision 5870)
@@ -0,0 +1,324 @@
+# -*- coding: UTF-8 -*-
+# To check if in Standby
+import Screens.Standby
+
+# eServiceReference
+from enigma import eServiceReference, eServiceCenter
+
+# ...
+from ServiceReference import ServiceReference
+
+# Timer
+from EPGRefreshTimer import epgrefreshtimer, EPGRefreshTimerEntry, checkTimespan
+
+# To calculate next timer execution
+from time import time
+
+# Plugin Config
+from xml.etree.cElementTree import parse as cet_parse
+from Tools.XMLTools import stringToXML
+from os import path as path
+
+# We want a list of unique services
+from EPGRefreshService import EPGRefreshService
+
+# Configuration
+from Components.config import config
+
+# Path to configuration
+CONFIG = "/etc/enigma2/epgrefresh.xml"
+
+class EPGRefresh:
+	"""Simple Class to refresh EPGData"""
+
+	def __init__(self):
+		# Initialize
+		self.services = (set(), set())
+		self.previousService = None
+		self.forcedScan = False
+		self.session = None
+		self.beginOfTimespan = 0
+
+		# Mtime of configuration files
+		self.configMtime = -1
+
+		# Read in Configuration
+		self.readConfiguration()
+
+	def readConfiguration(self):
+		# Check if file exists
+		if not path.exists(CONFIG):
+			return
+
+		# Check if file did not change
+		mtime = path.getmtime(CONFIG)
+		if mtime == self.configMtime:
+			return
+
+		# Keep mtime
+		self.configMtime = mtime
+
+		# Empty out list
+		self.services[0].clear()
+		self.services[1].clear()
+
+		# Open file
+		configuration= cet_parse(CONFIG).getroot()
+
+		# Add References
+		for service in configuration.findall("service"):
+			value = service.text
+			if value:
+				# strip all after last : (custom name)
+				pos = value.rfind(':')
+				if pos != -1:
+					value = value[:pos+1]
+
+				duration = service.get('duration', None)
+				duration = duration and int(duration)
+
+				self.services[0].add(EPGRefreshService(value, duration))
+		for bouquet in configuration.findall("bouquet"):
+			value = bouquet.text
+			if value:
+				duration = bouquet.get('duration', None)
+				duration = duration and int(duration)
+				self.services[1].add(EPGRefreshService(value, duration))
+
+	def buildConfiguration(self):
+		list = ['<?xml version="1.0" ?>\n<epgrefresh>\n\n']
+
+		for service in self.services[0]:
+			ref = ServiceReference(service.sref)
+			list.extend([' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'])
+			list.append(' <service')
+			if service.duration is not None:
+				list.extend([' duration="', str(service.duration), '"'])
+			list.extend(['>', stringToXML(service.sref), '</service>\n'])
+		for bouquet in self.services[1]:
+			ref = ServiceReference(bouquet.sref)
+			list.extend([' <!-- ', stringToXML(ref.getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')), ' -->\n'])
+			list.append(' <bouquet')
+			if bouquet.duration is not None:
+				list.extend([' duration="', str(bouquet.duration), '"'])
+			list.extend(['>', stringToXML(bouquet.sref), '</bouquet>\n'])
+
+		list.append('\n</epgrefresh>')
+
+		return list
+
+	def saveConfiguration(self):
+		file = open(CONFIG, 'w')
+		file.writelines(self.buildConfiguration())
+
+		file.close()
+
+	def forceRefresh(self, session = None):
+		print "[EPGRefresh] Forcing start of EPGRefresh"
+		if self.session is None:
+			if session is not None:
+				self.session = session
+			else:
+				return False
+
+		self.forcedScan = True
+		self.prepareRefresh()
+		return True
+
+	def start(self, session = None):
+		if session is not None:
+			self.session = session
+
+		epgrefreshtimer.setRefreshTimer(self.createWaitTimer)
+
+	def stop(self):
+		print "[EPGRefresh] Stopping Timer"
+		epgrefreshtimer.clear()
+
+	def prepareRefresh(self):
+		print "[EPGRefresh] About to start refreshing EPG"
+
+		# Keep service
+		self.previousService =  self.session.nav.getCurrentlyPlayingServiceReference()
+
+		# Maybe read in configuration
+		try:
+			self.readConfiguration()
+		except Exception, e:
+			print "[EPGRefresh] Error occured while reading in configuration:", e
+
+		# This will hold services which are not explicitely in our list
+		additionalServices = []
+		additionalBouquets = []
+
+		# See if we are supposed to read in autotimer services
+		if config.plugins.epgrefresh.inherit_autotimer.value:
+			removeInstance = False
+			try:
+				# Import Instance
+				from Plugins.Extensions.AutoTimer.plugin import autotimer
+
+				if autotimer is None:
+					removeInstance = True
+					# Create an instance
+					from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
+					autotimer = AutoTimer()
+
+				# Read in configuration
+				autotimer.readXml()
+			except Exception, e:
+				print "[EPGRefresh] Could not inherit AutoTimer Services:", e
+			else:
+				# Fetch services
+				for timer in autotimer.getEnabledTimerList():
+					additionalServices.extend([EPGRefreshService(x, None) for x in timer.services])
+					additionalBouquets.extend([EPGRefreshService(x, None) for x in timer.bouquets])
+			finally:
+				# Remove instance if there wasn't one before
+				if removeInstance:
+					autotimer = None
+
+		serviceHandler = eServiceCenter.getInstance()
+		for bouquet in self.services[1].union(additionalBouquets):
+			myref = eServiceReference(bouquet.sref)
+			list = serviceHandler.list(myref)
+			if list is not None:
+				while 1:
+					s = list.getNext()
+					# TODO: I wonder if its sane to assume we get services here (and not just new lists)
+					if s.valid():
+						additionalServices.append(EPGRefreshService(s.toString(), None))
+					else:
+						break
+		del additionalBouquets[:]
+
+		scanServices = []
+		channelIdList = []
+		for scanservice in self.services[0].union(additionalServices):
+			service = eServiceReference(scanservice.sref)
+			if not service.valid() \
+				or (service.flags & (eServiceReference.isMarker|eServiceReference.isDirectory)):
+
+				continue
+
+			channelID = '%08x%04x%04x' % (
+				service.getUnsignedData(4), # NAMESPACE
+				service.getUnsignedData(2), # TSID
+				service.getUnsignedData(3), # ONID
+			)
+
+			if channelID not in channelIdList:
+				scanServices.append(scanservice)
+				channelIdList.append(channelID)
+		del additionalServices[:]
+
+		# Debug
+		#print "[EPGRefresh] Services we're going to scan:", ', '.join([repr(x) for x in scanServices])
+
+		self.scanServices = scanServices
+		self.refresh()
+
+	def cleanUp(self):
+		config.plugins.epgrefresh.lastscan.value = int(time())
+		config.plugins.epgrefresh.lastscan.save()
+
+		# Eventually force autotimer to parse epg
+		if config.plugins.epgrefresh.parse_autotimer.value:
+			removeInstance = False
+			try:
+				# Import Instance
+				from Plugins.Extensions.AutoTimer.plugin import autotimer
+
+				if autotimer is None:
+					removeInstance = True
+					# Create an instance
+					from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
+					autotimer = AutoTimer()
+
+				# Parse EPG
+				autotimer.parseEPG()
+			except Exception, e:
+				print "[EPGRefresh] Could not start AutoTimer:", e
+			finally:
+				# Remove instance if there wasn't one before
+				if removeInstance:
+					autotimer = None
+
+		# shutdown if we're supposed to go to deepstandby and not recording
+		if not self.forcedScan and config.plugins.epgrefresh.afterevent.value \
+			and not Screens.Standby.inTryQuitMainloop:
+
+			self.session.open(
+				Screens.Standby.TryQuitMainloop,
+				1
+			)
+
+		self.forcedScan = False
+		epgrefreshtimer.cleanup()
+
+		# Zap back
+		if self.previousService is not None or Screens.Standby.inStandby:
+			self.session.nav.playService(self.previousService)
+
+	def refresh(self):
+		if self.forcedScan:
+			self.nextService()
+		else:
+			# Abort if a scan finished later than our begin of timespan
+			if self.beginOfTimespan < config.plugins.epgrefresh.lastscan.value:
+				return
+			if config.plugins.epgrefresh.force.value \
+				or (Screens.Standby.inStandby and \
+					not self.session.nav.RecordTimer.isRecording()):
+
+				self.nextService()
+			# We don't follow our rules here - If the Box is still in Standby and not recording we won't reach this line
+			else:
+				if not checkTimespan(
+					config.plugins.epgrefresh.begin.value,
+					config.plugins.epgrefresh.end.value):
+
+					print "[EPGRefresh] Gone out of timespan while refreshing, sorry!"
+					self.cleanUp()
+				else:
+					print "[EPGRefresh] Box no longer in Standby or Recording started, rescheduling"
+
+					# Recheck later
+					epgrefreshtimer.add(EPGRefreshTimerEntry(
+							time() + config.plugins.epgrefresh.delay_standby.value*60,
+							self.refresh,
+							nocheck = True)
+					)
+
+	def createWaitTimer(self):
+		self.beginOfTimespan = time()
+
+		# Add wait timer to epgrefreshtimer
+		epgrefreshtimer.add(EPGRefreshTimerEntry(time() + 30, self.prepareRefresh))
+
+	def nextService(self):
+		# Debug
+		print "[EPGRefresh] Maybe zap to next service"
+
+		try:
+			# Get next reference
+			service = self.scanServices.pop(0)
+		except IndexError:
+			# Debug
+			print "[EPGRefresh] Done refreshing EPG"
+
+			# Clean up
+			self.cleanUp()
+		else:
+			# Play next service
+			self.session.nav.playService(eServiceReference(service.sref))
+
+			# Start Timer
+			delay = service.duration or config.plugins.epgrefresh.interval.value
+			epgrefreshtimer.add(EPGRefreshTimerEntry(
+				time() + delay*60,
+				self.refresh,
+				nocheck = True)
+			)
+
+epgrefresh = EPGRefresh()
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshChannelEditor.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshChannelEditor.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshChannelEditor.py	(revision 5870)
@@ -0,0 +1,232 @@
+# -*- coding: UTF-8 -*-
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Components.ConfigList import ConfigListScreen
+from Screens.ChannelSelection import SimpleChannelSelection
+
+# GUI (Summary)
+from Screens.Setup import SetupSummary
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Button import Button
+
+# Configuration
+from Components.config import getConfigListEntry, ConfigSelection, \
+	NoSave
+
+from EPGRefreshService import EPGRefreshService
+
+# Show ServiceName instead of ServiceReference
+from ServiceReference import ServiceReference
+
+from enigma import getDesktop
+
+class SimpleBouquetSelection(SimpleChannelSelection):
+	def __init__(self, session, title):
+		SimpleChannelSelection.__init__(self, session, title)
+		self.skinName = "SimpleChannelSelection"
+
+	def channelSelected(self): # just return selected service
+		ref = self.getCurrentSelection()
+		if (ref.flags & 7) == 7:
+			self.close(ref)
+		else:
+			# We return the currently active path here
+			# Asking the user if this is what he wants might be better though
+			self.close(self.servicePath[-1])
+
+class EPGRefreshServiceEditor(Screen, ConfigListScreen):
+	"""Edit Services to be refreshed by EPGRefresh"""
+
+	skin = """<screen name="EPGRefreshServiceEditor" title="Edit Services to refresh" position="75,150" size="565,245">
+		<widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
+		<ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+	
+	skinKS = """<screen name="EPGRefreshServiceEditor" title="Edit Services to refresh" position="230,150" size="565,245">
+		<widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
+		<ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+	
+	skinHD = """<screen name="EPGRefreshServiceEditor" title="Edit Services to refresh" position="358,220" size="565,245">
+		<widget name="config" position="5,5" size="555,200" scrollbarMode="showOnDemand" />
+		<ePixmap position="5,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="145,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="285,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="425,205" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="5,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="145,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="285,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="425,205" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session, services):
+		try:
+			skin_w = getDesktop(0).size().width()
+			print "DESKTOPsize is",skin_w
+			if skin_w == 1280:
+				self.skin = EPGRefreshServiceEditor.skinHD
+			elif skin_w == 1024:
+				self.skin = EPGRefreshServiceEditor.skinKS
+			else:
+				self.skin = EPGRefreshServiceEditor.skin
+		except:
+			print "DESKTOPsize not detected"
+			self.skin = EPGRefreshServiceEditor.skin
+		Screen.__init__(self, session)
+
+		# Summary
+		self.setup_title = _("EPGRefresh Services")
+		self.onChangedEntry = []
+
+		# We need to copy the list to be able to ignore changes
+		self.services = (
+			services[0][:],
+			services[1][:]
+		)
+
+		self.typeSelection = NoSave(ConfigSelection(choices = [
+			("channels", _("Channels")),
+			("bouquets", _("Bouquets"))]
+		))
+		self.typeSelection.addNotifier(self.refresh, initial_call = False)
+
+		self.reloadList()
+
+		ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("OK"))
+		self["key_yellow"] = Button(_("delete"))
+		self["key_blue"] = Button(_("New"))
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+			{
+				"cancel": self.cancel,
+				"save": self.save,
+				"yellow": self.removeService,
+				"blue": self.newService
+			}
+		)
+
+		# Trigger change
+		self.changed()
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Edit Services to refresh"))
+
+	def saveCurrent(self):
+		del self.services[self.idx][:]
+
+		# Warning, accessing a ConfigListEntry directly might be considered evil!
+
+		myl = self["config"].getList()
+		myl.pop(0)
+		for item in myl:
+			self.services[self.idx].append(item[1].value)
+
+	def refresh(self, value):
+		self.saveCurrent()
+
+		self.reloadList()
+		self["config"].setList(self.list)
+
+	def reloadList(self):
+		self.list = [
+			getConfigListEntry(_("Editing"), self.typeSelection)
+		]
+
+		if self.typeSelection.value == "channels":
+			self.idx = 0
+		else: # self.typeSelection.value == "bouquets":
+			self.idx = 1
+
+		self.list.extend([
+			getConfigListEntry(_("Refreshing"), NoSave(ConfigSelection(choices = [(x, ServiceReference(x.sref).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', ''))])))
+				for x in self.services[self.idx]
+		])
+
+	def changed(self):
+		for x in self.onChangedEntry:
+			try:
+				x()
+			except Exception:
+				pass
+
+	def getCurrentEntry(self):
+		cur = self["config"].getCurrent()
+		if cur:
+			return cur[0]
+		return ""
+
+	def getCurrentValue(self):
+		cur = self["config"].getCurrent()
+		if cur:
+			return str(cur[1].getText())
+		return ""
+
+	def createSummary(self):
+		return SetupSummary
+
+	def removeService(self):
+		cur = self["config"].getCurrent()
+		if cur:
+			list = self["config"].getList()
+			list.remove(cur)
+			self["config"].setList(list)
+
+	def newService(self):
+		if self.typeSelection.value == "channels":
+			self.session.openWithCallback(
+				self.finishedServiceSelection,
+				SimpleChannelSelection,
+				_("Select channel to refresh")
+			)
+		else: # self.typeSelection.value == "bouquets":
+			self.session.openWithCallback(
+				self.finishedServiceSelection,
+				SimpleBouquetSelection,
+				_("Select bouquet to refresh")
+			)
+
+	def finishedServiceSelection(self, *args):
+		if args:
+			list = self["config"].getList()
+			list.append(getConfigListEntry(
+				_("Refreshing"),
+				NoSave(ConfigSelection(choices = [(
+					EPGRefreshService(str(args[0].toString()), None),
+					ServiceReference(args[0]).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '')
+				)]))
+			))
+			self["config"].setList(list)
+
+	def cancel(self):
+		self.close(None)
+
+	def save(self):
+		self.saveCurrent()
+
+		self.close(self.services)
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshConfiguration.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshConfiguration.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshConfiguration.py	(revision 5870)
@@ -0,0 +1,185 @@
+# for localized messages
+from . import _
+
+# GUI (Screens)
+from Screens.Screen import Screen
+from Components.ConfigList import ConfigListScreen
+from EPGRefreshChannelEditor import EPGRefreshServiceEditor
+
+# GUI (Summary)
+from Screens.Setup import SetupSummary
+
+# GUI (Components)
+from Components.ActionMap import ActionMap
+from Components.Button import Button
+
+# Configuration
+from Components.config import config, getConfigListEntry
+
+from EPGRefresh import epgrefresh
+
+from enigma import getDesktop
+
+class EPGRefreshConfiguration(Screen, ConfigListScreen):
+	"""Configuration of EPGRefresh"""
+
+	skin = """<screen name="EPGRefreshConfiguration" title="Configure EPGRefresh" position="75,155" size="565,280">
+		<widget name="config" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
+		<ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+	
+	skinKS = """<screen name="EPGRefreshConfiguration" title="Configure EPGRefresh" position="230,155" size="565,280">
+		<widget name="config" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
+		<ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+	
+	skinHD = """<screen name="EPGRefreshConfiguration" title="Configure EPGRefresh" position="358,220" size="565,280">
+		<widget name="config" position="5,5" size="555,225" scrollbarMode="showOnDemand" />
+		<ePixmap position="0,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+		<ePixmap position="140,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+		<ePixmap position="280,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+		<ePixmap position="420,235" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+		<widget name="key_red" position="0,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_green" position="140,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_yellow" position="280,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+		<widget name="key_blue" position="420,235" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+	</screen>"""
+
+	def __init__(self, session):
+		try:
+			skin_w = getDesktop(0).size().width()
+			print "DESKTOPsize is",skin_w
+			if skin_w == 1280:
+				self.skin = EPGRefreshConfiguration.skinHD
+			elif skin_w == 1024:
+				self.skin = EPGRefreshConfiguration.skinKS
+			else:
+				self.skin = EPGRefreshConfiguration.skin
+		except:
+			print "DESKTOPsize not detected"
+			self.skin = EPGRefreshConfiguration.skin
+		Screen.__init__(self, session)
+
+		# Summary
+		self.setup_title = _("EPGRefresh Configuration")
+		self.onChangedEntry = []
+
+		# Although EPGRefresh keeps services in a Set we prefer a list
+		self.services = (
+			[x for x in epgrefresh.services[0]],
+			[x for x in epgrefresh.services[1]]
+		)
+
+		self.list = [
+			getConfigListEntry(_("Refresh automatically"), config.plugins.epgrefresh.enabled),
+			getConfigListEntry(_("Wakeup from Deep-Standby to refresh EPG"), config.plugins.epgrefresh.wakeup),
+			getConfigListEntry(_("Time to stay on service (in m)"), config.plugins.epgrefresh.interval),
+			getConfigListEntry(_("Refresh EPG after"), config.plugins.epgrefresh.begin),
+			getConfigListEntry(_("Refresh EPG before"), config.plugins.epgrefresh.end),
+			getConfigListEntry(_("Delay when not in Standby (in m)"), config.plugins.epgrefresh.delay_standby),
+			getConfigListEntry(_("Force scan even if reciever is in use"), config.plugins.epgrefresh.force),
+			getConfigListEntry(_("Inherit Services from AutoTimer if available"), config.plugins.epgrefresh.inherit_autotimer),
+			getConfigListEntry(_("Make AutoTimer parse EPG if available"), config.plugins.epgrefresh.parse_autotimer),
+			getConfigListEntry(_("Shutdown after refresh"), config.plugins.epgrefresh.afterevent),
+		]
+
+		ConfigListScreen.__init__(self, self.list, session = session, on_change = self.changed)
+
+		# Initialize Buttons
+		self["key_red"] = Button(_("Cancel"))
+		self["key_green"] = Button(_("OK"))
+		self["key_yellow"] = Button(_("Refresh now"))
+		self["key_blue"] = Button(_("Edit Services"))
+
+		# Define Actions
+		self["actions"] = ActionMap(["SetupActions", "ColorActions"],
+			{
+				"cancel": self.keyCancel,
+				"save": self.keySave,
+				"yellow": self.forceRefresh,
+				"blue": self.editServices
+			}
+		)
+
+		# Trigger change
+		self.changed()
+
+		self.onLayoutFinish.append(self.setCustomTitle)
+
+	def setCustomTitle(self):
+		self.setTitle(_("Configure EPGRefresh"))
+
+	def forceRefresh(self):
+		epgrefresh.services = (set(self.services[0]), set(self.services[1]))
+		epgrefresh.forceRefresh(self.session)
+
+	def editServices(self):
+		self.session.openWithCallback(
+			self.editServicesCallback,
+			EPGRefreshServiceEditor,
+			self.services
+		)
+
+	def editServicesCallback(self, ret):
+		if ret:
+			self.services = ret
+
+	def changed(self):
+		for x in self.onChangedEntry:
+			try:
+				x()
+			except Exception:
+				pass
+
+	def getCurrentEntry(self):
+		return self["config"].getCurrent()[0]
+
+	def getCurrentValue(self):
+		return str(self["config"].getCurrent()[1].getText())
+
+	def createSummary(self):
+		return SetupSummary
+
+	def cancelConfirm(self, result):
+		if not result:
+			return
+
+		for x in self["config"].list:
+			x[1].cancel()
+
+		self.close(self.session)
+
+	def keyCancel(self):
+		if self["config"].isChanged():
+			from Screens.MessageBox import MessageBox
+
+			self.session.openWithCallback(
+				self.cancelConfirm,
+				MessageBox,
+				_("Really close without saving settings?")
+			)
+		else:
+			self.close(self.session)
+
+	def keySave(self):
+		epgrefresh.services = (set(self.services[0]), set(self.services[1]))
+		epgrefresh.saveConfiguration()
+
+		for x in self["config"].list:
+			x[1].save()
+
+		self.close(self.session)
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshResource.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshResource.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshResource.py	(revision 5870)
@@ -0,0 +1,118 @@
+from twisted.web import http, resource
+from EPGRefresh import epgrefresh
+from EPGRefreshService import EPGRefreshService
+from enigma import eServiceReference
+
+class EPGRefreshStartRefreshResource(resource.Resource):
+	def render(self, req):
+		state = False
+
+		if epgrefresh.forceRefresh():
+			output = "initiated refresh"
+			state = True
+		else:
+			output = "could not initiate refresh"
+
+		req.setResponseCode(http.OK)
+		req.setHeader('Content-type', 'application; xhtml+xml')
+		req.setHeader('charset', 'UTF-8')
+
+		return """<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
+			<e2simplexmlresult>
+				<e2state>%s</e2state>
+				<e2statetext>%s</e2statetext>
+			</e2simplexmlresult>
+			""" % ('true' if state else 'false', output)
+
+class EPGRefreshAddRemoveServiceResource(resource.Resource):
+	TYPE_ADD = 0
+	TYPE_DEL = 1
+
+	def __init__(self, type):
+		assert(type in (self.TYPE_ADD, self.TYPE_DEL))
+		self.type = type
+
+	def render(self, req):
+		do_add = self.type == self.TYPE_ADD
+		state = False
+
+		if 'sref' in req.args:
+			sref = req.args["sref"][0]
+			if do_add:
+				# strip all after last : (custom name)
+				pos = sref.rfind(':')
+				if pos != -1:
+					sref = sref[:pos+1]
+
+			duration = req.args.get("duration", None)
+			try:
+				duration = duration and int(duration)
+			except ValueError, ve:
+				output = 'invalid value for "duration": ' + str(duration)
+			else:
+				epgservice = EPGRefreshService(sref, duration)
+
+				if sref:
+					ref = eServiceReference(str(sref))
+					if not ref.valid():
+						output = 'invalid value for "sref": ' + str(sref)
+					elif (ref.flags & 7) == 7:
+						# bouquet
+						if epgservice in epgrefresh.services[1]:
+							if do_add:
+								output = "bouquet already in list"
+							else:
+								epgrefresh.services[1].remove(epgservice)
+								output = "bouquet removed from list"
+								state = True
+						else:
+							if do_add:
+								epgrefresh.services[1].add(epgservice)
+								output = "bouquet added to list"
+								state = True
+							else:
+								output = "bouquet not in list"
+					else:
+						# assume service
+						if epgservice in epgrefresh.services[0]:
+							if do_add:
+								output = "service already in list"
+							else:
+								epgrefresh.services[0].remove(epgservice)
+								output = "service removed from list"
+								state = True
+						else:
+							if do_add:
+								epgrefresh.services[0].add(epgservice)
+								output = "service added to list"
+								state = True
+							else:
+								output = "service not in list"
+
+					# save if list changed
+					if state:
+						epgrefresh.saveConfiguration()
+				else:
+					output = 'invalid value for "sref": ' + str(sref)
+		else:
+			output = 'missing argument "sref"'
+
+		req.setResponseCode(http.OK)
+		req.setHeader('Content-type', 'application; xhtml+xml')
+		req.setHeader('charset', 'UTF-8')
+		
+		return """<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
+			<e2simplexmlresult>
+				<e2state>%s</e2state>
+				<e2statetext>%s</e2statetext>
+			</e2simplexmlresult>
+			""" % ('true' if state else 'false', output)
+
+class EPGRefreshListServicesResource(resource.Resource):
+	def render(self, req):
+		# show xml
+		req.setResponseCode(http.OK)
+		req.setHeader('Content-type', 'application; xhtml+xml')
+		req.setHeader('charset', 'UTF-8')
+		return ''.join(epgrefresh.buildConfiguration())
+
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshService.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshService.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshService.py	(revision 5870)
@@ -0,0 +1,25 @@
+class EPGRefreshService(object):
+	def __init__(self, sref, duration):
+		self.sref = str(sref)
+		self.duration = duration
+
+	def __eq__(self, other):
+		if hasattr(other, 'sref'):
+			return self.sref == other.sref
+		return False
+
+	def __hash__(self):
+		return self.sref.__hash__()
+
+	def __str__(self):
+		return self.sref
+
+	def __repr__(self):
+		return ''.join((
+			'<EPGRefreshService (',
+			', '.join((
+				self.sref,
+				str(self.duration or '?'),
+			)),
+			')>'
+		))
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshTimer.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshTimer.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/EPGRefreshTimer.py	(revision 5870)
@@ -0,0 +1,165 @@
+# To check if in Standby
+import Screens.Standby
+
+# Base Class
+import timer
+
+# To see if in Timespan and to determine begin of timespan
+from time import localtime, mktime, time, strftime
+
+# Config
+from Components.config import config
+
+def checkTimespan(begin, end):
+	# Get current time
+	time = localtime()
+
+	# Check if we span a day
+	if begin[0] > end[0] or (begin[0] == end[0] and begin[1] >= end[1]):
+		# Check if begin of event is later than our timespan starts
+		if time.tm_hour > begin[0] or (time.tm_hour == begin[0] and time.tm_min >= begin[1]):
+			# If so, event is in our timespan
+			return True
+		# Check if begin of event is earlier than our timespan end
+		if time.tm_hour < end[0] or (time.tm_hour == end[0] and time.tm_min <= end[1]):
+			# If so, event is in our timespan
+			return True
+		return False
+	else:
+		# Check if event begins earlier than our timespan starts
+		if time.tm_hour < begin[0] or (time.tm_hour == begin[0] and time.tm_min < begin[1]):
+			# Its out of our timespan then
+			return False
+		# Check if event begins later than our timespan ends
+		if time.tm_hour > end[0] or (time.tm_hour == end[0] and time.tm_min > end[1]):
+			# Its out of our timespan then
+			return False
+		return True
+
+class EPGRefreshTimerEntry(timer.TimerEntry):
+	"""TimerEntry ..."""
+	def __init__(self, begin, tocall, nocheck = False):
+		timer.TimerEntry.__init__(self, int(begin), int(begin))
+
+		self.function = tocall
+		self.nocheck = nocheck
+		if nocheck:
+			self.state = self.StatePrepared
+
+	def getNextActivation(self):
+		# We delay our activation so we won't rush into reprocessing a repeating one
+		return self.begin+1
+
+	def activate(self):
+		if self.state == self.StateWaiting:
+			# Check if in timespan
+			if checkTimespan(config.plugins.epgrefresh.begin.value, config.plugins.epgrefresh.end.value):
+				print "[EPGRefresh] In Timespan, will check if we're in Standby and have no Recordings running next"
+				# Do we realy want to check nav?
+				from NavigationInstance import instance
+				if config.plugins.epgrefresh.force.value or (Screens.Standby.inStandby and instance is not None and not instance.RecordTimer.isRecording()):
+					return True
+				else:
+					print "[EPGRefresh] Box still in use, rescheduling"
+
+					# Recheck later
+					self.begin = time() + config.plugins.epgrefresh.delay_standby.value*60
+					return False
+			else:
+				print "[EPGRefresh] Not in timespan, ending timer"
+				self.state = self.StateEnded
+				return False
+		elif self.state == self.StateRunning:
+			self.function()
+
+		return True
+
+	def resetState(self):
+		self.state = self.StateWaiting
+		self.cancelled = False
+		self.timeChanged()
+
+	def timeChanged(self):
+		if self.nocheck and self.state < self.StateRunning:
+			self.state = self.StatePrepared
+
+	def shouldSkip(self):
+		return False
+
+	def __repr__(self):
+		return ''.join((
+				"<EPGRefreshTimerEntry (",
+				', '.join((
+					strftime("%c", localtime(self.begin)),
+					str(self.repeated),
+					str(self.function)
+				)),
+				")>"
+			))
+
+class EPGRefreshTimer(timer.Timer):
+	def __init__(self):
+		timer.Timer.__init__(self)
+
+	def remove(self, entry):
+		print "[EPGRefresh] Timer removed " + str(entry)
+
+		# avoid re-enqueuing
+		entry.repeated = False
+
+		# abort timer.
+		# this sets the end time to current time, so timer will be stopped.
+		entry.abort()
+
+		if entry.state != entry.StateEnded:
+			self.timeChanged(entry)
+
+		print "state: ", entry.state
+		print "in processed: ", entry in self.processed_timers
+		print "in running: ", entry in self.timer_list
+		# now the timer should be in the processed_timers list. remove it from there.
+		self.processed_timers.remove(entry)
+
+	def setRefreshTimer(self, tocall):
+		# Add refresh Timer
+		now = localtime()
+		# XXX: basic workaround if the clock is not yet set
+		year = 2009
+		if now.tm_year > 2009:
+			year = now.tm_year
+		begin = mktime(
+			(year, now.tm_mon, now.tm_mday,
+			config.plugins.epgrefresh.begin.value[0],
+			config.plugins.epgrefresh.begin.value[1],
+			0, now.tm_wday, now.tm_yday, now.tm_isdst)
+		)
+
+		# If the last scan was finished before our timespan begins/began and
+		# timespan began in the past fire the timer once (timer wouldn't do so
+		# by itself)
+		if config.plugins.epgrefresh.lastscan.value < begin and begin < time():
+			tocall()
+
+		refreshTimer = EPGRefreshTimerEntry(begin, tocall, nocheck = True)
+
+		i = 0
+		while i < 7:
+			refreshTimer.setRepeated(i)
+			i += 1
+
+		# We can be sure that whenever this function is called the timer list
+		# was wiped, so just add a new timer
+		self.addTimerEntry(refreshTimer)
+
+	def add(self, entry):
+		entry.timeChanged()
+		print "[EPGRefresh] Timer added " + str(entry)
+		self.addTimerEntry(entry)
+
+	def clear(self):
+		self.timer_list = []
+
+	def isActive(self):
+		return len(self.timer_list) > 0
+
+epgrefreshtimer = EPGRefreshTimer()
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/LICENSE
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/LICENSE	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/LICENSE	(revision 5870)
@@ -0,0 +1,12 @@
+All Files of this Software are licensed under the Creative Commons 
+Attribution-NonCommercial-ShareAlike 3.0 Unported 
+License if not stated otherwise in a Files Head. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+
+Alternatively, this plugin may be distributed and executed on hardware which
+is licensed by Dream Multimedia GmbH.
+
+This plugin is NOT free software. It is open source, you are allowed to
+modify it (if you keep the license), but it may not be commercially 
+distributed other than under the conditions noted above.
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/__init__.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/__init__.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/__init__.py	(revision 5870)
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
+from os import environ as os_environ
+import gettext
+
+def localeInit():
+	lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
+	os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
+	gettext.bindtextdomain("EPGRefresh", resolveFilename(SCOPE_PLUGINS, "Extensions/EPGRefresh/locale"))
+
+def _(txt):
+	t = gettext.dgettext("EPGRefresh", txt)
+	if t == txt:
+		print "[EPGRefresh] fallback to default translation for", txt
+		t = gettext.gettext(txt)
+	return t
+
+localeInit()
+language.addCallback(localeInit)
+
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/maintainer.info
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/maintainer.info	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+moritz.venn@freaque.net
+EPGRefresh
Index: /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/plugin.py
===================================================================
--- /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/plugin.py	(revision 5870)
+++ /ipk/source/swapepg_epgrefresh_2_6/var/swap/extensions/EPGRefresh/plugin.py	(revision 5870)
@@ -0,0 +1,148 @@
+# for localized messages
+from . import _
+
+# Config
+from Components.config import config, ConfigYesNo, ConfigNumber, \
+	ConfigSubsection, ConfigClock
+
+# Calculate default begin/end
+from time import time, localtime, mktime
+now = localtime()
+begin = mktime((
+	now.tm_year, now.tm_mon, now.tm_mday, 20, 15, \
+	0, now.tm_wday, now.tm_yday, now.tm_isdst)
+)
+end = mktime((
+	now.tm_year, now.tm_mon, now.tm_mday, 06, 30, \
+	0, now.tm_wday, now.tm_yday, now.tm_isdst)
+)
+
+config.plugins.epgrefresh = ConfigSubsection()
+config.plugins.epgrefresh.enabled = ConfigYesNo(default = False)
+config.plugins.epgrefresh.begin = ConfigClock(default = int(begin))
+config.plugins.epgrefresh.end = ConfigClock(default = int(end))
+config.plugins.epgrefresh.interval = ConfigNumber(default = 2)
+config.plugins.epgrefresh.delay_standby = ConfigNumber(default = 10)
+config.plugins.epgrefresh.inherit_autotimer = ConfigYesNo(default = False)
+config.plugins.epgrefresh.afterevent = ConfigYesNo(default = False)
+config.plugins.epgrefresh.force = ConfigYesNo(default = False)
+config.plugins.epgrefresh.wakeup = ConfigYesNo(default = False)
+config.plugins.epgrefresh.lastscan = ConfigNumber(default = 0)
+config.plugins.epgrefresh.parse_autotimer = ConfigYesNo(default = False)
+
+del now, begin, end
+
+# Plugin
+from EPGRefresh import epgrefresh
+from EPGRefreshConfiguration import EPGRefreshConfiguration
+from EPGRefreshService import EPGRefreshService
+
+# Plugin definition
+from Plugins.Plugin import PluginDescriptor
+
+def standbyQuestionCallback(session, res = None):
+	if res:
+		from Screens.Standby import Standby
+		session.open(Standby)
+
+# Autostart
+def autostart(reason, **kwargs):
+	if reason == 0 and kwargs.has_key("session"):
+		session = kwargs["session"]
+		epgrefresh.session = session
+
+		if config.plugins.epgrefresh.enabled.value:
+			if config.plugins.epgrefresh.wakeup.value:
+				now = localtime()
+				begin = int(mktime(
+					(now.tm_year, now.tm_mon, now.tm_mday,
+					config.plugins.epgrefresh.begin.value[0],
+					config.plugins.epgrefresh.begin.value[1],
+					0, now.tm_wday, now.tm_yday, now.tm_isdst)
+				))
+				# booted +- 10min from begin of timespan
+				if abs(time() - begin) < 600:
+					from Screens.MessageBox import MessageBox
+					from Tools.Notifications import AddNotificationWithCallback
+					from Tools.BoundFunction import boundFunction
+					# XXX: we use a notification because this will be suppressed otherwise
+					AddNotificationWithCallback(
+						boundFunction(standbyQuestionCallback, session),
+						MessageBox,
+						_("This might have been an automated bootup to refresh the EPG. For this to happen it is recommmended to put the receiver to Standby.\nDo you want to do this now?"),
+						timeout = 15
+					)
+
+			epgrefresh.start(session)
+
+	elif reason == 1:
+		epgrefresh.stop()
+
+def getNextWakeup():
+	# Return invalid time if not automatically refreshing
+	if not config.plugins.epgrefresh.enabled.value or \
+		not config.plugins.epgrefresh.wakeup.value:
+
+		return -1
+
+	now = localtime()
+	begin = int(mktime(
+		(now.tm_year, now.tm_mon, now.tm_mday,
+		config.plugins.epgrefresh.begin.value[0],
+		config.plugins.epgrefresh.begin.value[1],
+		0, now.tm_wday, now.tm_yday, now.tm_isdst)
+	))
+	# todays timespan has not yet begun
+	if begin > time():
+		return begin
+	# otherwise add 1 day
+	return begin+86400
+
+# Mainfunction
+def main(session, **kwargs):
+	epgrefresh.stop()
+	session.openWithCallback(
+		doneConfiguring,
+		EPGRefreshConfiguration
+	)
+
+def doneConfiguring(session, **kwargs):
+	if config.plugins.epgrefresh.enabled.value:
+		epgrefresh.start(session)
+
+# Eventinfo
+def eventinfo(session, servicelist, **kwargs):
+	ref = session.nav.getCurrentlyPlayingServiceReference()
+	if not ref:
+		return
+	sref = ref.toString()
+	# strip all after last :
+	pos = sref.rfind(':')
+	if pos != -1:
+		sref = sref[:pos+1]
+
+	epgrefresh.services[0].add(EPGRefreshService(str(sref), None))
+
+def Plugins(**kwargs):
+	return [
+		PluginDescriptor(
+			name = "EPGRefresh",
+			where = [
+				PluginDescriptor.WHERE_AUTOSTART,
+				PluginDescriptor.WHERE_SESSIONSTART
+			],
+			fnc = autostart,
+			wakeupfnc = getNextWakeup
+		),
+		PluginDescriptor(
+			name = "EPGRefresh",
+			description = _("Automated EPGRefresher"),
+			where = PluginDescriptor.WHERE_PLUGINMENU,
+			fnc = main
+		),
+		PluginDescriptor(
+			name = _("Add to EPGRefresh"),
+			where = PluginDescriptor.WHERE_EVENTINFO,
+			fnc = eventinfo
+		),
+	]
Index: /ipk/source/swapgames_Sudoku_1_1/var/swap/extensions/Sudoku/plugin.py
===================================================================
--- /ipk/source/swapgames_Sudoku_1_1/var/swap/extensions/Sudoku/plugin.py	(revision 5870)
+++ /ipk/source/swapgames_Sudoku_1_1/var/swap/extensions/Sudoku/plugin.py	(revision 5870)
@@ -0,0 +1,676 @@
+# -*- coding: ISO-8859-1 -*-
+#===============================================================================
+# Sudoku Plugin by DarkVolli 2009
+# class board by Robert Wohleb
+#
+# This 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, or (at your option) any later
+# version.
+#===============================================================================
+
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+from Screens.MessageBox import MessageBox
+from Components.Sources.CanvasSource import CanvasSource
+from Components.Button import Button
+from Components.Label import Label
+from Components.ActionMap import ActionMap
+from Tools.Directories import fileExists, resolveFilename, SCOPE_CURRENT_SKIN
+from enigma import eTimer, gFont, getDesktop, RT_HALIGN_CENTER, RT_VALIGN_CENTER
+from Components.config import config
+import random
+import xml.etree.cElementTree
+
+SAVEFILE = "/usr/lib/enigma2/python/Plugins/Extensions/Sudoku/Sudoku.sav"
+
+def RGB(r,g,b):
+	return (r<<16)|(g<<8)|b
+
+
+def main(session,**kwargs):
+	session.open(Sudoku)
+
+
+def Plugins(**kwargs):
+	return [PluginDescriptor(name="Sudoku", description=_("Sudoku Game"), where = [PluginDescriptor.WHERE_PLUGINMENU], fnc=main)]
+
+
+# thanks to Robert Wohleb for this class...
+class board:
+	boardlist = []
+	partialboardlist = []
+
+
+	def generate(self, numFilled=(9*9)):
+		slots = []
+		fillOrder = []
+
+		random.seed()
+
+		# setup board
+		row = [0,0,0,0,0,0,0,0,0]
+		for i in range(0, 9):
+			self.boardlist.append(row[:])
+
+		for j in range(0, 9):
+			for i in range(0, 9):
+				slots.append((i,j))
+
+		self.search(slots, 0)
+		
+		while len(slots) > 0:
+			i = random.randint(0, len(slots)-1)
+			fillOrder.append(slots[i])
+			del slots[i]
+
+		# setup board
+		for i in range(0, 9):
+			self.partialboardlist.append(row[:])
+
+		for i in range(0, numFilled):
+			j = fillOrder[i]
+			self.partialboardlist[j[0]][j[1]] = self.boardlist[j[0]][j[1]]
+
+
+	def search(self, slots, index):
+		nums = []
+		fillOrder = []
+
+		if len(slots) == index:
+			return self.check()
+
+		for i in range(1, 10):
+			nums.append(i)
+
+		while len(nums) > 0:
+			i = random.randint(0, len(nums)-1)
+			fillOrder.append(nums[i])
+			del nums[i]
+
+		for i in fillOrder:
+			x = slots[index][0]
+			y = slots[index][1]
+			self.boardlist[x][y] = i
+			if (self.check()):
+				if self.search(slots, index+1):
+					return True
+			self.boardlist[x][y] = 0
+		return False
+
+
+	def check(self):
+		for i in range(0, 9):
+			if (not self.checkRow(i)) or (not self.checkCol(i)) or (not self.checkSquare(i)):
+				return False
+		return True
+
+
+	def checkRow(self, row):
+		found = []
+		for i in range(0, 9):
+			if not self.boardlist[i][row] == 0:
+				if self.boardlist[i][row] in found:
+					return False
+				found.append(self.boardlist[i][row])
+		return True
+
+
+	def checkCol(self, col):
+		found = []
+		for j in range(0, 9):
+			if not self.boardlist[col][j] == 0:
+				if self.boardlist[col][j] in found:
+					return False
+				found.append(self.boardlist[col][j])
+		return True
+
+
+	def checkSquare(self, square):
+		found = []
+		xoffset = (3*(square % 3))
+		yoffset = int(square / 3) * 3
+		for j in range(0, 3):
+			for i in range(0, 3):
+				if not self.boardlist[xoffset+i][yoffset+j] == 0:
+					if self.boardlist[xoffset+i][yoffset+j] in found:
+						return False
+					found.append(self.boardlist[xoffset+i][yoffset+j])
+		return True
+
+
+# Sudoku cell...
+class SudokuCell:
+	def __init__(self, canvas, x, y, w, h):
+		self.canvas = canvas
+		self.x      = x
+		self.y      = y
+		self.w      = w
+		self.h      = h
+
+		self.value_ = 0
+		self.focus_ = False
+		self.readonly_ = False
+		self.bg_color = 0
+
+
+	def setValue(self, v):
+		self.value_ = v
+
+
+	def value(self):
+		return self.value_
+
+
+	def setFocus(self, f):
+		self.focus_ = f
+
+
+	def focus(self):
+		return self.focus_
+
+
+	def setReadonly(self, r):
+		self.readonly_ = r
+
+
+	def readonly(self):
+		return self.readonly_
+
+
+	def color(self, col):
+		self.bg_color = col
+
+
+	def paint(self):
+		fg    = RGB(255,255,255) # foreground
+		black = RGB(  0,  0,  0) # background readonly
+		focus = RGB(192,192,  0) # background focus
+		grey  = RGB( 70, 70, 70) # background not readonly
+		green = RGB(  0,255,  0) # background solved
+		red   = RGB(255,  0,  0) # background error
+
+		b  = 2
+
+		self.canvas.fill(self.x, self.y, self.w, self.h, fg)
+		
+		if self.bg_color == 0:
+			bg = black
+		elif self.bg_color == 1:
+			bg = grey
+		elif self.bg_color == 2:
+			bg = green
+		elif self.bg_color == 3:
+			bg = red
+
+		if self.focus_:
+			bg = focus
+
+		self.canvas.fill(self.x+b, self.y+b, self.w-2*b, self.h-2*b, bg)
+
+		if self.value_ > 0:
+			self.canvas.writeText(self.x, self.y, self.w, self.h, fg, bg, gFont("Regular", 24), str(self.value_), RT_HALIGN_CENTER|RT_VALIGN_CENTER)
+
+		self.canvas.flush()
+
+
+# mainwindow...
+class Sudoku(Screen):
+
+	def __init__(self, session):
+		# get framebuffer resolution...
+		desk = getDesktop(0)
+		w = int(desk.size().width())
+		h = int(desk.size().height())
+
+		# display window in center...
+		x = (w - 520) / 2
+		y = (h - 390) / 2
+
+		# set skin...
+		# ToDo: change for HD Skins...
+		Sudoku.skin = """
+			<screen position="%d,%d" size="520,390" title="Sudoku 0.1" >
+				<widget source="Canvas" render="Canvas" position="10,20" size="354,354" />
+				<widget name="gamelevel" position="380,25" size="140,40" font="Regular;21"/>
+				<ePixmap name="green"    position="375,98"   zPosition="4" size="140,40" pixmap="skin_default/buttons/green.png" transparent="1" alphatest="on" />
+				<ePixmap name="yellow"  position="375,178" zPosition="4" size="140,40" pixmap="skin_default/buttons/yellow.png" transparent="1" alphatest="on" />
+				<ePixmap name="blue" position="375,258" zPosition="4" size="140,40" pixmap="skin_default/buttons/blue.png" transparent="1" alphatest="on" />
+				<ePixmap name="red"   position="375,338" zPosition="4" size="140,40" pixmap="skin_default/buttons/red.png" transparent="1" alphatest="on" />
+				<widget name="key_green"    position="375,98"   zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+				<widget name="key_yellow"  position="375,178" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+				<widget name="key_blue" position="375,258" zPosition="5" size="140,40" valign="center" halign="center"  font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+				<widget name="key_red"   position="375,338" zPosition="5" size="140,40" valign="center" halign="center" font="Regular;21" transparent="1" foregroundColor="white" shadowColor="black" shadowOffset="-1,-1" />
+			</screen>""" % (x, y)
+
+		# i'm not really sure if this is the right way to get the background color from a skinned window?
+		# there must exist a better way? everything is taken from skin.py
+		# find xml for actual skin...
+#--- Civer start--------
+		skin = config.skin.primary_skin.value[:16]
+		print "-----------SKIN:",skin
+		if skin == "/var/swap/skins/":
+			print "----------------SWAPSKIN ERKANNT"
+			filename = config.skin.primary_skin.value
+		else:
+#--- Civer end----------
+			filename = resolveFilename(SCOPE_CURRENT_SKIN) + "skin.xml"
+			print "------------------------FILENAME", filename
+			print "-----------------", resolveFilename(SCOPE_CURRENT_SKIN)
+		actualSkin = xml.etree.cElementTree.parse(filename).getroot()
+		print "------------------------ACTUALSKIN", actualSkin
+
+		# get colors from skin and write to dictionary
+		colorNames = dict()
+		for c in actualSkin.findall("colors"):
+			for color in c.findall("color"):
+				get_attr = color.attrib.get
+				name = get_attr("name")
+				color = get_attr("value")
+				if name and color:
+					colorNames[name] = color
+					#print "Color:", name, color
+
+		# find colors for skinned window...
+		for windowstyle in actualSkin.findall("windowstyle"):
+			# look or skinned window...
+			if windowstyle.attrib.get("id") == "0":
+				for color in windowstyle.findall("color"):
+					get_attr = color.attrib.get
+					type = get_attr("name")
+					color = get_attr("color")
+					# is it a "named" color?
+					if color[0] != '#':
+						# is "named" color, have to look in dictionary... 
+						color = colorNames[color]
+					#print type, color
+					# at least get the background color...
+					if type == "Background":
+						bgcolor = int(color[1:], 0x10)
+		#if not bgcolor:
+		bgcolor = RGB(  0,  0,  0)
+
+		self.skin = Sudoku.skin
+		Screen.__init__(self, session)
+		self["Canvas"] = CanvasSource()
+		self["gamelevel"] = Label(_(" <    easy    >"))
+		self["key_green"] = Button(_("new game"))
+		self["key_yellow"] = Button(_("check game"))
+		self["key_blue"] = Button(_("restart game"))
+		self["key_red"] = Button(_("solve game"))
+		
+		self.cnt = 0;
+		self.timer = eTimer()
+		self.timer.callback.append(self.timerHandler)
+
+		self.xFocus = 4
+		self.yFocus = 4
+
+		self.gameLevel = 0
+
+		self["actions"] = ActionMap(["WizardActions", "ColorActions", "SetupActions"],
+		{
+			"0"     : self.bt_0_pressed,
+			"1"     : self.bt_1_pressed,
+			"2"     : self.bt_2_pressed,
+			"3"     : self.bt_3_pressed,
+			"4"     : self.bt_4_pressed,
+			"5"     : self.bt_5_pressed,
+			"6"     : self.bt_6_pressed,
+			"7"     : self.bt_7_pressed,
+			"8"     : self.bt_8_pressed,
+			"9"     : self.bt_9_pressed,
+			"up"    : self.up_pressed,
+			"down"  : self.down_pressed,
+			"left"  : self.left_pressed,
+			"right" : self.right_pressed,
+			"red"   : self.bt_solve_game,
+			"green" : self.bt_new_game,
+			"yellow": self.bt_check_game,
+			"blue"  : self.bt_restart_game,
+			"cancel": self.quit,
+			"deleteForward" : self.next_pressed,
+			"deleteBackward": self.previous_pressed,
+		})
+		# fill canvas with background color...
+		self["Canvas"].fill(0, 0, 354, 354, bgcolor)
+
+		self.board_cells = []
+		self.board_values= []
+		# ToDo: change for HD Skins...
+		GROUP_SIZE	= 108
+		CELL_SIZE	= 35
+		CELL_OFFSET	= 4
+
+		for j in range(9):
+			tmp = []
+			for i in range(9):
+				cell = SudokuCell(self["Canvas"],
+								  j * (CELL_SIZE + CELL_OFFSET) + (j / 3) * (GROUP_SIZE - 3 * CELL_SIZE),
+								  i * (CELL_SIZE + CELL_OFFSET) + (i / 3) * (GROUP_SIZE - 3 * CELL_SIZE),
+								  CELL_SIZE, CELL_SIZE)
+				tmp.append(cell)
+			self.board_cells.append(tmp)
+
+		row = [0,0,0,0,0,0,0,0,0]
+		for i in range(0, 9):
+			self.board_values.append(row[:])
+
+		self.onLayoutFinish.append(self.load_game)
+
+
+	def bt_0_pressed(self):
+		self.key_event1(0)
+
+
+	def bt_1_pressed(self):
+		self.key_event1(1)
+
+
+	def bt_2_pressed(self):
+		self.key_event1(2)
+
+
+	def bt_3_pressed(self):
+		self.key_event1(3)
+
+
+	def bt_4_pressed(self):
+		self.key_event1(4)
+
+
+	def bt_5_pressed(self):
+		self.key_event1(5)
+
+
+	def bt_6_pressed(self):
+		self.key_event1(6)
+
+
+	def bt_7_pressed(self):
+		self.key_event1(7)
+
+
+	def bt_8_pressed(self):
+		self.key_event1(8)
+
+
+	def bt_9_pressed(self):
+		self.key_event1(9)
+
+
+	def key_event1(self, key):
+		cell = self.board_cells[self.xFocus][self.yFocus]
+		if not cell.readonly():
+			cell.setValue(key)
+			cell.color(1) #grey
+			cell.paint()
+			self.check_game(False)
+
+
+	def up_pressed(self):
+		if self.yFocus > 0:
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(False)
+			cell.paint()
+			self.yFocus = self.yFocus-1
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(True)
+			cell.paint()
+
+
+	def down_pressed(self):
+		if self.yFocus < 8:
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(False)
+			cell.paint()
+			self.yFocus = self.yFocus+1
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(True)
+			cell.paint()
+
+
+	def left_pressed(self):
+		if self.xFocus > 0:
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(False)
+			cell.paint()
+			self.xFocus = self.xFocus-1
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(True)
+			cell.paint()
+
+
+	def right_pressed(self):
+		if self.xFocus < 8:
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(False)
+			cell.paint()
+			self.xFocus = self.xFocus+1
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(True)
+			cell.paint()
+
+
+	def next_pressed(self):
+		self.session.openWithCallback(self.next_pressedCallback, MessageBox, _("Change the game level and start new game?"))
+
+
+	def next_pressedCallback(self, result):
+		if result:
+			self.gameLevel += 1
+			if self.gameLevel > 3:
+				self.gameLevel = 0
+			self.setGamelLevelLabel()
+			self.new_game()
+
+
+	def previous_pressed(self):
+		self.session.openWithCallback(self.previous_pressedCallback, MessageBox, _("Change the game level and start new game?"))
+
+
+	def previous_pressedCallback(self, result):
+		if result:
+			self.gameLevel -= 1
+			if self.gameLevel < 0:
+				self.gameLevel = 3
+			self.setGamelLevelLabel()
+			self.new_game()
+
+
+	def setGamelLevelLabel(self):
+		if self.gameLevel == 0:
+			self["gamelevel"].setText("<     easy     >")
+		elif self.gameLevel == 1:
+			self["gamelevel"].setText("<   medium   >")
+		elif self.gameLevel == 2:
+			self["gamelevel"].setText("<     hard     >")
+		elif self.gameLevel == 3:
+			self["gamelevel"].setText("< impossible >")
+
+
+	def bt_new_game(self):
+		self.new_game()
+
+
+	def bt_check_game(self):
+		self.cnt += 100
+		self.check_game(True)
+
+
+	def bt_restart_game(self):
+		self.restart_game()
+
+
+	def bt_solve_game(self):
+		self.solve_game()
+
+
+	def quit(self):
+		self.timer.stop()
+		self.save_game()
+		self.close()
+
+
+	# displays time in title...
+	def timerHandler(self):
+		if self.cnt > 0:
+			self.instance.setTitle("Sudoku 0.1 %10d sec" % self.cnt)
+			self.cnt += 1
+		else:
+			self.instance.setTitle("Sudoku 0.1")
+
+
+	# look for wrong cells...
+	def check_game(self, highlight):
+		empty = False;
+		correct = True;
+	
+		for j in range(0, 9):
+			for i in range(0, 9):
+				cell = self.board_cells[i][j]
+				val = cell.value()
+	
+				if cell.readonly():
+					continue
+	
+				if not val:
+					empty = True
+				else:
+					err = False
+					for k in range(0, 9):
+						if ((i != k	and self.board_cells[k][j].value() == val) or (j != k and self.board_cells[i][k].value() == val)):
+							err = True
+							break
+	
+					if err:
+						if highlight:
+							cell.color(3) #red
+							cell.paint()
+	
+						correct	= False
+
+					elif highlight:
+						cell.color(1) #grey
+						cell.paint()	
+	
+		if not empty and correct:
+			self.timer.stop()
+			for j in range(0, 9):
+				for i in range(0, 9):
+					cell = self.board_cells[i][j]
+					cell.color(2) #green
+					cell.paint()
+					cell.setReadonly(True)
+
+
+	# create new game...
+	def new_game(self):
+		cell = self.board_cells[self.xFocus][self.yFocus]
+		cell.setFocus(True)
+
+		b = board()
+		del b.boardlist[:]
+		del b.partialboardlist[:]
+		n =	11 * (5 - self.gameLevel)
+		#n = 80
+		b.generate(n)
+		self.board_values = b.boardlist
+		for j in range(0, 9):
+			for i in range(0, 9):
+				cell = self.board_cells[i][j]
+				cell.setValue(b.partialboardlist[i][j])
+				if b.partialboardlist[i][j] == 0:
+					cell.setReadonly(False)
+					cell.color(1) #grey
+				else:
+					cell.setReadonly(True)
+					cell.color(0) #black
+				cell.paint()
+
+		self.cnt = 1
+		self.timer.start(1000)
+
+
+	# Restart game...
+	def restart_game(self):
+		solved = True
+		
+		for j in range(0, 9):
+			for i in range(0, 9):
+				cell = self.board_cells[i][j]
+	
+				if not cell.readonly():
+					solved = False
+					cell.color(1) #grey
+					cell.setValue(0)
+					cell.paint()
+
+		if solved:
+			self.new_game()
+
+
+	# display all values and stop game...
+	def solve_game(self):
+		self.cnt=0;
+		for j in range(0, 9):
+			for i in range(0, 9):
+				cell = self.board_cells[i][j]
+	
+				cell.setValue(self.board_values[i][j])
+				cell.setReadonly(True)
+				cell.color(0) #black
+				cell.paint()
+
+
+	# save actual game to file...
+	def save_game(self):
+		sav = open(SAVEFILE, "w")
+		sav.write( "%d %d\n" % (self.gameLevel, self.cnt) )
+
+		for j in range(0, 9):
+			for i in range(0, 9):
+				sav.write("%d %d %d\n" % (self.board_values[i][j], self.board_cells[i][j].value(), self.board_cells[i][j].readonly()))
+
+		sav.close()
+
+
+	# load game from file...
+	def load_game(self):
+		solved = True
+
+		if fileExists(SAVEFILE, "r"):
+			sav = open(SAVEFILE, "r")
+			inp = sav.readline()
+			inplist = inp.split()
+			
+			self.gameLevel = int(inplist[0])
+			self.cnt = int(inplist[1])
+	
+			for j in range(0, 9):
+				for i in range(0, 9):
+					inp = sav.readline()
+					inp = inp.strip()
+					inplist = inp.split()
+					self.board_values[i][j] = int(inplist[0])
+					cell = self.board_cells[i][j]
+					cell.setValue(int(inplist[1]))
+					cell.setReadonly(int(inplist[2]))
+					if cell.readonly():
+						cell.color(0) # black
+					else:
+						cell.color(1) # grey
+						solved = False
+					cell.paint()
+
+			sav.close()
+
+		if solved:
+			self.new_game()
+		else:
+			cell = self.board_cells[self.xFocus][self.yFocus]
+			cell.setFocus(True)
+			cell.paint()
+			self.check_game(False)
+			self.setGamelLevelLabel()
+		self.timer.start(1000)
Index: /ipk/source/swapinfos_buliticker_1_0/var/swap/extensions/Buliticker/plugin.py
===================================================================
--- /ipk/source/swapinfos_buliticker_1_0/var/swap/extensions/Buliticker/plugin.py	(revision 5870)
+++ /ipk/source/swapinfos_buliticker_1_0/var/swap/extensions/Buliticker/plugin.py	(revision 5870)
@@ -0,0 +1,986 @@
+# -*- coding: utf-8 -*-
+#
+#		Fußball Liveticker für die 1./2.Bundesliga 
+#
+# 	Quelle: http://linpop.zdf.de/sport/bl1/konferenz-sub.htm
+#
+#	V1.0 13.04.09 
+#
+# V1.0a 17.04.09 Fehler gefixt ; Konferenz-URL geändert ; geänderte Ergebnisse farbig
+#
+# V1.0b 18.04.09 Unterkanäle Auswahl hinzugefügt (grüne Taste)
+#
+# V1.0c 18.04.09 Fehler im Tickertext gefixt
+#
+# Enigma2 Plugin 
+#
+# Author: barabas
+#
+
+import os, sys
+
+from Plugins.Plugin import PluginDescriptor
+from twisted.web.client import getPage
+from twisted.internet import reactor
+from Screens.Screen import Screen
+from Screens.Console import Console
+from Screens.MessageBox import MessageBox
+from Screens.InputBox import InputBox
+from Screens.ChoiceBox import ChoiceBox
+from Screens.ChannelSelection import ChannelSelection
+from Screens.InfoBarGenerics import InfoBarSubserviceSelection
+from Screens.SubservicesQuickzap import SubservicesQuickzap
+from Components.ActionMap import ActionMap
+from Components.Label import Label
+from Components.Sources.List import List
+from Components.MenuList import MenuList
+from Components.config import config, ConfigSubsection, ConfigText, configfile
+from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
+from Components.Pixmap import Pixmap, MovingPixmap
+from Components.AVSwitch import AVSwitch
+from enigma import eTimer, getDesktop, eListboxPythonMultiContent, eListbox, gFont, RT_HALIGN_LEFT, RT_HALIGN_RIGHT, RT_HALIGN_CENTER
+from re import sub, split, search, match, findall
+from string import find, strip
+from Tools.LoadPixmap import LoadPixmap
+
+def transHTML(text):
+	text = text.replace('&nbsp;'," ").replace('&#39;',"'").replace('&szlig;',"ß").replace('&quot;','"').replace('&ndash;',"-")	
+	text = text.replace('&copy;.*'," ").replace('&amp;',"&").replace('&uuml;',"ü").replace('&auml;',"ä").replace('&ouml;',"ö")
+	text = text.replace('&Uuml;',"Ü").replace('&Auml;',"Ä").replace('&Ouml;',"Ö")				
+	return text
+
+refreshtimer = 15000
+screenhidetimer = 15000
+try:
+		size_w = int(getDesktop(0).size().width())
+		size_h = int(getDesktop(0).size().height())
+except:
+		size_w = 1280
+		size_h = 720
+
+config.plugins.buliticker = ConfigSubsection()
+config.plugins.buliticker.link = ConfigText(default="http://linpop.zdf.de/sport/bl1/konferenz.htm", fixed_size = False)
+config.plugins.buliticker.actmenu = ConfigText(default="ergmenu", fixed_size = False)
+
+###############################################################################  
+# backgroundColor="#c9deb7"
+# scrollbarMode="showOnDemand"
+
+#				<eLabel zPosition="1" position="28,93" size="502,459" backgroundColor="#c9deb7" />
+#				<eLabel zPosition="1" position="548,93" size="500,234" backgroundColor="#c9deb7" />
+class ShowFullTicker(Screen):
+		
+		if size_w == 1280:
+				skin = """
+				<screen name="ShowTicker" position="5,3" size="1270,712" title="Buli FullTicker" flags="wfNoBorder">
+				<ePixmap position="5,7" size="1270,710"  zPosition="-10" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/Buliticker/zdftickerback.png" transparent="1" />
+				<widget source="global.CurrentTime" render="Label" position="850,505" size="280,22" font="Regular;20" halign="right" foregroundColor="black" transparent="1">
+					<convert type="ClockToText">Date</convert>
+				</widget>
+				<widget source="global.CurrentTime" render="Label" position="1140,505" size="80,22" font="Regular;20" halign="left" foregroundColor="black" transparent="1">
+					<convert type="ClockToText">Default</convert>
+				</widget>
+			  <widget name="0_menu" zPosition="2" position="30,95" size="500,447" transparent="1" foregroundColor="black" />
+				<widget name="tablabel" zPosition="2" position="100,280" size="440,25" font="Regular;22" halign="left" foregroundColor="black" transparent="1"/>
+				<widget name="1_menu" zPosition="2" position="550,95" size="500,225" transparent="1" foregroundColor="black" />
+				<widget name="erglabel" zPosition="2" position="600,100" size="440,25" font="Regular;22" halign="left" foregroundColor="black" transparent="1"/>
+				<eLabel zPosition="2" position="5,531" size="1270,2" backgroundColor="black" />
+				<widget name="2_menu" zPosition="2" position="20,535" size="1240,165" transparent="1" foregroundColor="black" />
+				<eLabel zPosition="1" position="5,535" size="1270,180" backgroundColor="#f4fcfc" />
+				<widget name="tickerlabel" zPosition="2" position="520,610" size="440,25" font="Regular;22" halign="left" foregroundColor="black" transparent="1" />
+				<widget name="statuslabel" zPosition="2" position="620,480" size="440,25" font="Regular;22" halign="left" foregroundColor="black" transparent="1" />
+			</screen>"""
+		else:
+#				<eLabel zPosition="1" position="8,73" size="392,372" backgroundColor="#c9deb7" />
+# 			<eLabel zPosition="1" position="413,73" size="292,230" backgroundColor="#c9deb7" />
+				skin = """
+				<screen name="ShowTicker" position="5,3" size="710,568" title="Buli FullTicker" flags="wfNoBorder">
+				<ePixmap position="5,5" size="710,560"  zPosition="-10" pixmap="/usr/lib/enigma2/python/Plugins/Extensions/Buliticker/zdftickerback_sd.png" transparent="1" />
+				<widget source="global.CurrentTime" render="Label" position="420,432" size="200,20" font="Regular;17" halign="right" foregroundColor="black" transparent="1">
+					<convert type="ClockToText">Date</convert>
+				</widget>
+				<widget source="global.CurrentTime" render="Label" position="630,432" size="80,20" font="Regular;17" halign="left" foregroundColor="black" transparent="1">
+					<convert type="ClockToText">Default</convert>
+				</widget>
+				
+			  <widget name="0_menu" zPosition="2" position="10,75" size="370,370" transparent="1" foregroundColor="black" />
+
+				<widget name="tablabel" zPosition="2" position="50,275" size="440,25" font="Regular;20" halign="left" foregroundColor="black" transparent="1"/>
+	
+				<widget name="1_menu" zPosition="2" position="385,75" size="310,225" transparent="1" foregroundColor="black" />
+
+				<widget name="erglabel" zPosition="2" position="500,95" size="200,25" font="Regular;20" halign="left" foregroundColor="black" transparent="1"/>
+	
+				<eLabel zPosition="2" position="5,453" size="710,2" backgroundColor="black" />
+	
+				<widget name="2_menu" zPosition="2" position="20,456" size="690,115" transparent="1" foregroundColor="black" />
+				<eLabel zPosition="1" position="5,456" size="705,115" backgroundColor="#f4fcfc" />
+				<widget name="tickerlabel" zPosition="2" position="250,510" size="340,25" font="Regular;20" halign="left" foregroundColor="black" transparent="1" />
+				<widget name="statuslabel" zPosition="2" position="385,380" size="340,25" font="Regular;20" halign="left" foregroundColor="black" transparent="1" />
+			</screen>"""
+			
+		def __init__(self, session):
+				self.loadinginprogress = False
+				self.skin = ShowFullTicker.skin
+				Screen.__init__(self, session)
+				
+				print "----> %d" % size_w
+				print "----> %d" % size_h
+		
+				self.baseurl = "http://linpop.zdf.de/sport/"
+				self.lastbulilink = pluginpath + "/lastbulilink.txt"	
+				self.hideflag = True
+				self.tableentries = []
+				self.linklist = []
+				self.menunr = 2
+				self.index = 1
+				self.buli = ""
+				self.ergold = []
+				self.tickerold = ""
+				
+				self.servicelist = self.session.instantiateDialog(ChannelSelection)
+			
+				self["0_menu"] = ItemList([])
+				self["1_menu"] = ItemList([])
+				self["2_menu"] = ItemList([])
+				
+				self.actmenu = "2_menu"				
+				self["erglabel"] = Label("")
+				self["tablabel"] = Label("")
+				self["tickerlabel"] = Label("")
+				self["statuslabel"] = Label("")
+				self["actions"] = ActionMap(["ColorActions","OkCancelActions","DirectionActions","HelpActions","MovieSelectionActions","InputActions"],
+				{
+					"1": self.loadBuli1,
+					"2": self.loadBuli2,
+					"3": self.tester,
+					"green": self.subService,
+					"ok":	self.ok,
+					"cancel": self.exit,
+					"right": self.pageDown,
+					"left": self.pageUp,
+					"up": self.up,
+					"down": self.down,
+#  				"contextMenu": self.switchMenu,
+					"showEventInfo": self.miniView,
+					"displayHelp": self.hideScreen,
+				}, -1)	
+				
+				self.konfurl = config.plugins.buliticker.link.value
+
+				if search("/bl1/",self.konfurl) is not None:
+						self.buli = "bl1"
+				else:
+						self.buli = "bl2"
+
+ 				self.screenHideTimer = eTimer()
+				self.screenHideTimer.callback.append(self.hideTimerAction)
+
+ 				self.refreshInfoTimer = eTimer()
+				self.refreshInfoTimer.callback.append(self.timerAction)
+				self.refreshInfoTimer.start(refreshtimer)
+
+				self.StartTimer = eTimer()
+				self.StartTimer.callback.append(self.download(self.konfurl,self.getLiveContent))
+				self.StartTimer.start(500)
+
+# geklaut aus InfoBarGenerics.py 
+
+		def subService(self):
+				if not self.hideflag:
+						service = self.session.nav.getCurrentService()
+						subservices = service and service.subServices()
+						n = subservices and subservices.getNumberOfSubservices()
+						selection = 0
+						print "---> %s" % n
+						if n and n > 0:
+							ref = self.session.nav.getCurrentlyPlayingServiceReference()
+							tlist = []
+							for x in range(n):
+								i = subservices.getSubservice(x)
+								if i.toString() == ref.toString():
+									selection = x
+								tlist.append((i.getName(), i))
+							tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
+							keys = ["red", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
+							selection += 2
+							self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
+
+							#self.session.openWithCallback(self.timerAction,SubservicesQuickzap, "quickzap")
+
+		def subserviceSelected(self, service):
+			if not service is None:
+				if not isinstance(service[1], str):
+					self.session.nav.playService(service[1], False)
+				
+						
+		def tester(self):
+#				self.ergold.append("neuer text")
+				self.tickerold = "test"
+												
+		def timerAction(self):
+				print "-----> ShowFullView Timer fired"
+				self.download(self.konfurl,self.getLiveContent)
+				self.refreshInfoTimerRestart()
+
+		def hideTimerAction(self):
+				print "-----> ScreenHide Timer fired"
+				if self.hideflag == True:
+						self.hideScreen()
+
+		def refreshInfoTimerRestart(self):
+				if self.refreshInfoTimer.isActive:
+						self.refreshInfoTimer.stop()
+				print "-----> ShowFullView Timer restart"
+				self.refreshInfoTimer.start(refreshtimer)
+
+		def hideTimerRestart(self):
+				if self.screenHideTimer.isActive:
+						self.screenHideTimer.stop()
+				print "-----> ScreenHide Timer restart"
+				self.screenHideTimer.start(screenhidetimer)
+																														
+		def miniView(self):
+				if self.hideflag:
+						self.refreshInfoTimer.stop()
+						self.screenHideTimer.stop()
+						self.session.openWithCallback(self.timerAction,ShowMiniTicker, self.konfurl)			
+														
+		def loadBuli1(self):
+				self.buli = "bl1"
+				self.konfurl = self.baseurl + "bl1/konferenz.htm"
+				self.timerAction()
+				self.hideTimerRestart()
+				
+		def loadBuli2(self):
+				self.buli = "bl2"
+				self.konfurl = self.baseurl + "bl2/konferenz.htm"	
+				self.timerAction()					
+				self.hideTimerRestart()
+						
+		def ok(self):
+				if self.hideflag:
+						if self.actmenu == "1_menu":
+								self.index = self[self.actmenu].getSelectedIndex()
+								self.konfurl = self.linklist[self.index]
+								self.timerAction()
+						else:
+								self.timerAction()
+																	
+		def up(self):
+				if not self.hideflag:
+						self.servicelist.moveUp()
+						self.session.execDialog(self.servicelist)
+				else:
+						self[self.actmenu].up()
+						self.hideTimerRestart()
+						self.refreshInfoTimerRestart()
+				
+		def down(self):
+				if not self.hideflag:
+						self.servicelist.moveDown()
+						self.session.execDialog(self.servicelist)
+				else:	
+						self[self.actmenu].down()
+						self.hideTimerRestart()
+						self.refreshInfoTimerRestart()
+				
+		def pageUp(self):
+				if not self.hideflag:
+						self.servicelist.moveUp()
+						self.servicelist.zap()
+				else:
+						self[self.actmenu].pageUp()
+						self.hideTimerRestart()
+						self.refreshInfoTimerRestart()
+				
+		def pageDown(self):
+				if not self.hideflag:
+						self.servicelist.moveDown()
+						self.servicelist.zap()
+				else:
+						self[self.actmenu].pageDown()
+						self.hideTimerRestart()
+						self.refreshInfoTimerRestart()
+																
+		def switchMenu(self):				
+				if self.menunr == 2:
+						# nur zwischen Erg. und Liveticker Menu wechseln
+						self.menunr = 1					
+				else:
+						self.menunr +=1	
+				self.actmenu = str(self.menunr) + "_menu"
+				if self.menunr == 2:
+						self["0_menu"].selectionEnabled(0)
+						self["1_menu"].selectionEnabled(0)
+				elif self.menunr == 1:
+						self["0_menu"].selectionEnabled(0)
+						self["2_menu"].selectionEnabled(0)
+				elif self.menunr == 0:
+						self["1_menu"].selectionEnabled(0)
+						self["2_menu"].selectionEnabled(0)																	
+				
+				self[self.actmenu].selectionEnabled(1)
+ 						
+		def getLiveContent(self,output):
+				self.loadinginprogress = False
+				self["statuslabel"].setText("")
+				self["0_menu"].l.setList([])
+				self["1_menu"].l.setList([])
+				self["2_menu"].l.setList([])
+					
+ 				self["0_menu"].selectionEnabled(0)
+ 				self["1_menu"].selectionEnabled(0)
+ 				self["2_menu"].selectionEnabled(1)
+ 				self.actmenu = "2_menu"				
+# 				if self.actmenu == "1_menu":
+# 						self[self.actmenu].moveToIndex(self.index)
+
+				self["erglabel"].setText("")
+				self["tablabel"].setText("")
+				self["tickerlabel"].setText("")
+				
+				output = output.decode("latin1").encode("utf-8")
+							
+				if size_w == 1280:
+						self["0_menu"].l.setItemHeight(22)
+						self["1_menu"].l.setItemHeight(25)
+						self["2_menu"].l.setItemHeight(55)
+						fontidx = 0
+						ysize = 22
+						axsize = 300
+						bxsize = 100
+						cxsize = 25
+						dxsize = 250
+						exsize = 25
+						fxsize = 80
+						gxsize = 35
+						afontticker = -1
+						bfontticker = 0
+						xsizeticker = 1120
+						ysizeticker = 25
+				else:
+						self["0_menu"].l.setItemHeight(20)
+						self["1_menu"].l.setItemHeight(22)
+						self["2_menu"].l.setItemHeight(55)
+						fontidx = 1
+						ysize = 20
+						axsize = 200
+						bxsize = 80
+						cxsize = 20
+						dxsize = 200
+						exsize = 20
+						fxsize = 60
+						gxsize = 20
+						afontticker = 0
+						bfontticker = 1
+						xsizeticker = 610	
+						ysizeticker = 25
+						
+				# Live Ergebnisse
+				self.tableentries = []
+				startpos = find(output,'<!-- Events -->')
+				if startpos == -1:
+						self["erglabel"].setText("Keine Ergebnisse gefunden!")
+				else:		
+						endpos = find(output,'<!-- /Events --> ')
+						bereich = output[startpos:endpos]
+						bereich = transHTML(bereich)
+						bereich = sub("</td>\s*\n","</td>",bereich)
+						bereich = sub('<a href="',"MARK:" + self.baseurl + self.buli + "/",bereich)
+						bereich = bereich.replace('</a>',"").replace('class="eventP">',"MARK:").replace('class="eventLive">',"MARK:")
+						erg = findall(r'MARK:(.*?)["<]',bereich)
+
+						if len(erg) == 0:
+								self["erglabel"].setText("Keine Ergebnisse gefunden!")
+						else:								
+								# 'http://linpop.zdf.de/sport/bl1/event20129.htm', 'Bielefeld - Schalke', '0:2 (0:1)'
+								y = 0								
+								offset = 3
+								for x in erg:
+										if y == 0:
+												res = [ x ]
+												self.linklist.append(x)
+										if y == 1:
+												res.append(MultiContentEntryText(pos=(20, 0), size=(axsize, ysize), font=fontidx, flags = RT_HALIGN_LEFT, text=x))							
+										if y == 2:
+												res.append(MultiContentEntryText(pos=(axsize+20, 0), size=(bxsize, ysize), font=fontidx, flags = RT_HALIGN_RIGHT, text=x))
+												self.tableentries.append(res)						
+										y +=1
+										if y == offset:
+												y = 0			
+								self["1_menu"].l.setList(self.tableentries)
+
+				# Blitztabelle
+				self.tableentries = []
+				startpos = find(output,'<!-- Blitztabelle -->')
+				if startpos == -1:
+						self["tablabel"].setText("Keine Blitztabelle gefunden!")
+				else:
+						endpos = find(output,'<!-- /Blitztabelle -->')
+						bereich = output[startpos:endpos]
+						bereich = transHTML(bereich)
+		
+						bereich = sub("</td>\s*\n","</td>",bereich)
+						bereich = sub('<img src=.*?/>',"",bereich)
+						
+						a = findall(r'>(.*?)</td>',bereich)
+						# '1', 'VfL Wolfsburg', '26', '58:32', '51'
+						if len(a) == 0:
+								self["tablabel"].setText("Keine Blitztabelle gefunden!")
+						else:																		
+								y = 0								
+								offset = 5
+								for x in a:
+										if y == 0:
+												res = [ x ]
+												res.append(MultiContentEntryText(pos=(10, 0), size=(cxsize, ysize), font=fontidx, flags = RT_HALIGN_RIGHT, text=x))
+										if y == 1:
+												res.append(MultiContentEntryText(pos=(cxsize+20, 0), size=(dxsize, ysize), font=fontidx, flags = RT_HALIGN_LEFT, text=x))							
+										if y == 2:
+												res.append(MultiContentEntryText(pos=(dxsize+cxsize+30, 0), size=(exsize, ysize), font=fontidx, flags = RT_HALIGN_RIGHT, text=x))
+										if y == 3:
+												res.append(MultiContentEntryText(pos=(dxsize+cxsize+exsize+35, 0), size=(fxsize, ysize), font=fontidx, flags = RT_HALIGN_RIGHT, text=x))
+										if y == 4:
+												res.append(MultiContentEntryText(pos=(dxsize+cxsize+exsize+fxsize+40, 0), size=(gxsize, ysize), font=fontidx, flags = RT_HALIGN_RIGHT, text=x))		
+												self.tableentries.append(res)						
+										y +=1
+										if y == offset:
+												y = 0			
+								self["0_menu"].l.setList(self.tableentries)
+
+				# Liveticker
+				self.tableentries = []
+				minute = []
+				bild = []
+				paarung = []
+				text = []
+				startpos = find(output,'<!-- rechte Spalte -->')
+				if startpos == -1:
+						self["tickerlabel"].setText("Kein Liveticker gefunden!")
+				else:				
+						endpos = find(output,'<!-- /rechte Spalte -->')
+						bereich = output[startpos:endpos]
+						bereich = transHTML(bereich)
+						# falls kein Bild -> Dummy Eintrag 
+						bereich = sub('<div class="minute">.*?</div>\n','<div class="minute"></div><img src="pics/dummy.gif" alt="Dummy" class="message-type">',bereich)
+						minute = findall(r'<div class="minute">(.*?)</div>',bereich)
+						if len(minute) == 0:
+								self["tickerlabel"].setText("Kein Liveticker gefunden!")
+						else:	
+								bild = findall(r'<img src="pics/(.*?).gif',bereich)
+								# Paarung nur bei Konferenz
+								if search("event",self.konfurl) is not None:
+										for x in minute:
+												paarung.append(" ")
+								else:					
+										paarung = findall(r'class="message-header">(.*?)</a>',bereich)
+								text =  findall(r'<p>.*?\s*(.*?)</p>',bereich)
+								textnr = len(text)
+								y = 0
+								a = []				
+								for x in text:
+										#print "---> %s %s %s" % (x,text[y],paarung[y])
+										text[y] = sub("<[^>]*>","",text[y])
+										a.append((bild[y],minute[y],paarung[y],strip(text[y])))
+										y +=1						 					
+								# ('halbzeit_gr', '', 'Ingolstadt - Wehen', 'Abpfiff durch T. Metzen, der Endstand lautet 0:0.    ')
+								for pic, time, spiel, livetext in a:
+										if time == "":
+												time = "--"		
+										x = "%s ( %s min. / %d )" % (spiel,time,textnr)
+										res = [ x ]
+										if pic != "dummy":
+												png = LoadPixmap(pluginpath + "/icons/" + pic + ".png")
+												res.append(MultiContentEntryPixmapAlphaTest(pos=(0, 0), size=(55, 55), png = png))
+										res.append(MultiContentEntryText(pos=(70, 0), size=(xsizeticker, ysizeticker), font=afontticker, flags = RT_HALIGN_LEFT, text=x))
+										res.append(MultiContentEntryText(pos=(70, ysizeticker+1), size=(xsizeticker, ysizeticker), font=bfontticker, flags = RT_HALIGN_LEFT, text=livetext))		
+										self.tableentries.append(res)						
+										textnr -=1
+								self["2_menu"].l.setList(self.tableentries)						
+
+								# falls neue Ergebnisse oder neuer Tickerttext -> Screen anzeigen			
+								if ( self.ergold != erg or self.tickerold != text[0] )  and self.hideflag == False:
+										self.hideScreen()
+								self.ergold = erg
+								self.tickerold = text[0]
+							
+							
+		def download(self, link, name):
+				self.loadinginprogress = True
+				getPage(link).addCallback(name).addErrback(self.downloadError)
+						
+		def downloadError(self,output):
+				self.loadinginprogress = False
+				self["statuslabel"].setText("Fehler beim Download")			
+		
+		def hideScreen(self):
+				if self.hideflag == True:
+						self.hideflag = False
+						self.screenHideTimer.stop()
+						self.hide()
+				else:
+						self.hideflag = True
+						self.screenHideTimer.start(screenhidetimer)
+						self.show()
+	
+		def exit(self):
+				if self.loadinginprogress:
+						reactor.callLater(1,self.exit)
+				else:
+						config.plugins.buliticker.link.value = self.konfurl
+						config.plugins.buliticker.link.save()
+						configfile.save()
+						self.close()
+
+
+#####################################
+#	<eLabel zPosition="1" position="0,540" size="1280,170" backgroundColor="white" />
+# scrollbarMode="showOnDemand"
+class ShowMiniTicker(Screen):
+
+		if size_w == 1280:
+				skin = """
+			  <screen name="ShowTicker" position="0,626" size="1280,80" title="Buli MiniTicker" transparent="0" flags="wfNoBorder">
+			  <widget name="ergmenu" zPosition="1" position="20,0" size="1240,80" transparent="1" foregroundColor="white" />
+			  <widget name="tickermenu" zPosition="1" position="15,0" size="1260,80" transparent="1" foregroundColor="white" />
+				<widget name="tickerlabel" zPosition="1" position="520,20" size="440,25" font="Regular;22" halign="left" foregroundColor="white" transparent="1" />
+				</screen>"""
+		else:
+				skin = """
+			  <screen name="ShowTicker" position="0,495" size="720,80" title="Buli MiniTicker" transparent="0" flags="wfNoBorder">
+			  <widget name="ergmenu" zPosition="1" position="5,0" size="715,80" transparent="1" foregroundColor="white" />
+				<widget name="tickermenu" zPosition="2" position="5,0" size="715,80" transparent="1" foregroundColor="white" />
+				<widget name="tickerlabel" zPosition="2" position="280,30" size="340,25" font="Regular;20" halign="left" foregroundColor="white" transparent="1" />
+				</screen>"""
+					
+		def __init__(self, session, link):
+				self.loadinginprogress = False
+				self.skin = ShowMiniTicker.skin
+				Screen.__init__(self, session)
+				
+				self.baseurl = "http://linpop.zdf.de/sport/"				
+				self.hideflag = True
+				self.tableentries = []
+				self.ergold = []
+				self.tickerold = ""
+				self.konfurl = link
+				self.servicelist = self.session.instantiateDialog(ChannelSelection)
+				
+				self["ergmenu"] = ItemList([])
+				self["tickermenu"] = ItemList([])
+
+				self.actmenu = config.plugins.buliticker.actmenu.value
+
+				self["tickerlabel"] = Label("")
+				self["actions"] = ActionMap(["ColorActions","OkCancelActions","DirectionActions","HelpActions","MovieSelectionActions","InputActions"],
+				{
+					"1": self.loadBuli1,
+					"2": self.loadBuli2,
+					"3": self.tester,
+					"green": self.subService,
+					"ok":	self.ok,
+					"cancel": self.exit,
+					"right": self.zapDown,
+					"left": self.zapUp,
+					"up": self.up,
+					"down": self.down,
+					"showEventInfo": self.switchMenu,
+ 					"displayHelp": self.hideScreen,
+				}, -1)	
+
+				if search("/bl1/",self.konfurl) is not None:
+							self.buli = "bl1"
+				else:
+							self.buli = "bl2"
+										
+ 				self.screenHideTimer = eTimer()
+				self.screenHideTimer.callback.append(self.hideTimerAction)
+				self.screenHideTimer.start(screenhidetimer)
+							
+ 				self.refreshInfoTimer = eTimer()
+				self.refreshInfoTimer.callback.append(self.timerAction)
+				
+				self.onShown.append(self.loadMenu)	
+
+		def subService(self):
+				service = self.session.nav.getCurrentService()
+				subservices = service and service.subServices()
+				n = subservices and subservices.getNumberOfSubservices()
+				selection = 0
+				print "---> %s" % n
+				if n and n > 0:
+						ref = self.session.nav.getCurrentlyPlayingServiceReference()
+						tlist = []
+						for x in range(n):
+							i = subservices.getSubservice(x)
+							if i.toString() == ref.toString():
+								selection = x
+							tlist.append((i.getName(), i))
+						tlist = [(_("Quickzap"), "quickzap", service.subServices()), ("--", "")] + tlist
+						keys = ["red", "",  "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" ] + [""] * n
+						selection += 2
+						self.session.openWithCallback(self.subserviceSelected, ChoiceBox, title=_("Please select a subservice..."), list = tlist, selection = selection, keys = keys)
+	
+						#self.session.openWithCallback(self.timerAction,SubservicesQuickzap, "quickzap")
+
+		def subserviceSelected(self, service):
+			if not service is None:
+				if not isinstance(service[1], str):
+					self.session.nav.playService(service[1], False)
+							
+		def tester(self):
+				self.ergold[2]="3:3"
+#				self.tickerold = "test"
+
+		def hideTimerAction(self):
+				print "-----> ScreenHide Timer fired"
+				if self.hideflag == True:
+						self.hideScreen()
+						
+		def timerAction(self):
+				print "-----> ShowMiniView timer fired"
+				self.download(self.konfurl,self.getLiveContent)
+				self.refreshInfoTimerRestart()
+
+		def refreshInfoTimerRestart(self):
+				if self.refreshInfoTimer.isActive:
+						self.refreshInfoTimer.stop()
+				print "-----> ShowMiniView Timer restart"
+				self.refreshInfoTimer.start(refreshtimer)
+
+		def hideTimerRestart(self):
+				if self.screenHideTimer.isActive:
+						self.screenHideTimer.stop()
+				print "-----> ScreenHide Timer restart"
+				self.screenHideTimer.start(screenhidetimer)
+
+		def loadMenu(self):
+				self.hideTimerRestart()
+				self.refreshInfoTimerRestart()
+				self.download(self.konfurl,self.getLiveContent)
+				self["ergmenu"].selectionEnabled(0)
+				if self.actmenu == "ergmenu":
+						self["ergmenu"].show()
+						self["tickermenu"].hide()
+						self["tickerlabel"].hide()
+						self["tickermenu"].selectionEnabled(0)
+				elif self.actmenu == "tickermenu":
+						self["tickerlabel"].show()
+						self["tickermenu"].selectionEnabled(1)
+						self["tickermenu"].show()
+						self["ergmenu"].hide()
+				if self.hideflag == False:
+						self.hideScreen()
+																					
+		def switchMenu(self):
+				self.hideTimerRestart()
+				self.refreshInfoTimerRestart()
+				self.download(self.konfurl,self.getLiveContent)
+				self["ergmenu"].selectionEnabled(0)
+				if self.actmenu == "ergmenu":
+						self.actmenu = "tickermenu"
+						self["ergmenu"].hide()
+						self["tickermenu"].show()
+						self["tickerlabel"].show()
+						self["tickermenu"].selectionEnabled(1)
+				elif self.actmenu == "tickermenu":
+						self.actmenu = "ergmenu"
+						self["tickerlabel"].hide()
+						self["tickermenu"].selectionEnabled(0)
+						self["tickermenu"].hide()
+						self["ergmenu"].show()
+				if self.hideflag == False:
+						self.hideScreen()
+																
+		def loadBuli1(self):
+				self.buli = "bl1"
+				self.konfurl = self.baseurl + "bl1/konferenz.htm"
+				self.ergold = []
+				self.timerAction()
+				self.hideTimerRestart()
+				
+		def loadBuli2(self):
+				self.buli = "bl2"
+				self.konfurl = self.baseurl + "bl2/konferenz.htm"	
+				self.ergold = []
+				self.timerAction()				
+				self.hideTimerRestart()
+						
+		def ok(self):
+				pass
+											
+		def up(self):
+				self.screenHideTimer.stop()
+				if not self.hideflag or ( self.hideflag and self.actmenu == "ergmenu"):
+						self.servicelist.moveUp()
+						self.session.execDialog(self.servicelist)				
+				else:
+						if self.actmenu == "tickermenu":
+								self["tickermenu"].up()
+								self.hideTimerRestart()
+								self.refreshInfoTimerRestart()
+		
+		def down(self):
+				self.screenHideTimer.stop()
+				if not self.hideflag or ( self.hideflag and self.actmenu == "ergmenu"):
+						self.servicelist.moveDown()
+						self.session.execDialog(self.servicelist)				
+				else:
+						if self.actmenu == "tickermenu":
+								self["tickermenu"].down()									
+								self.hideTimerRestart()
+								self.refreshInfoTimerRestart()
+
+		def zapUp(self):
+				self.servicelist.moveUp()
+				self.servicelist.zap()
+				
+		def zapDown(self):
+				self.servicelist.moveDown()
+				self.servicelist.zap()
+						
+		def getLiveContent(self,output):
+				self.loadinginprogress = False
+				self["tickerlabel"].setText("")
+				self["tickermenu"].l.setList([])
+				self["ergmenu"].l.setList([])
+				self["tickerlabel"].setText("")
+				output = output.decode("latin1").encode("utf-8")
+				
+				self["tickermenu"].l.setItemHeight(80)
+				
+				if size_w == 1280:
+						fonterg = -1
+						afontticker = -1
+						bfontticker = 0
+						ysize = 25
+						axsize = 290
+						bxsize = 100
+						xsizeticker = 1190
+						ysizeticker = 25
+						maxchar = 110
+						maxword = 17
+				else:
+						fonterg = 3
+						afontticker = 0
+						bfontticker = 1
+						ysize = 20
+						axsize = 170
+						bxsize = 60
+						xsizeticker = 615	
+						ysizeticker = 25			
+						maxchar = 70
+						maxword = 11
+												
+				# Live Ergebnisse
+				self.tableentries = []
+				startpos = find(output,'<!-- Events -->')
+				if startpos == -1:
+						self["tickerlabel"].setText("Keine Ergebnisse gefunden!")
+				else:		
+						endpos = find(output,'<!-- /Events --> ')
+						bereich = output[startpos:endpos]
+						bereich = transHTML(bereich)
+						bereich = sub("</td>\s*\n","</td>",bereich)
+						bereich = sub('<a href="',"MARK:" + self.baseurl + self.buli + "/",bereich)
+						bereich = bereich.replace('</a>',"").replace('class="eventP">',"MARK:").replace('class="eventLive">',"MARK:")
+						erg = findall(r'MARK:(.*?)["<]',bereich)
+
+						if len(erg) == 0:
+								self["tickerlabel"].setText("Keine Ergebnisse gefunden!")
+						else:								
+								 												
+								# 'http://linpop.zdf.de/sport/bl1/event20129.htm', 'Bielefeld - Schalke', '0:2 (0:1)'
+								y = 0								
+								offset = 9
+								index = 0
+								for x in erg:
+										if y == 0:
+												res = [ x ]
+												#self.linklist.append(x)
+										if y == 1:
+												res.append(MultiContentEntryText(pos=(10, 2), size=(axsize, ysize), font=fonterg, flags = RT_HALIGN_LEFT, text=x))
+										if y == 2:
+												if len(self.ergold) > 0:
+														if x != self.ergold[index]:
+																res.append(MultiContentEntryText(pos=(axsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00f23d21))
+														else:
+																res.append(MultiContentEntryText(pos=(axsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00dab329))
+												else:
+														res.append(MultiContentEntryText(pos=(axsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00dab329))
+										if y == 3:
+												pass
+										if y == 4:										
+												res.append(MultiContentEntryText(pos=(axsize+bxsize+15, 2), size=(axsize, ysize), font=fonterg, flags = RT_HALIGN_LEFT, text=x))
+										if y == 5:
+												if len(self.ergold) > 0:
+														if x != self.ergold[index]:
+																res.append(MultiContentEntryText(pos=(2*axsize+bxsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00f23d21))
+														else:
+																res.append(MultiContentEntryText(pos=(2*axsize+bxsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00dab329))
+												else:
+														res.append(MultiContentEntryText(pos=(2*axsize+bxsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00dab329))
+										if y == 6:
+												pass
+										if y == 7:												
+												res.append(MultiContentEntryText(pos=(2*axsize+2*bxsize+15, 2), size=(axsize, ysize), font=fonterg, flags = RT_HALIGN_LEFT, text=x))
+										if y == 8:
+												if len(self.ergold) > 0:
+														if x != self.ergold[index]:
+																res.append(MultiContentEntryText(pos=(3*axsize+2*bxsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00f23d21))
+														else:
+																res.append(MultiContentEntryText(pos=(3*axsize+2*bxsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00dab329))
+												else:
+														res.append(MultiContentEntryText(pos=(3*axsize+2*bxsize+5, 2), size=(bxsize, ysize), font=fonterg, flags = RT_HALIGN_RIGHT, text=x, color=0x00dab329))
+												self.tableentries.append(res)
+										y +=1
+										if y == offset:
+												y = 0
+										index +=1			
+								self["ergmenu"].l.setList(self.tableentries)
+
+														
+				# Liveticker
+				self.tableentries = []
+				ticker = []	
+				minute = []
+				bild = []
+				paarung = []
+				text = []
+				startpos = find(output,'<!-- rechte Spalte -->')
+				if startpos == -1:
+						self["tickerlabel"].setText("Kein Liveticker gefunden!")
+				else:				
+						endpos = find(output,'<!-- /rechte Spalte -->')
+						bereich = output[startpos:endpos]
+						bereich = transHTML(bereich)
+						# falls kein Bild -> Dummy Eintrag 
+						bereich = sub('<div class="minute">.*?</div>\n','<div class="minute"></div><img src="pics/dummy.gif" alt="Dummy" class="message-type">',bereich)
+						minute = findall(r'<div class="minute">(.*?)</div>',bereich)
+						if len(minute) == 0:
+								self["tickerlabel"].setText("Kein Liveticker gefunden!")
+						else:
+								bild = findall(r'<img src="pics/(.*?).gif',bereich)
+								# Paarung nur bei Konferenz
+								if search("event",self.konfurl) is not None:
+										for x in minute:
+												paarung.append(" ")
+								else:					
+										paarung = findall(r'class="message-header">(.*?)</a>',bereich)
+								text =  findall(r'<p>.*?\s*(.*?)</p>',bereich)	
+								textnr = len(text)
+								y = 0											
+								for x in text:
+										text[y] = sub("<[^>]*>","",text[y])				
+										ticker.append((bild[y],minute[y],paarung[y],strip(text[y])))
+										y +=1						 					
+								# ('halbzeit_gr', '', 'Ingolstadt - Wehen', 'Abpfiff durch T. Metzen, der Endstand lautet 0:0.    ')
+											
+								for pic, time, spiel, livetext in ticker:
+										if time == "":
+												time = "--"		
+										x = "%s ( %s min. / %d )" % (spiel,time,textnr)
+										res = [ x ]
+										if pic != "dummy":
+												png = LoadPixmap(pluginpath + "/icons/" + pic + ".png")
+												res.append(MultiContentEntryPixmapAlphaTest(pos=(10, 10), size=(55, 55), png = png))
+										res.append(MultiContentEntryText(pos=(70, 5), size=(xsizeticker, ysizeticker), font=afontticker, flags = RT_HALIGN_LEFT, text=x,color_sel=0x00ffffff))
+										if len(livetext) > maxchar:									
+												firstline = ""
+												secondline = ""
+												z=split(" ",livetext)
+												#print "--> %s %s" % (len(livetext),len(z))
+												for i in z[0:maxword]:
+														firstline = firstline + " " + i
+												for i in z[maxword:]:
+														secondline = secondline + " " + i
+												res.append(MultiContentEntryText(pos=(70, ysizeticker+5), size=(xsizeticker, ysizeticker), font=bfontticker, flags = RT_HALIGN_LEFT, text=strip(firstline),color_sel=0x00ffffff))										
+												res.append(MultiContentEntryText(pos=(70, 2*ysizeticker+5), size=(xsizeticker, ysizeticker), font=bfontticker, flags = RT_HALIGN_LEFT, text=strip(secondline),color_sel=0x00ffffff))
+										else:
+												res.append(MultiContentEntryText(pos=(70, ysizeticker+5), size=(xsizeticker, ysizeticker), font=bfontticker, flags = RT_HALIGN_LEFT, text=livetext))		
+										self.tableentries.append(res)						
+										textnr -=1
+								self["tickermenu"].l.setList(self.tableentries)
+			
+# 								print self.ergold
+# 								print erg
+# 								print self.tickerold
+# 								print text[0]
+# 								print self.hideflag
+# 								print self.actmenu								
+
+								# falls neue Ergebnisse oder neuer Tickerttext -> Screen anzeigen			
+								if not self.hideflag:
+										if self.ergold != erg and len(self.ergold) > 0:
+												self.actmenu = "ergmenu"
+												self["tickerlabel"].hide()
+												self["tickermenu"].selectionEnabled(0)
+												self["tickermenu"].hide()
+												self["ergmenu"].show()
+												self.hideScreen()
+										elif self.tickerold != text[0]:
+												self.actmenu = "tickermenu"
+												self["ergmenu"].hide()
+												self["tickermenu"].show()
+												self["tickerlabel"].show()
+												self["tickermenu"].selectionEnabled(1)
+												self.hideScreen()
+																								
+								self.ergold = erg
+								self.tickerold = text[0]
+																
+		def download(self, link, name):
+				self.loadinginprogress = True
+				getPage(link).addCallback(name).addErrback(self.downloadError)
+						
+		def downloadError(self,output):
+				self.loadinginprogress = False
+				self["tickerlabel"].setText("Fehler beim Download")
+
+		def hideScreen(self):
+				if self.hideflag == True:
+						self.hideflag = False
+						self.screenHideTimer.stop()
+						self.hide()
+				else:
+						self.hideflag = True
+						self.screenHideTimer.start(screenhidetimer)
+						self.show()
+								
+		def exit(self):
+				self.refreshInfoTimer.stop()
+				self.screenHideTimer.stop()
+				if self.loadinginprogress:
+						reactor.callLater(1,self.exit)
+				else:
+						config.plugins.buliticker.actmenu.value = self.actmenu
+						config.plugins.buliticker.actmenu.save()
+						configfile.save()
+						self.close()
+	
+#######################
+
+class ItemList(MenuList):
+		def __init__(self, items, enableWrapAround = True):
+			MenuList.__init__(self, items, enableWrapAround, eListboxPythonMultiContent)
+			self.l.setFont(-1, gFont("Regular", 22))
+			self.l.setFont(0, gFont("Regular", 20))
+			self.l.setFont(1, gFont("Regular", 18))
+			self.l.setFont(2, gFont("Regular", 16))
+			self.l.setFont(3, gFont("Regular", 15))
+		
+#############################						
+											        
+def main(session, **kwargs):
+			session.open(ShowFullTicker)
+						
+def Plugins(path,**kwargs):
+			global pluginpath
+			pluginpath = path
+ 			return PluginDescriptor(
+					name="Bundesliga Liveticker", 
+					description="1./2. Bundesliga Ticker (c)linpop.zdf.de", 
+					icon="zdftickerlogo.png",
+					where = [ PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU ],
+					fnc=main)
Index: /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/FritzCall.pot
===================================================================
--- /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/FritzCall.pot	(revision 5870)
+++ /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/FritzCall.pot	(revision 5870)
@@ -0,0 +1,398 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-16 13:54+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. TRANSLATORS: this is a help text, keep it short
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "Add entry to phonebook"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "All"
+msgstr ""
+
+msgid "All calls"
+msgstr ""
+
+msgid "Append shortcut number"
+msgstr ""
+
+msgid "Append type of number"
+msgstr ""
+
+msgid "Append vanity name"
+msgstr ""
+
+msgid "Areacode to add to Outgoing Calls (if necessary)"
+msgstr ""
+
+msgid "Austria"
+msgstr ""
+
+msgid "Automatically add new Caller to PhoneBook"
+msgstr ""
+
+msgid "CF Drive"
+msgstr ""
+
+msgid "Call monitoring"
+msgstr ""
+
+msgid "Can't create PhoneBook.txt"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Cancel"
+msgstr ""
+
+msgid "Connected to FRITZ!Box!"
+msgstr ""
+
+#, python-format
+msgid ""
+"Connecting to FRITZ!Box failed\n"
+" (%s)\n"
+"retrying..."
+msgstr ""
+
+msgid "Connecting to FRITZ!Box..."
+msgstr ""
+
+#, python-format
+msgid ""
+"Connection to FRITZ!Box! lost\n"
+" (%s)\n"
+"retrying..."
+msgstr ""
+
+#, python-format
+msgid "Could not load calls from FRITZ!Box - Error: %s"
+msgstr ""
+
+#, python-format
+msgid "Could not load phonebook from FRITZ!Box - Error: %s"
+msgstr ""
+
+msgid "Could not parse FRITZ!Box Phonebook entry"
+msgstr ""
+
+msgid "Country"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Delete"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Delete entry"
+msgstr ""
+
+msgid "Display FRITZ!box-Fon calls on screen"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display all calls"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display incoming calls"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display missed calls"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display outgoing calls"
+msgstr ""
+
+#, python-format
+msgid ""
+"Do you really want to delete entry for\n"
+"\n"
+"%(number)s\n"
+"\n"
+"%(name)s?"
+msgstr ""
+
+#, python-format
+msgid ""
+"Do you really want to overwrite entry for\n"
+"%(number)s\n"
+"\n"
+"%(name)s\n"
+"\n"
+"with\n"
+"\n"
+"%(newname)s?"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Edit"
+msgstr ""
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "Edit phonebook entry"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Edit selected entry"
+msgstr ""
+
+msgid "Enter Search Terms"
+msgstr ""
+
+msgid "Entry incomplete."
+msgstr ""
+
+msgid "FRITZ!Box FON IP address"
+msgstr ""
+
+#, python-format
+msgid "FRITZ!Box Login failed! - Error: %s"
+msgstr ""
+
+msgid "FRITZ!Box Login failed! - Wrong Password!"
+msgstr ""
+
+msgid "Flash"
+msgstr ""
+
+msgid "France"
+msgstr ""
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "FritzCall Setup"
+msgstr ""
+
+msgid "Germany"
+msgstr ""
+
+msgid "Getting calls from FRITZ!Box..."
+msgstr ""
+
+msgid "Harddisk"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Incoming"
+msgstr ""
+
+#, python-format
+msgid ""
+"Incoming Call on %(date)s from\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"to: %(phone)s"
+msgstr ""
+
+msgid "Incoming calls"
+msgstr ""
+
+msgid "Italy"
+msgstr ""
+
+msgid "Last 10 calls:\n"
+msgstr ""
+
+msgid "MSN to show (separated by ,)"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Missed"
+msgstr ""
+
+msgid "Missed calls"
+msgstr ""
+
+msgid "Name"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "New"
+msgstr ""
+
+msgid "No entry selected"
+msgstr ""
+
+msgid "Number"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "OK"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Outgoing"
+msgstr ""
+
+#, python-format
+msgid ""
+"Outgoing Call on %(date)s to\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"from: %(phone)s"
+msgstr ""
+
+msgid "Outgoing calls"
+msgstr ""
+
+msgid "Password Accessing FRITZ!Box"
+msgstr ""
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+#. TRANSLATORS: keep it short, this is a button
+msgid "Phone calls"
+msgstr ""
+
+msgid "PhoneBook Location"
+msgstr ""
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+#. TRANSLATORS: keep it short, this is a button
+msgid "Phonebook"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Quit"
+msgstr ""
+
+msgid "Read PhoneBook from FRITZ!Box"
+msgstr ""
+
+msgid "Reverse Lookup Caller ID (select country below)"
+msgstr ""
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Search"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Search (case insensitive)"
+msgstr ""
+
+msgid "Search phonebook"
+msgstr ""
+
+msgid "Shortcut"
+msgstr ""
+
+msgid "Show Calls for specific MSN"
+msgstr ""
+
+msgid "Show Outgoing Calls"
+msgstr ""
+
+msgid "Show after Standby"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Show details of entry"
+msgstr ""
+
+msgid "Strip Leading 0"
+msgstr ""
+
+msgid "Switzerland"
+msgstr ""
+
+msgid "The Netherlands"
+msgstr ""
+
+msgid "Timeout for Call Notifications (seconds)"
+msgstr ""
+
+msgid "UNKNOWN"
+msgstr ""
+
+msgid "USB Stick"
+msgstr ""
+
+msgid "Use internal PhoneBook"
+msgstr ""
+
+msgid "Vanity"
+msgstr ""
+
+msgid "You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"
+msgstr ""
+
+msgid ""
+"You need to set the password of the FRITZ!Box\n"
+"in the configuration dialog to display calls\n"
+"\n"
+"It could be a communication issue, just try again."
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "display calls"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "display phonebook"
+msgstr ""
+
+msgid "done"
+msgstr ""
+
+msgid "done, using last list"
+msgstr ""
+
+msgid "finishing"
+msgstr ""
+
+msgid "home"
+msgstr ""
+
+msgid "login"
+msgstr ""
+
+msgid "login ok"
+msgstr ""
+
+msgid "login verification"
+msgstr ""
+
+msgid "mobile"
+msgstr ""
+
+msgid "preparing"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "quit"
+msgstr ""
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "save and quit"
+msgstr ""
+
+msgid "show as list"
+msgstr ""
+
+msgid "show each call"
+msgstr ""
+
+msgid "show nothing"
+msgstr ""
+
+msgid "work"
+msgstr ""
Index: /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/Makefile
===================================================================
--- /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/Makefile	(revision 5870)
+++ /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/Makefile	(revision 5870)
@@ -0,0 +1,42 @@
+#
+# to use this for the localisation of other plugins,
+# just change the DOMAIN to the name of the Plugin.
+# It is assumed, that the domain ist the same as
+# the directory name of the plugin.
+#
+
+DOMAIN=FritzCall
+installdir = /usr/lib/enigma2/python/Plugins/Extensions/$(DOMAIN)
+GETTEXT=xgettext
+MSGFMT = msgfmt
+
+LANGS := de it
+LANGPO := $(foreach LANG, $(LANGS),$(LANG).po)
+LANGMO := $(foreach LANG, $(LANGS),$(LANG).mo)
+
+$(foreach LANG, $(LANGS),$(LANG)/LC_MESSAGES/$(DOMAIN).mo): $(LANGMO)
+	for lang in $(LANGS); do \
+		mkdir -p $$lang/LC_MESSAGES; \
+		cp $$lang.mo $$lang/LC_MESSAGES/$(DOMAIN).mo; \
+	done
+
+
+# the TRANSLATORS: allows putting translation comments before the to-be-translated line.
+$(DOMAIN).pot: ../plugin.py
+	$(GETTEXT) --no-location -L python --add-comments="TRANSLATORS:" -d $(DOMAIN) -s -o $(DOMAIN).pot ../plugin.py
+	msguniq -o $(DOMAIN)uniq.pot $(DOMAIN).pot
+	$(RM) $(DOMAIN).pot
+	mv $(DOMAIN)uniq.pot $(DOMAIN).pot
+
+
+%.mo: %.po
+	$(MSGFMT) -o $@ $<
+
+%.po: $(DOMAIN).pot
+	msgmerge -s -U $@ $(DOMAIN).pot; \
+
+clean:
+	rm -f *~
+
+distclean: clean
+	rm -f *.mo
Index: /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/de.po
===================================================================
--- /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/de.po	(revision 5870)
+++ /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/de.po	(revision 5870)
@@ -0,0 +1,438 @@
+# FritzCall plugin german localization
+# Copyright (C) 2008 Michael Schmidt
+# This file is distributed under the same license as the PACKAGE package.
+# Michael Schmidt <michael@schmidt-schmitten.com>, 2008.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Enigma2 FritzCall Plugin\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-16 13:53+0200\n"
+"PO-Revision-Date: 2008-09-16 13:54+0200\n"
+"Last-Translator: Michael Schmidt <michael@schmidt-schmitten.com>\n"
+"Language-Team: german <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. TRANSLATORS: this is a help text, keep it short
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "Add entry to phonebook"
+msgstr "Neuer Telefonbucheintrag"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "All"
+msgstr "Alle"
+
+msgid "All calls"
+msgstr "Alle Anrufe"
+
+msgid "Append shortcut number"
+msgstr "Füge Kurzwahl an"
+
+msgid "Append type of number"
+msgstr "Füge Typ der Nummer an"
+
+msgid "Append vanity name"
+msgstr "Füge Vanity-Nummer an"
+
+msgid "Areacode to add to Outgoing Calls (if necessary)"
+msgstr "Vorwahl für abgehende Anrufe (falls nötig)"
+
+msgid "Austria"
+msgstr "Österreich"
+
+msgid "Automatically add new Caller to PhoneBook"
+msgstr "Anrufer automatisch dem Telefonbuch hinzufügen"
+
+msgid "CF Drive"
+msgstr "CF Laufwerk"
+
+msgid "Call monitoring"
+msgstr "Anrufanzeige"
+
+msgid "Can't create PhoneBook.txt"
+msgstr "Kann Phonebook.txt nicht anlegen"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Cancel"
+msgstr "Abbruch"
+
+msgid "Connected to FRITZ!Box!"
+msgstr "Verbunden mit FRITZ!Box!"
+
+#, python-format
+msgid ""
+"Connecting to FRITZ!Box failed\n"
+" (%s)\n"
+"retrying..."
+msgstr ""
+"Verbindung zur FRITZ!Box fehlgeschlagen\n"
+" (%s)\n"
+"neuer Versuch..."
+
+msgid "Connecting to FRITZ!Box..."
+msgstr "Verbinde mit FRITZ!Box..."
+
+#, python-format
+msgid ""
+"Connection to FRITZ!Box! lost\n"
+" (%s)\n"
+"retrying..."
+msgstr ""
+"Verbindung mit FRITZ!Box verloren\n"
+" (%s)\n"
+"neuer Versuch..."
+
+#, python-format
+msgid "Could not load calls from FRITZ!Box - Error: %s"
+msgstr "Konnte verpasste Anrufe nicht von FRITZ!Box laden - Fehler: %s"
+
+#, python-format
+msgid "Could not load phonebook from FRITZ!Box - Error: %s"
+msgstr "Konnte Telefonbuch nicht von FRITZ!Box laden - Fehler: %s"
+
+msgid "Could not parse FRITZ!Box Phonebook entry"
+msgstr "Konnte Eintrag in FRITZ!Box-Telefonbuch nicht lesen"
+
+msgid "Country"
+msgstr "Land"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Delete"
+msgstr "Löschen"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Delete entry"
+msgstr "Eintrag löschen"
+
+msgid "Display FRITZ!box-Fon calls on screen"
+msgstr "Anzeige der Anrufe auf der FRITZ!Box Fon"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display all calls"
+msgstr "Alle Anrufe"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display incoming calls"
+msgstr "Eingehende Anrufe"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display missed calls"
+msgstr "Verpasste Anrufe"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display outgoing calls"
+msgstr "Abgehende Anrufe"
+
+#, python-format
+msgid ""
+"Do you really want to delete entry for\n"
+"\n"
+"%(number)s\n"
+"\n"
+"%(name)s?"
+msgstr ""
+"Soll der Eintrag\n"
+"\n"
+"%(name)s\n"
+"\n"
+"für %(number)s wirklich gelöscht werden?"
+
+#, python-format
+msgid ""
+"Do you really want to overwrite entry for\n"
+"%(number)s\n"
+"\n"
+"%(name)s\n"
+"\n"
+"with\n"
+"\n"
+"%(newname)s?"
+msgstr ""
+"Soll der Eintrag\n"
+"\n"
+"%(name)s\n"
+"\n"
+"für\n"
+"\n"
+"%(number)s\n"
+"\n"
+"wirklich in den folgenden geändert werden?\n"
+"\n"
+"%(newname)s"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Edit"
+msgstr "Ändern"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "Edit phonebook entry"
+msgstr "Bearbeite Telefonbucheintrag"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Edit selected entry"
+msgstr "Eintrag bearbeiten"
+
+msgid "Enter Search Terms"
+msgstr "Suchbegriffe"
+
+msgid "Entry incomplete."
+msgstr "Eintrag unvollständig."
+
+msgid "FRITZ!Box FON IP address"
+msgstr "FRITZ!Box FON IP-Adresse"
+
+#, python-format
+msgid "FRITZ!Box Login failed! - Error: %s"
+msgstr "FRITZ!Box Login fehlgeschlagen! - Fehler: %s"
+
+msgid "FRITZ!Box Login failed! - Wrong Password!"
+msgstr "FRITZ!Box Login fehlgeschlagen! - Falsches Passwort"
+
+msgid "Flash"
+msgstr "Flash"
+
+msgid "France"
+msgstr "Frankreich"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "FritzCall Setup"
+msgstr "FritzCall Einstellungen"
+
+msgid "Germany"
+msgstr "Deutschland"
+
+msgid "Getting calls from FRITZ!Box..."
+msgstr "Hole Liste der Anrufe von der FRITZ!Box..."
+
+msgid "Harddisk"
+msgstr "Festplatte"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Incoming"
+msgstr "Eingehend"
+
+#, python-format
+msgid ""
+"Incoming Call on %(date)s from\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"to: %(phone)s"
+msgstr ""
+"Eingehender Anruf um %(date)s von\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"an: %(phone)s"
+
+msgid "Incoming calls"
+msgstr "Eingehende Anrufe"
+
+msgid "Italy"
+msgstr "Italien"
+
+msgid "Last 10 calls:\n"
+msgstr "Die letzten zehn Anrufe im Standby:\n"
+
+msgid "MSN to show (separated by ,)"
+msgstr "anzuzeigende MSNs (getrennt durch ,)"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Missed"
+msgstr "Verpasst"
+
+msgid "Missed calls"
+msgstr "Verpasste Anrufe"
+
+msgid "Name"
+msgstr "Name"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "New"
+msgstr "Neu"
+
+msgid "No entry selected"
+msgstr "Kein Eintrag ausgewählt"
+
+msgid "Number"
+msgstr "Nummer"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "OK"
+msgstr "OK"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Outgoing"
+msgstr "Abgehend"
+
+#, python-format
+msgid ""
+"Outgoing Call on %(date)s to\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"from: %(phone)s"
+msgstr ""
+"Abgehender Anruf um %(date)s an\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"von: %(phone)s"
+
+msgid "Outgoing calls"
+msgstr "Abgehende Anrufe"
+
+msgid "Password Accessing FRITZ!Box"
+msgstr "Passwort der FRITZ!Box"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+#. TRANSLATORS: keep it short, this is a button
+msgid "Phone calls"
+msgstr "Telefonanrufe"
+
+msgid "PhoneBook Location"
+msgstr "Speicherort des Telefonbuchs"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+#. TRANSLATORS: keep it short, this is a button
+msgid "Phonebook"
+msgstr "Telefonbuch"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Quit"
+msgstr "Beenden"
+
+msgid "Read PhoneBook from FRITZ!Box"
+msgstr "Telefonbuch der FRITZ!Box auslesen"
+
+msgid "Reverse Lookup Caller ID (select country below)"
+msgstr "Rückwärtssuche (bitte Land auswählen)"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Search"
+msgstr "Suche"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Search (case insensitive)"
+msgstr "Suche Zeichenfolge (groß/klein egal)"
+
+msgid "Search phonebook"
+msgstr "Telefonbuchsuche"
+
+msgid "Shortcut"
+msgstr "Kurzwahl"
+
+msgid "Show Calls for specific MSN"
+msgstr "Zeige nur Anrufe bestimmter Nummern"
+
+msgid "Show Outgoing Calls"
+msgstr "Zeige abgehende Anrufe an"
+
+msgid "Show after Standby"
+msgstr "Anzeige nach Standby"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Show details of entry"
+msgstr "Details des Eintrags anzeigen"
+
+msgid "Strip Leading 0"
+msgstr "Führende 0 entfernen"
+
+msgid "Switzerland"
+msgstr "Schweiz"
+
+msgid "The Netherlands"
+msgstr "Niederlande"
+
+msgid "Timeout for Call Notifications (seconds)"
+msgstr "Anzeigedauer in Sekunden"
+
+msgid "UNKNOWN"
+msgstr "UNBEKANNT"
+
+msgid "USB Stick"
+msgstr "USB Stick"
+
+msgid "Use internal PhoneBook"
+msgstr "Benutze internes Telefonbuch"
+
+msgid "Vanity"
+msgstr "Vanity"
+
+msgid "You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"
+msgstr ""
+"Monitoring auf der FRITZ!Box muss durch Wählen von #96*5* eingeschaltet "
+"werden!"
+
+msgid ""
+"You need to set the password of the FRITZ!Box\n"
+"in the configuration dialog to display calls\n"
+"\n"
+"It could be a communication issue, just try again."
+msgstr ""
+"In der Konfiguration muss das Passwort für\n"
+"die FRITZ!Box gesetzt sein.\n"
+"\n"
+"Es könnte eine Kommunikationsproblem mit der FRITZ!Box sein.\n"
+"Versuchen Sie es nochmal."
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "display calls"
+msgstr "Alle Anrufe"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "display phonebook"
+msgstr "Telefonbuch"
+
+msgid "done"
+msgstr "fertig"
+
+msgid "done, using last list"
+msgstr "fertig, benutze letzte Liste"
+
+msgid "finishing"
+msgstr "Fertigstellung"
+
+msgid "home"
+msgstr "privat"
+
+msgid "login"
+msgstr "Login"
+
+msgid "login ok"
+msgstr "Login OK"
+
+msgid "login verification"
+msgstr "Login Verifikation"
+
+msgid "mobile"
+msgstr "mobil"
+
+msgid "preparing"
+msgstr "Vorbereitung"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "quit"
+msgstr "Beenden"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "save and quit"
+msgstr "Sichern und Beenden"
+
+msgid "show as list"
+msgstr "Liste der Anrufe"
+
+msgid "show each call"
+msgstr "Anzeige der einzelnen Anrufe"
+
+msgid "show nothing"
+msgstr "keine Anzeige"
+
+msgid "work"
+msgstr "geschäftlich"
Index: /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/it.po
===================================================================
--- /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/it.po	(revision 5870)
+++ /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/locale/it.po	(revision 5870)
@@ -0,0 +1,431 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Enigma2 FRITZ!Box plugin italian locale\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2008-09-16 13:53+0200\n"
+"PO-Revision-Date: 2008-09-16 10:19+0200\n"
+"Last-Translator: Spaeleus <spaeleus@croci.org>\n"
+"Language-Team: www.linsat.net <spaeleus@croci.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-Language: Italian\n"
+"X-Poedit-Country: ITALY\n"
+"X-Poedit-SourceCharset: iso-8859-1\n"
+
+#. TRANSLATORS: this is a help text, keep it short
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "Add entry to phonebook"
+msgstr "Aggiungere voce in rubrica"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "All"
+msgstr "Tutte"
+
+msgid "All calls"
+msgstr "Tutte le Chiamate"
+
+msgid "Append shortcut number"
+msgstr "Aggiungere numero breve"
+
+msgid "Append type of number"
+msgstr "Agg. il tipo di numero (casa,cell.,uff.)"
+
+msgid "Append vanity name"
+msgstr "Aggiungere nome 'Vanity'"
+
+msgid "Areacode to add to Outgoing Calls (if necessary)"
+msgstr "Prefisso per le Chiamate in Uscita (se necessario)"
+
+msgid "Austria"
+msgstr "Austria"
+
+msgid "Automatically add new Caller to PhoneBook"
+msgstr "Ins. autom. nuovo chiamante in rubrica"
+
+msgid "CF Drive"
+msgstr "Drive CF"
+
+msgid "Call monitoring"
+msgstr "Monitoraggio chiamate"
+
+msgid "Can't create PhoneBook.txt"
+msgstr "Impossibile creare PhoneBook.txt!"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Cancel"
+msgstr "Annullare"
+
+msgid "Connected to FRITZ!Box!"
+msgstr "Connesso alla FRITZ!Box!"
+
+#, python-format
+msgid ""
+"Connecting to FRITZ!Box failed\n"
+" (%s)\n"
+"retrying..."
+msgstr ""
+"Connessione alla FRITZ!Box fallita!\n"
+"(%s)\n"
+"Nuovo tentativo in corso..."
+
+msgid "Connecting to FRITZ!Box..."
+msgstr "Connessione alla FRITZ!Box in corso"
+
+#, python-format
+msgid ""
+"Connection to FRITZ!Box! lost\n"
+" (%s)\n"
+"retrying..."
+msgstr ""
+"Connessione alla FRITZ!Box persa!\n"
+"(%s)\n"
+"Nuovo tentativo in corso..."
+
+#, python-format
+msgid "Could not load calls from FRITZ!Box - Error: %s"
+msgstr "Impossibile caricare le chiamate dalla FRITZ!Box! - Errore: %s"
+
+#, python-format
+msgid "Could not load phonebook from FRITZ!Box - Error: %s"
+msgstr "Impossibile caricare la rubrica dalla FRITZ!Box! - Errore: %s"
+
+msgid "Could not parse FRITZ!Box Phonebook entry"
+msgstr "Impossibile analizzare la voce nella Rubrica della FRITZ!Box!"
+
+msgid "Country"
+msgstr "Nazione"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Delete"
+msgstr "Cancell."
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Delete entry"
+msgstr "Cancellare voce"
+
+msgid "Display FRITZ!box-Fon calls on screen"
+msgstr "Visualizza le chiamate telef. sulla TV"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display all calls"
+msgstr "Tutte le Chiamate"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display incoming calls"
+msgstr "Chiamate in Ingresso"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display missed calls"
+msgstr "Chiamate perse"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Display outgoing calls"
+msgstr "Chiamate in Uscita"
+
+#, python-format
+msgid ""
+"Do you really want to delete entry for\n"
+"\n"
+"%(number)s\n"
+"\n"
+"%(name)s?"
+msgstr ""
+"Cancellare la voce\n"
+"\n"
+"%(number)s\n"
+"\n"
+"%(name)s?"
+
+#, python-format
+msgid ""
+"Do you really want to overwrite entry for\n"
+"%(number)s\n"
+"\n"
+"%(name)s\n"
+"\n"
+"with\n"
+"\n"
+"%(newname)s?"
+msgstr ""
+"Sovrascrivere la voce\n"
+"%(number)s\n"
+"\n"
+"%(name)s\n"
+"\n"
+"con\n"
+"\n"
+"%(newname)s?"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Edit"
+msgstr "Mod."
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "Edit phonebook entry"
+msgstr "Modificare voce rubrica"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Edit selected entry"
+msgstr "Mod. voce selezionata"
+
+msgid "Enter Search Terms"
+msgstr "Inserire criteri di ricerca"
+
+msgid "Entry incomplete."
+msgstr ""
+
+msgid "FRITZ!Box FON IP address"
+msgstr "Indirizzo IP FRITZ!Box FON"
+
+#, python-format
+msgid "FRITZ!Box Login failed! - Error: %s"
+msgstr "Login alla FRITZ!Box fallito! - Errore: %s"
+
+msgid "FRITZ!Box Login failed! - Wrong Password!"
+msgstr "Login alla FRITZ!Box fallito! - Password errata!"
+
+msgid "Flash"
+msgstr "Flash"
+
+msgid "France"
+msgstr "Francia"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+msgid "FritzCall Setup"
+msgstr "Configurazione FritzCall"
+
+msgid "Germany"
+msgstr "Germania"
+
+msgid "Getting calls from FRITZ!Box..."
+msgstr "Recupero chiamate dalla FRITZ!Box in corso"
+
+msgid "Harddisk"
+msgstr "Harddisk"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Incoming"
+msgstr "In Entr."
+
+#, python-format
+msgid ""
+"Incoming Call on %(date)s from\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"to: %(phone)s"
+msgstr ""
+"Chiamata in arrivo su %(date)s da\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"a: %(phone)s"
+
+msgid "Incoming calls"
+msgstr "Chiamate in Ingresso"
+
+msgid "Italy"
+msgstr "Italia"
+
+msgid "Last 10 calls:\n"
+msgstr "Ultime 10 chiamate:\n"
+
+msgid "MSN to show (separated by ,)"
+msgstr "MSN da mostrare (separare con ,)"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Missed"
+msgstr "Ch. Perse"
+
+msgid "Missed calls"
+msgstr "Chiamate perse"
+
+msgid "Name"
+msgstr "Nome"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "New"
+msgstr "Nuovo"
+
+msgid "No entry selected"
+msgstr "Nessuna voce selezionata"
+
+msgid "Number"
+msgstr "Numero"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "OK"
+msgstr "OK"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Outgoing"
+msgstr "In Uscita"
+
+#, python-format
+msgid ""
+"Outgoing Call on %(date)s to\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"from: %(phone)s"
+msgstr ""
+"Chiamata in uscita su %(date)s a\n"
+"---------------------------------------------\n"
+"%(number)s\n"
+"%(caller)s\n"
+"---------------------------------------------\n"
+"da: %(phone)s"
+
+msgid "Outgoing calls"
+msgstr "Chiamate in Uscita"
+
+msgid "Password Accessing FRITZ!Box"
+msgstr "Password di accesso alla FRITZ!Box"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+#. TRANSLATORS: keep it short, this is a button
+msgid "Phone calls"
+msgstr "Ch. Telef."
+
+msgid "PhoneBook Location"
+msgstr "Posizione Rubrica"
+
+#. TRANSLATORS: this is a window title. Avoid the use of non ascii chars
+#. TRANSLATORS: keep it short, this is a button
+msgid "Phonebook"
+msgstr "Rubrica"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Quit"
+msgstr "Uscire"
+
+msgid "Read PhoneBook from FRITZ!Box"
+msgstr "Caricare la Rubrica dalla FRITZ!Box"
+
+msgid "Reverse Lookup Caller ID (select country below)"
+msgstr "Identificativo Chiamante (Selezionare il Paese!)"
+
+#. TRANSLATORS: keep it short, this is a button
+msgid "Search"
+msgstr "Ricerca"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Search (case insensitive)"
+msgstr "Ricerca (non distingue Maiusc-minusc)"
+
+msgid "Search phonebook"
+msgstr "Ricerca su rubrica"
+
+msgid "Shortcut"
+msgstr "Numero breve"
+
+msgid "Show Calls for specific MSN"
+msgstr "Mostrare le chiamate per MSN specifico"
+
+msgid "Show Outgoing Calls"
+msgstr "Mostrare le chiamate in uscita"
+
+msgid "Show after Standby"
+msgstr "Mostrare chiamate dopo lo Standby"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "Show details of entry"
+msgstr "Mostrare dettagli voce"
+
+msgid "Strip Leading 0"
+msgstr "Sopprimere '0' iniziali"
+
+msgid "Switzerland"
+msgstr "Svizzera"
+
+msgid "The Netherlands"
+msgstr "Olanda"
+
+msgid "Timeout for Call Notifications (seconds)"
+msgstr "Ritardo notifica chiamate (secondi)"
+
+msgid "UNKNOWN"
+msgstr "SCONOSCIUTO"
+
+msgid "USB Stick"
+msgstr "Penna USB"
+
+msgid "Use internal PhoneBook"
+msgstr "Usare la Rubrica interna"
+
+msgid "Vanity"
+msgstr "'Vanity'"
+
+msgid "You need to enable the monitoring on your FRITZ!Box by dialing #96*5*!"
+msgstr "Per abilitare il monitoraggio sulla FRITZ!Box comporre #96*5*!"
+
+msgid ""
+"You need to set the password of the FRITZ!Box\n"
+"in the configuration dialog to display calls\n"
+"\n"
+"It could be a communication issue, just try again."
+msgstr ""
+"E' necessario impostare la password della FRITZ!Box\n"
+"nel menu configurazione per mostrare le chiamate.\n"
+"\n"
+"Potrebbe trattarsi di un problema di comunicazione, riprovare."
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "display calls"
+msgstr "Tutte le Chiamate"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "display phonebook"
+msgstr "Mostrare rubrica"
+
+msgid "done"
+msgstr "Fatto"
+
+msgid "done, using last list"
+msgstr "Fatto, sarà usata l'ultima lista"
+
+msgid "finishing"
+msgstr "Quasi terminato..."
+
+msgid "home"
+msgstr "Casa"
+
+msgid "login"
+msgstr "Login"
+
+msgid "login ok"
+msgstr "Login OK"
+
+msgid "login verification"
+msgstr "Verifica Login"
+
+msgid "mobile"
+msgstr "Cellulare"
+
+msgid "preparing"
+msgstr "Preparazione in corso"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "quit"
+msgstr "Uscire"
+
+#. TRANSLATORS: this is a help text, keep it short
+msgid "save and quit"
+msgstr "Salvare e uscire"
+
+msgid "show as list"
+msgstr "Come lista"
+
+msgid "show each call"
+msgstr "Tutte"
+
+msgid "show nothing"
+msgstr "Nulla"
+
+msgid "work"
+msgstr "Ufficio"
Index: /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/reverselookup.xml
===================================================================
--- /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/reverselookup.xml	(revision 5870)
+++ /ipk/source/swapinfos_fritzcall_1_2/var/swap/extensions/FritzCall/reverselookup.xml	(revision 5870)
@@ -0,0 +1,1523 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- reverselookup.xml revision 1.03 from 20, Jun 2008
+
+	 The syntax of this file is fairly self-explanatory
+     However, a few things need to be said. First and foremost
+     everything in here needs to be xml compliant, that means all
+     quotes, pound signs etc need to be properly escaped!!!
+     Otherwise jfritz will refuse too load due to of SAX errors.
+     
+     Websites and pattern entries are processed in the order they
+     are placed. This is important when determining what web site should
+     be used first and what pattern should be used for that web site first.
+   	 As soon as one matching name is found, jfritz will stop trying other
+   	 patterns / entries.
+   	 
+   	 Make sure that each url entry contains the string $NUMBER at the
+   	 appropriate spot or else the algorithm won't work! The attributes prefix
+   	 and areacode are optional. The attribute prefix is used to determine if 
+   	 the number needs the area code prefix or not. if the attribute area code
+   	 is set make sure to include string $AREACODE, or $PFXAREACODE at the
+   	 appropriate spot in the url. For more info see http://www.jfritz.org
+   	    	 
+-->
+
+<reverselookup version="1.01">
+	<country code="+1">
+		<website name="whitepages.com" url="http://www.whitepages.com/search/ReversePhone?phone=$NUMBER" prefix="1">
+			<entry>
+				<name>&lt;a href=&quot;[^&quot;]*&quot; class=&quot;fn n&quot; title=&quot;[^&quot;]*&quot;&gt;([^&lt;]*)&lt;/a&gt;</name>
+				<street>&lt;span class=&quot;street-address&quot;&gt;([^&lt;]*)&lt;/span&gt;</street>
+				<city>&lt;span class=&quot;locality&quot;&gt;([^&lt;]*)&lt;/span&gt;</city>
+				<zipcode>&lt;span class=&quot;postal-code&quot;&gt;([^&lt;]*)&lt;/span&gt;</zipcode>
+			</entry>
+			<entry>
+				<name>&lt;a href=&quot;[^&quot;]*&quot; class=&quot;fn n&quot; title=&quot;[^&quot;]*&quot;&gt;([^&lt;]*)&lt;/a&gt;</name>
+				<street>()&lt;span class=&quot;results_widget_street_none&quot;&gt;street address not available&lt;/span&gt;</street>
+				<city>&lt;span class=&quot;locality&quot;&gt;([^&lt;]*)&lt;/span&gt;</city>
+				<zipcode>&lt;span class=&quot;postal-code&quot;&gt;([^&lt;]*)&lt;/span&gt;</zipcode>
+			</entry>
+			<entry>
+				<name>&lt;[span]*[div]* class=&quot;fn n&quot;&gt;([^&lt;]*)&lt;/[span]*[div]*&gt;</name>
+				<street>&lt;span class=&quot;street-address&quot;&gt;([^&lt;]*)&lt;/span&gt;</street>
+				<city>&lt;span class=&quot;locality&quot;&gt;([^&lt;]*)&lt;/span&gt;</city>
+				<zipcode>&lt;span class=&quot;postal-code&quot;&gt;([^&lt;]*)&lt;/span&gt;</zipcode>
+			</entry>
+			<entry>
+				<name>&lt;[span]*[div]* class=&quot;fn n&quot;&gt;([^&lt;]*)&lt;/[span]*[div]*&gt;</name>
+				<street>()&lt;span class=&quot;results_widget_street_none&quot;&gt;street address not available&lt;/span&gt;</street>
+				<city>&lt;span class=&quot;locality&quot;&gt;([^&lt;]*)&lt;/span&gt;</city>
+				<zipcode>&lt;span class=&quot;postal-code&quot;&gt;([^&lt;]*)&lt;/span&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+1x">
+		<website name="caribbeanyellowpages.com" url="http://www.caribbeanyellowpages.com/yellowsearch.html?heading=$AREACODE$NUMBER&amp;submit2=Search&amp;ListingAgentFormat=eSYPE" prefix="" hidden="@HiddenXDoc&quot;\s*?value=&quot;([^&quot;]*)&quot;" nexturl="http://www.caribbeanyellowpages.com/ListBossPage.html?eRequestedPageType=ListingsByPhone&amp;ListingAgentFormat=eSUPE&amp;ClassID=&amp;ProductID=&amp;Tab=&amp;DoSetCookie=off&amp;Alphabet=&amp;DisableViewSwitch=false&amp;PageBossPageNumber=-1&amp;ListBossPageNumber=-1&amp;HiddenXDoc=$HIDDEN&amp;IProdItemID=&amp;originalquery=$AREACODE$NUMBER">
+			<entry>
+				<name>SUPEfindingLine[^&gt;]*&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;td\sstyle=&quot;padding-right:\s*4px;\s*padding-left:\s*4px;&quot;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+1345">
+		<website name="caymanislandsyp.com" url="http://www.caymanislandsyp.com/ListBossPage.html?heading=$PART1-$PART2&amp;submit2=Search&amp;ListingAgentFormat=eSYPE" prefix="" hidden="@HiddenXDoc&quot;\s*?value=&quot;([^&quot;]*)&quot;" nexturl="http://www.caymanislandsyp.com/ListBossPage.html?eRequestedPageType=ListingsByPhone&amp;ListingAgentFormat=eSUPE&amp;ClassID=&amp;ProductID=&amp;Tab=&amp;DoSetCookie=off&amp;Alphabet=&amp;DisableViewSwitch=false&amp;PageBossPageNumber=-1&amp;ListBossPageNumber=-1&amp;HiddenXDoc=$HIDDEN&amp;IProdItemID=&amp;originalquery=$NUMBER">
+			<entry>
+				<name>SUPEfindingLine&quot;?&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;td\sstyle=&quot;padding-right:\s*4px;\s*padding-left:\s*4px;&quot;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+1441">
+		<website name="bermudayp.com" url="http://www.informationpages.com/sys/pageserver.dll?b=43&amp;p=0&amp;s=-6&amp;f=&amp;gp=0&amp;go=$NUMBER" prefix="">
+			<entry>
+				<name>class.NameLink&quot;?&gt;([^&lt;]*)&lt;</name>
+				<street>ltext0&quot;?&gt;(?:&lt;t[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;td&gt;)?([^,]*),</street>
+				<city>ltext0&quot;?&gt;(?:&lt;t[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;[^&lt;]*&lt;td&gt;)?[^,]*,([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+1670">
+		<website name="cnmiphonebook.com" url="http://www.informationpages.com/sys/pageserver.dll?b=390&amp;p=1&amp;s=-4&amp;f=&amp;gp=&amp;go=$NUMBER" prefix="">
+			<entry>
+				<name>SPAN\sCLASS=WN\sSTYLE=&quot;(?:[^B]*)BACKGROUND-COLOR:#ccddff&quot;&gt;([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+1671">
+		<website name="cnmiphonebook.com" url="http://www.informationpages.com/sys/pageserver.dll?b=388&amp;p=1&amp;s=-4&amp;f=&amp;gp=&amp;go=$NUMBER" prefix="">
+			<entry>
+				<name>SPAN\sCLASS=WN\sSTYLE=&quot;BACKGROUND-COLOR:#ccddff&quot;&gt;([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+20">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Egypt" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$AREACODE$NUMBER&amp;substring=0&amp;Country=Egypt" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+221">
+		<website name="senegalphonebook.com" url="http://www.senegalphonebook.com/en/whitepages/?start=1&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+222">
+		<website name="mauritaniaphonebook.com" url="http://www.mauritaniaphonebook.com/en/whitepages/?start=1&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+223">
+		<website name="maliphonebook.com" url="http://www.maliphonebook.com/en/whitepages/?&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+224">
+		<website name="guineaphonebook.com" url="http://www.guineaphonebook.com/en/whitepages/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+225">
+		<website name="abc.ci" url="http://www.abc.ci/index.php?page=4&amp;numero=$NUMBER&amp;Submit=Rechercher" prefix="">
+			<entry>
+				<name>td\swidth=&quot;49%&quot;(?:[^&gt;]*?&gt;){3}([^&lt;]*?)&lt;</name>
+				<street>&lt;i&gt;\s*([^\s]*\s*[^\s]*\s*[^\s]*)\s</street>
+				<city>&lt;i&gt;\s*[^\s]*\s*[^\s]*\s*[^\s]*\s*([^&lt;]*?)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+226">
+		<website name="burkinaphonebook.com" url="http://www.burkinaphonebook.com/en/whitepages/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+227">
+		<website name="nigerphonebook.com" url="http://www.nigerphonebook.com/en/whitepages/?start=1&amp;q=$PART1-$PART2-$PART3-$PART4" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+228">
+		<website name="togophonebook.com" url="http://www.togophonebook.com/en/whitepages/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+229">
+		<website name="beninphonebook.com" url="http://www.beninphonebook.com/en/whitepages/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+230">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+		<website name="mauritius-yellow-pages.info" url="http://www.mauritius-yellow-pages.info/visitors_advanced_search_result_mauritius_yellow_pages.php?xcbocategory=0&amp;txtxoxphone=$NUMBER" nexturl="http://www.mauritius-yellow-pages.info/visitors_display_company_details_mauritius_yellow_pages.php?advertiserid=$HIDDEN" prefix="" hidden="visitors_display_company_details_mauritius_yellow_pages\.php\?advertiserid=(\d*)'">
+			<entry>
+				<name>&lt;title&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;b&gt;City:(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</street>
+				<city>&lt;b&gt;City:(?:[^&gt;]*?&gt;){11}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+236">
+		<website name="centralafricaphonebook.com" url="http://www.centralafricaphonebook.com/en/whitepages/?start=1&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+237">
+		<website name="cameroonphonebook.com" url="http://www.cameroonphonebook.com/en/whitepages/?start=1&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+238">
+		<website name="paginasamarelas.cv" url="http://www.paginasamarelas.cv/resultados_pesquisa.aspx?tipoMeio=1&amp;txtMeio=$NUMBER&amp;tipoPesq=a&amp;procura=s&amp;lang=pt" nexturl="http://www.paginasamarelas.cv/detalhe_pesquisa.aspx?id=$HIDDEN" prefix="" hidden="aspx\?id=(\d{5})">
+			<entry>
+				<name>&lt;b&gt;Nome:&lt;/b&gt;\s?([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>&lt;b&gt;Morada:&lt;/b&gt;\s?([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+239">
+		<website name="paginasamarelas.st" url="http://213.13.158.108/saotome/resultados_pesquisa.aspx?tipoMeio=1&amp;txtMeio=$NUMBER&amp;tipoPesq=a&amp;procura=s&amp;lang=pt" nexturl="http://213.13.158.108/saotome/detalhe_pesquisa.aspx?id=$HIDDEN" prefix="" hidden="aspx\?id=(\d{5})">
+			<entry>
+				<name>&lt;b&gt;Nome:&lt;/b&gt;\s?([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>&lt;b&gt;Morada:&lt;/b&gt;\s?([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+240">
+		<website name="malabophonebook.com" url="http://www.malabophonebook.com/pagesblanches/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+241">
+		<website name="gabonphonebook.com" url="http://www.gabonphonebook.com/en/whitepages/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+242">
+		<website name="congophonebook.com" url="http://www.congophonebook.com/en/whitepages/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+244">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+248">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+250">
+		<website name="rwandaphonebook.com" url="http://www.rwandaphonebook.com/en/whitepages/?&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+251">
+		<website name="ethiopiabook.com" url="http://www.ethiopiabook.com/whitepages/?start=1&amp;q=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+253">
+		<website name="djiboutiphonebook.com" url="http://www.djiboutiphonebook.com/pagesblanches/?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+254">
+		<website name="yellowpageskenya.com" url="http://www.yellowpageskenya.com/index.php?yp=1&amp;srchppltxt=$NUMBER&amp;search=search+for+people" prefix="">
+			<entry>
+				<name>div\sclass=.pagination(?:[^&gt;]*?&gt;){8}([^&lt;]*)&lt;</name>
+				<street>(P.\sO.\sBox\s\d{5})</street>
+				<city>P.\sO.\sBox\s\d{5}\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+255">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s\(0$AREACODE\)\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+257">
+		<website name="burundiphonebook.com" url="http://www.burundiphonebook.com/en/whitepages/?start=1&amp;q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;h4&gt;([^&lt;]*)&lt;</name>
+				<street>(?:&lt;address&gt;([^,^&lt;]*?,[^,^&lt;]*?),[^&lt;]*?&lt;)|(?:&lt;address&gt;([^,^&lt;]*?),[^&lt;]*?&lt;)</street>
+				<city>(?:&lt;address&gt;(?:[^,^&lt;]*?,){0,2}([^&lt;]*?)&lt;/address&gt;)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+258">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s(?:\(\d*?\)\s)$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+260">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s\(0$AREACODE\)\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+262">
+		<website name="infobel.com" url="http://infobel.com/en/france/Inverse.aspx?qPhone=0262$NUMBER&amp;qSelLang3=&amp;SubmitREV=Search&amp;inphCoordType=EPSG" prefix="">
+			<entry>
+				<name>div\sclass=.result-head.&gt;&lt;h3&gt;1\.\s*([^&lt;]*)&lt;</name>
+				<street>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;([^,]*),</street>
+				<city>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*\d{5}\s*([^&lt;]*)&lt;</city>
+				<zipcode>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*(\d{5})</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+263">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s\(0$AREACODE\)\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+		<website name="telone.co.zw" url="http://www.telone.co.zw/cgi-bin/searchdir.pl" prefix="" post="searchtxt=$NUMBER&amp;city=0$AREACODE&amp;I1.x=26&amp;I1.y=8&amp;searchcol=number&amp;searchcol1=resbus">
+			<entry>
+				<name>Address(?:[^&gt;]*?&gt;){8}([^&lt;]*)&lt;</name>
+				<street>Address(?:[^&gt;]*?&gt;){16}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+264">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s\(0$AREACODE\)\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+265">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s(?:\(09265\)\s)?$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+266">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s$PART1-$PART2">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+267">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$AREACODE$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s$AREACODE-$NUMBER">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+268">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$AREACODE$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s$AREACODE-$NUMBER">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*(?:&lt;br&gt;[^&lt;]*))&lt;|Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+269">
+		<website name="infobel.com" url="http://infobel.com/en/france/Inverse.aspx?qPhone=0269$NUMBER&amp;qSelLang3=&amp;SubmitREV=Search&amp;inphCoordType=EPSG" prefix="">
+			<entry>
+				<name>div\sclass=.result-head.&gt;&lt;h3&gt;1\.\s*([^&lt;]*)&lt;</name>
+				<street>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;([^,]*),</street>
+				<city>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*\d{5}\s*([^&lt;]*)&lt;</city>
+				<zipcode>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*(\d{5})</zipcode>
+			</entry>
+		</website>
+		<website name="comorestelecom.km" url="http://www.comorestelecom.km/annu_inverse.php?passage=1&amp;phone=$NUMBER&amp;Submit=Rechercher" prefix="">
+			<entry>
+				<name>Votre\srequ&amp;ecirc;te[^\d]*$NUMBER(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</name>
+				<street>Votre\srequ&amp;ecirc;te[^\d]*$NUMBER(?:[^&gt;]*&gt;){9}([^&amp;]*&amp;[^&amp;]*)</street>
+				<city>Votre\srequ&amp;ecirc;te[^\d]*$NUMBER(?:[^&gt;]*&gt;){9}(?:[^&amp;]*&amp;nbsp;){2}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+27">
+		<website name="brabys.co.za" url="http://www.brabys.co.za/search-Results.asp?region=-1&amp;town=-1&amp;numnum=$NUMBER" nexturl="http://www.brabys.co.za/$HIDDEN" prefix="" hidden="&lt;a\shref=&quot;([^&quot;]*)&quot;(?:[^&gt;]*&gt;){6}\s\(0$AREACODE\)">
+			<entry>
+				<name>font-size:\ssmaller;"(?:[^;]*;){3}([^&lt;]*)&lt;</name>
+				<street>Physical\sAddress(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>Physical\sAddress(?:[^&gt;]*?&gt;){6}([^&lt;]*&lt;br&gt;[^&lt;]*)&lt;</city>
+				<zipcode>Physical\sAddress(?:[^&gt;]*?&gt;){8}\s?([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+297">
+		<website name="arubian.net" url="http://arubian.net/cgi-bin/data.cgi" prefix="" post="pass=ok&amp;user=phonebook&amp;searchtype=any&amp;field=&amp;searchtext=$PART1-$PART2&amp;find=GO">
+			<entry>
+				<name>Address(?:[^&gt;]*?&gt;){3}&quot;([^&quot;]*)&quot;&lt;</name>
+				<street>Address(?:[^&gt;]*?&gt;){5}&quot;([^&quot;]*)&quot;&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+298">
+		<website name="nummar.fo" url="http://www.nummar.fo/urslit.php?leita=vidka&amp;nummar=$NUMBER" prefix="">
+			<entry>
+				<name>AutoNumber1(?:[^&gt;]*&gt;){10}([^,^&lt;]*),</name>
+				<street>AutoNumber1(?:[^&gt;]*&gt;){10}(?:[^,^&lt;]*),([^,^&lt;]*),[^&lt;]*&lt;</street>
+				<city>AutoNumber1(?:[^&gt;]*&gt;){10}(?:[^,^&lt;]*,[^,^&lt;]*,)([^&lt;]*)&lt;|AutoNumber1(?:[^&gt;]*&gt;){10}(?:[^,^&lt;]*,)([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+30">
+		<website name="whitepages.gr" url="http://www.whitepages.gr/en/results.aspx" prefix="" post="x_tel=$NUMBER">
+			<entry>
+				<name>&lt;td\sclass=&quot;text-black&quot;\sheight=&quot;46&quot;\svalign=&quot;top&quot;\salign=&quot;left&quot;\s?&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>reslist_ctl01_straddr[^&gt;]*&gt;([^&lt;]*)&lt;</street>
+				<city>reslist_ctl01_district[^&gt;]*&gt;([^&lt;]*)&lt;</city>
+				<zipcode>reslist_ctl01_postal[^&gt;]*&gt;([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+31">
+		<website name="www.nummerzoeker.com" url="http://www.nummerzoeker.com/?phone=$NUMBER&amp;maxrows=10&amp;page=0&amp;export=excel" prefix="0">
+			<entry>
+				<name>^[^,]*,([^,]*,[^,]*),[^,]*,[^,]*,[^,]*$</name>
+				<street>^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$</street>
+				<city>^[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$</city>
+				<zipcode>^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$</zipcode>
+			</entry>
+		</website>
+		<website name="www.gebeld.nl" url="http://www.gebeld.nl/content.asp?zapp=zapp&amp;land=Nederland&amp;zoek=numm&amp;searchfield1=fullnumber&amp;searchfield2=&amp;queryfield1=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;td&gt;&lt;font size=&quot;2&quot; face=&quot;Verdana, Arial, Helvetica, sans-serif&quot;&gt;([^&lt;]*)&lt;/font&gt;&lt;/td&gt;</name>
+				<street>&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;([^&lt;]+)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\s+&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;[^&lt;]+&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\s+&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;[^&lt;]+&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;</street>
+				<city>&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;[^&lt;]+&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\s+&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;[^&amp;]*&amp;nbsp;([^&lt;]+)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\s+&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;[^&lt;]+&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;</city>
+				<zipcode>&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;([^&lt;]+)&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\s+&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;([^&amp;]*)&amp;nbsp;[^&lt;]+&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;\s+&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;[^&lt;]+&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+32">
+		<website name="gebeld.nl" url="http://www.gebeld.nl/content.asp?zapp=zapp&amp;land=Belgie&amp;zoek=numm&amp;searchfield1=fullnumber&amp;searchfield2=&amp;queryfield1=$NUMBER" prefix="0">
+			<entry>
+				<name>/font(?:[^&gt;]*?&gt;){4}([^&lt;]*?)&lt;</name>
+				<street>/font(?:[^&gt;]*?&gt;){12}([^&lt;]*?)&lt;</street>
+				<city>/font(?:[^&gt;]*?&gt;){19}([^&amp;]*?)&amp;nbsp;</city>
+				<zipcode>/font(?:[^&gt;]*?&gt;){19}[^&amp;]*?&amp;nbsp;([^&lt;]*?)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+33">
+		<website name="www.annuaireinverse.com" url="http://88.175.61.166/G118012/home.asp?RN=$NUMBER&amp;CO=RN&amp;FR=118012&amp;sm=rep" prefix="0">;
+			<entry>
+				<name>&lt;TD HEIGHT=&quot;15&quot; BGCOLOR=&quot;#ABEEFB&quot;  &gt;&lt;FONT CLASS=&quot;ctexte&quot;&gt;&amp;nbsp;([^&lt;]*)</name>
+				<street>&lt;TD HEIGHT=&quot;35&quot; VALIGN=&quot;TOP&quot;&gt;&lt;FONT CLASS=&quot;copytexte&quot;&gt;([^&lt;]*)&lt;br /&gt;[^&lt;]*</street>
+				<city>&lt;TD HEIGHT=&quot;35&quot; VALIGN=&quot;TOP&quot;&gt;&lt;FONT CLASS=&quot;copytexte&quot;&gt;[^&lt;]*&lt;br /&gt;\d* ([^&lt;]*)</city>
+				<zipcode>&lt;TD HEIGHT=&quot;35&quot; VALIGN=&quot;TOP&quot;&gt;&lt;FONT CLASS=&quot;copytexte&quot;&gt;[^&lt;]*&lt;br /&gt;(\d*) [^&lt;]*</zipcode>
+			</entry>
+		</website>
+		<website name="www.annuaireinverse.com" url="http://www.annuaireinverse.com/G118012/home.asp?RN=$NUMBER&amp;CO=RN&amp;FR=118012&amp;sm=rep" prefix="0">;
+			<entry>
+				<name>&lt;TD HEIGHT=&quot;15&quot; BGCOLOR=&quot;#ABEEFB&quot;  &gt;&lt;FONT CLASS=&quot;ctexte&quot;&gt;&amp;nbsp;([^&lt;]*)</name>
+				<street>&lt;TD HEIGHT=&quot;35&quot; VALIGN=&quot;TOP&quot;&gt;&lt;FONT CLASS=&quot;copytexte&quot;&gt;([^&lt;]*)&lt;br /&gt;[^&lt;]*</street>
+				<city>&lt;TD HEIGHT=&quot;35&quot; VALIGN=&quot;TOP&quot;&gt;&lt;FONT CLASS=&quot;copytexte&quot;&gt;[^&lt;]*&lt;br /&gt;\d* ([^&lt;]*)</city>
+				<zipcode>&lt;TD HEIGHT=&quot;35&quot; VALIGN=&quot;TOP&quot;&gt;&lt;FONT CLASS=&quot;copytexte&quot;&gt;[^&lt;]*&lt;br /&gt;(\d*) [^&lt;]*</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+350">
+		<website name="gibyellow.gi" url="http://www.gibyellow.gi/number_results.asp?Number=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;strong&gt;([^&lt;]*?)&lt;/strong&gt;(?:[^&gt;]*?&gt;){7}$NUMBER&lt;</name>
+				<street>&lt;td class=&quot;name&quot;&gt;$NUMBER&lt;/td&gt;(?:[^v]+(?!a).){2}[^&gt;]*?&gt;([^&lt;]*?)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+351">
+		<website name="pai.pt" url="http://www.pai.pt/search/$NUMBER.html" prefix="">
+			<entry>
+				<name>bppost.&gt;([^&lt;]*?)&lt;</name>
+				<street>addrBlock\saddressTab\sact(?:[^&gt;]*?&gt;){2}\s*([^&lt;]*?)&lt;</street>
+				<city>addrBlock\saddressTab\sact(?:[^&gt;]*?&gt;){4}[^\s]*?\s([^&lt;]*?)&lt;</city>
+				<zipcode>addrBlock\saddressTab\sact(?:[^&gt;]*?&gt;){4}([^\s]*?)\s</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+352">
+		<website name="editustel.lu" url="http://www.editustel.lu/luxweb/neosearchAT.do?input=$NUMBER" prefix="">
+			<entry>
+				<name>raisSoc[^&gt;]*&gt;([^&lt;]*?)&lt;</name>
+				<street>raisSoc(?:[^&gt;]*?&gt;){5}([^&lt;]*?)&lt;</street>
+				<city>raisSoc(?:[^&gt;]*?&gt;){6}L-\d{4}&amp;nbsp;([^&lt;^\(]*)</city>
+				<zipcode>raisSoc(?:[^&gt;]*?&gt;){6}L-(\d{4})&amp;nbsp;</zipcode>
+			</entry>
+		</website>
+		<website name="infobel.com" url="http://infobel.com/en/luxembourg/Inverse.aspx?qPhone=$NUMBER&amp;qSelLang3=&amp;SubmitREV=Search&amp;inphCoordType=EPSG" prefix="">
+			<entry>
+				<name>ResNoPack2.&gt;&lt;tr&gt;&lt;td&gt;&lt;h3&gt;1\.\s*([^&lt;]*)&lt;</name>
+				<street>InfoItemNoPack[^&gt;]*&gt;([^,]*),</street>
+				<city>InfoItemNoPack[^&gt;]*&gt;[^,]*,[^\d]*\d{4}\s*([^&lt;]*)&lt;</city>
+				<zipcode>InfoItemNoPack[^&gt;]*&gt;[^,]*,[^\d]*(\d{4})</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+354">
+		<website name="simaskra.is" url="http://ja.is/gular?q=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;strong\sclass=&quot;name\sblack&quot;&gt;([^&lt;]*?)&lt;</name>
+				<street>&lt;em\sclass=&quot;home&quot;&gt;[^&gt;]*?&gt;([^&lt;]*?)&lt;</street>
+				<city>&lt;em\sclass=&quot;zone&quot;>[^\s]*?\s([^&lt;]*?)&lt;</city>
+				<zipcode>&lt;em\sclass=&quot;zone&quot;>([^\s]*?)\s[^&lt;]*?&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+355">
+		<website name="albanianyellowpages.com" url="http://www.albanianyellowpages.com/cgi-bin/yb/advanced2.pl?address1=Doesn%27t+Matter&amp;address2=Doesn%27t+Matter&amp;companyemailaddress=Doesn%27t+Matter&amp;dateadd=Doesn%27t+Matter&amp;datemod=Doesn%27t+Matter&amp;emailaddr=Doesn%27t+Matter&amp;homepage=Doesn%27t+Matter&amp;host=Doesn%27t+Matter&amp;id=Doesn%27t+Matter&amp;ip=Doesn%27t+Matter&amp;category=&amp;name=&amp;establish=&amp;city=&amp;state=&amp;zipcode=&amp;country=Doesn%27t+Matter&amp;phone=355+$AREACODE+$NUMBER&amp;fax=&amp;I1.x=0&amp;I1.y=0" prefix="" hidden="http://www.albanianyellowpages.com/cgi-bin/yb/org.pl\?id=([^&amp;]*)&amp;" nexturl="http://www.albanianyellowpages.com/cgi-bin/yb/org.pl?id=$HIDDEN&amp;formlist=advanced2&amp;formid=$HIDDEN&amp;begin=1&amp;end=1">
+			<entry>
+				<name>file\.gif(?:[^&gt;]*&gt;){9}([^&lt;]*?)&lt;</name>
+				<street>Address:(?:[^&gt;]*&gt;){6}([^&lt;]*?)&lt;</street>
+				<city>City:(?:[^&gt;]*&gt;){6}([^&lt;]*?)&lt;</city>
+				<zipcode>Zip\s*Code:(?:[^&gt;]*&gt;){6}([^&lt;]*?)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+356">
+		<website name="maltacom.com" url="http://www.maltacom.com/edirnew/modules/edir_checkquery.asp?g_telephone=$NUMBER" prefix="">
+			<entry>
+				<name>(?:&lt;td class=ln&gt;&lt;font class=fcbd&gt;)([^&lt;]*?)&lt;</name>
+				<street>PhoneNo(?:[^&gt;]*&gt;){30}([^&lt;]*)&lt;</street>
+				<city>PhoneNo(?:[^&gt;]*&gt;){34}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+358">
+		<website name="yritystele.fi" url="http://www.yritystele.fi/query?what=adv&amp;form=adv&amp;phone=$NUMBER" prefix="0">
+			<entry>
+				<name>toggleIPText(?:[^&gt;]*?&gt;){2}([^&lt;]*?)&lt;</name>
+				<street>toggleIPText(?:[^&gt;]*?&gt;){4}\s*?\|\s*?([^,]*?),</street>
+				<city>toggleIPText(?:[^&gt;]*?&gt;){4}(?:[^,]*?,){1,2}\s*\d{5}\s([^&lt;]*?)&lt;</city>
+				<zipcode>toggleIPText(?:[^&gt;]*?&gt;){4}(?:[^,]*?,){1,2}\s*(\d{5})\s[^&lt;]*?&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+36">
+		<website name="tudakozo.t-com.hu" url="http://www.tudakozo.t-com.hu/main?rand=6037541983298298990&amp;session_name=&amp;session_isFonetic=&amp;session_searchType=2&amp;session_custType=0&amp;session_location=&amp;session_zipcode=&amp;session_street=&amp;session_houseNo=&amp;session_areaCode=$AREACODE&amp;session_phoneNumber=$NUMBER&amp;session_queryType=2&amp;func0=firstQuery%28session_queryType%2Csession_custType%2Csession_searchType%2Csession_name%2Csession_location%2Csession_street%2Csession_zipcode%2Csession_houseNo%2Csession_isFonetic%2Csession_areaCode%2Csession_phoneNumber%29&amp;xsl=result&amp;xml=result&amp;func_newsess=&amp;OnError=xml%3Dmain%26xsl%3Dmain" prefix="">
+			<entry>
+				<name>onclick=&quot;getDatasheet[^&gt;]*?&gt;\(?([^&lt;^\(]*?)\(?&lt;</name>
+				<street>KiFindMet(?:[^&gt;]*?&gt;){3}:\s(?:[^,]*?,)(?:&amp;nbsp;)?([^&lt;]*?)&lt;</street>
+				<city>KiFindMet(?:[^&gt;]*?&gt;){3}:\s([^\d]*?)\d\d\d\d,</city>
+				<zipcode>KiFindMet(?:[^&gt;]*?&gt;){3}:\s(?:[^\d]*?)(\d\d\d\d),</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+370">
+		<website name="imones.lt" url="http://www.imones.lt/en/?submit=yes&amp;search=full&amp;page=full&amp;action=search&amp;qphone=$AREACODE$NUMBER" prefix="">
+			<entry>
+				<name>rowname(?:[^&gt;]*&gt;){2}([^&lt;]*)&lt;</name>
+				<street>rowadr&quot;&gt;\d{5}[^,]*,\s([^&lt;]*)&lt;|rowadr&quot;&gt;([^,]*),</street>
+				<city>rowadr&quot;&gt;\d{5}([^,]*),|rowadr&quot;&gt;[^,]*?,\s\d{5}\s([^&lt;]*)&lt;</city>
+				<zipcode>rowadr&quot;&gt;(\d{5})|rowadr&quot;&gt;[^,]*,\s(\d{5})\s[^&lt;]*&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+371">
+		<website name="zl.lv" url="http://www.zl.lv/portal/detail-search.php?comp=&amp;phone=$NUMBER&amp;meklet_detail=Suchen" prefix="">
+			<entry>
+				<name>tooltip[^&gt;]*?&gt;([^&lt;]*?)&lt;</name>
+				<street>tooltip(?:[^&gt;]*?&gt;){4}([^,]*?),</street>
+				<city>tooltip(?:[^&gt;]*?&gt;){4}[^,]*?,([^,]*?),</city>
+				<zipcode>tooltip(?:[^&gt;]*?&gt;){4}(?:[^,]*?,){2}([^&lt;]*?)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+372">
+		<website name="telemedia.ee" url="http://www.telemedia.ee/telemedia.php?lang=et&amp;tab=num&amp;list=on&amp;po=&amp;kw=$NUMBER&amp;pohi=on" prefix="">
+			<entry>
+				<name>favorlink3.&gt;([^&lt;]*?)&lt;</name>
+				<street>favorlink3.(?:[^&gt;]*?&gt;){10}(?:&amp;nbsp;)?(([^\s\d]+\s)+\d+?)</street>
+				<city>favorlink3.(?:[^&gt;]*?&gt;){10}(?: )?(?:[^\s\d]+\s)+\d+\s(([^\s]+\s)+)\d{5}</city>
+				<zipcode>favorlink3.(?:[^&gt;]*?&gt;){10}.+(\d{5})&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+375">
+		<website name="b2b.by" url="http://www.b2b.by/en/advanced.php?region=0&amp;tel=$NUMBER" prefix="">
+			<entry>
+				<name>a\shref=.infopage\.php[^&gt;]*&gt;([^&lt;]*)&lt;(?:[^&gt;]*&gt;){5}0$AREACODE</name>
+				<street>a\shref=.infopage\.php(?:[^&gt;]*?&gt;){4}(.+)\s[^&amp;]*&amp;....;\s\d{6}&lt;(?:[^&gt;]*&gt;){2}0$AREACODE</street>
+				<city>a\shref=.infopage\.php(?:[^&gt;]*?&gt;){4}.+\s([^&amp;]*)&amp;....;\s\d{6}&lt;(?:[^&gt;]*&gt;){2}0$AREACODE</city>
+				<zipcode>a\shref=.infopage\.php(?:[^&gt;]*?&gt;){4}.+(\d{6})&lt;(?:[^&gt;]*&gt;){2}0$AREACODE</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+378">
+		<website name="paginebianche.it" url="http://www.paginebianche.it/execute.cgi?btt=1&amp;tl=2&amp;tr=106&amp;tc=&amp;cb=&amp;qs=0549+$NUMBER" prefix="">
+			<entry>
+				<name>class=&quot;dati&quot;&gt;[^&gt;]*?&gt;([^&lt;]*)&lt;</name>
+				<street>class=&quot;dati&quot;&gt;(?:[^&gt;]*?&gt;){3}\d{5}&amp;nbsp;[^&amp;]*?[^-]*?-([^&lt;]*?)&lt;</street>
+				<city>class=&quot;dati&quot;&gt;(?:[^&gt;]*?&gt;){3}\d{5}&amp;nbsp;([^&amp;]*)[^-]*-[^&lt;]*&lt;</city>
+				<zipcode>class=&quot;dati&quot;&gt;(?:[^&gt;]*?&gt;){3}(\d{5})&amp;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+380">
+		<website name="business-ua.com" url="http://business-ua.com/advsearch.phtml?aphone=$NUMBER&amp;adv_sr=10" prefix="">
+			<entry>
+				<name>&lt;p\sclass=pt1>&lt;b&gt;([^&lt;]*)&lt;/b&gt;[^\(]*\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</name>
+				<street>&lt;p class=small&gt;\d*,\s[^,]*,([^&lt;]*)&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</street>
+				<city>&lt;p class=small&gt;\d*,\s([^,]*),[^&lt;]*&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</city>
+				<zipcode>&lt;p class=small&gt;(\d*),[^&lt;]*&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+381">
+		<website name="telekom.yu" url="http://www.telekom.yu/WhitePages/SearchPage.asp" prefix="" nexturl="http://www.telekom.yu/WhitePages/ResultPage.asp" post="Telefon=3444169&amp;Ulica=&amp;MG=011&amp;Ime=&amp;Broj=&amp;Mesto=&amp;Prezime=&amp;submit.x=38&amp;submit.y=12" hidden="(wrzlgrmpf)" cookie="\[([^;]*);">
+			<entry>
+				<name>&lt;p\sclass=pt1>&lt;b&gt;([^&lt;]*)&lt;/b&gt;[^\(]*\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</name>
+				<street>&lt;p class=small&gt;\d*,\s[^,]*,([^&lt;]*)&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</street>
+				<city>&lt;p class=small&gt;\d*,\s([^,]*),[^&lt;]*&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</city>
+				<zipcode>&lt;p class=small&gt;(\d*),[^&lt;]*&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\(0$AREACODE\)\s$NUMBER&lt;/p&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+385">
+		<website name="tportal.hr" url="http://www.tportal.hr/imenik/bijele.aspx?u=$NUMBER" prefix="0" hidden="@__VIEWSTATE&quot;\svalue=&quot;([^&quot;]*)&quot;" post="__VIEWSTATE=$HIDDEN&amp;tUpit=$NUMBER&amp;dizbor=0&amp;dzup=0&amp;tMjesto=&amp;tUlica=&amp;imbSearch.x=38&amp;imbSearch.y=14">
+			<entry>
+				<name>images/det.gif(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</name>
+				<street>prozor.focus\(\)&quot;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>prozor.focus\(\)&quot;&gt;([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+386">
+		<website name="rumenestrani.com" url="http://www.rumenestrani.com/Php3/show.php3?koren=checkbox&amp;naziv2=&amp;priimek2=&amp;x=0&amp;y=0&amp;telefonska2=$NUMBER&amp;regija2=All+regions&amp;obcina2=All+municipalities&amp;naselje2=&amp;ulica2=&amp;hisna2=&amp;posta2=&amp;eposta2=&amp;internet2=&amp;davcna2=&amp;dejavnost2=&amp;storitve2=&amp;omrezna%5B1%5D=61&amp;omrezna%5B7%5D=64&amp;omrezna%5B2%5D=62&amp;omrezna%5B8%5D=65&amp;omrezna%5B3%5D=602&amp;omrezna%5B9%5D=66&amp;omrezna%5B4%5D=69&amp;omrezna%5B10%5D=67&amp;omrezna%5B5%5D=63&amp;omrezna%5B11%5D=68&amp;omrezna%5B6%5D=601&amp;omrezna%5B12%5D=608&amp;iskanje=napredno" prefix="">
+			<entry>
+				<name>href=/Php3/show.php3.un_id[^&gt;]*?&gt;([^&lt;]*)&lt;</name>
+				<street>href=/Php3/show.php3.un_id(?:[^&gt;]*?&gt;){5}([^&lt;]*)&lt;</street>
+				<city>href=/Php3/show.php3.un_id(?:[^&gt;]*?&gt;){6}\d*.([^&lt;]*)&lt;</city>
+				<zipcode>href=/Php3/show.php3.un_id(?:[^&gt;]*?&gt;){6}(\d*)\s</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+387">
+		<website name="bhtelecom.ba" url="http://www.bhtelecom.ba/telefon_imenik.html" prefix="" hidden="id=&quot;_uqid&quot;\svalue=&quot;([^&quot;]*)&quot;$id=&quot;_cdt&quot;\svalue=&quot;([^&quot;]*)&quot;$" post="di=033&amp;br=215277&amp;btnSearch=Trazi&amp;_uqid=$HIDDEN1&amp;_cdt=$HIDDEN2&amp;_hsh=%23%23%23HSH%23%23%23" nexturl="http://www.bhtelecom.ba/index.php?id=536&amp;a=search" cookie="\[([^]]*)\]">
+			<entry>
+				<name>&lt;p\sclass=pt1>&lt;b&gt;([^&lt;]*)&lt;/b&gt;[^\(]*\($AREACODE\)\s$NUMBER&lt;/p&gt;</name>
+				<street>&lt;p class=small&gt;\d*,\s[^,]*,([^&lt;]*)&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\($AREACODE\)\s$NUMBER&lt;/p&gt;</street>
+				<city>&lt;p class=small&gt;\d*,\s([^,]*),[^&lt;]*&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\($AREACODE\)\s$NUMBER&lt;/p&gt;</city>
+				<zipcode>&lt;p class=small&gt;(\d*),[^&lt;]*&lt;/p&gt;&lt;/td&gt;&lt;td colspan=5\swidth=90\salign=left\svalign=center&gt;&lt;p\sclass=small&gt;\($AREACODE\)\s$NUMBER&lt;/p&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+39">
+		<website name="paginebianche.it" url="http://www.paginebianche.it/execute.cgi?btt=1&amp;ts=106&amp;cb=8&amp;mr=10&amp;rk=&amp;om=&amp;qs=$NUMBER" prefix="0">
+			<entry>
+				<name>class="org"&gt;([^&lt;]*)</name>
+				<street>class="street-address">([^&lt;]*)</street>
+				<city>class="locality">([^&lt;]*)</city>
+				<zipcode>class="postal-code">([^&lt;]*)</zipcode>
+			</entry>
+			<entry>
+				<name>&lt;a [^&gt;]*&gt;&lt;img [^&gt;]*&gt;&lt;/a&gt;&lt;a [^&gt;]*&gt;([^&lt;]*)</name>
+				<street>&lt;font [^&gt;]*&gt;[0-9]*&amp;nbsp;[^&amp;]*[^-]*-([^&lt;]*)&lt;</street>
+				<city>&lt;font [^&gt;]*&gt;[0-9]*&amp;nbsp;([^&amp;]*)[^-]*-[^&lt;]*&lt;</city>
+				<zipcode>&lt;font [^&gt;]*&gt;([0-9]*)&amp;nbsp;[^&amp;]*[^-]*-[^&lt;]*&lt;</zipcode>
+			</entry>
+			<entry>
+				<name>&lt;td class=&quot;dati&quot;&gt;&lt;span [^&gt;]*&gt;([^&lt;]*)&lt;/span&gt;&lt;br&gt;[0-9]*&amp;nbsp;[^&amp;]*[^-]*-[^&lt;]*&lt;</name>
+				<street>&lt;td class=&quot;dati&quot;&gt;&lt;span [^&gt;]*&gt;[^&lt;]*&lt;/span&gt;&lt;br&gt;[0-9]*&amp;nbsp;[^&amp;]*[^-]*-([^&lt;]*)&lt;</street>
+				<city>&lt;td class=&quot;dati&quot;&gt;&lt;span [^&gt;]*&gt;[^&lt;]*&lt;/span>&lt;br&gt;[0-9]*&amp;nbsp;([^&amp;]*)[^-]*-[^&lt;]*&lt;</city>
+				<zipcode>&lt;td class=&quot;dati&quot;&gt;&lt;span [^&gt;]*&gt;[^&lt;]*&lt;/span&gt;&lt;br&gt;([0-9]*)&amp;nbsp;[^&amp;]*[^-]*-[^&lt;]*&lt;</zipcode>
+			</entry>
+		</website>
+		<website name="infobel.com" url="http://www.infobel.com/it/Italy/Inverse.aspx?qPhone=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;div class="result-item"&gt;&lt;h[1-9]&gt;1. (?:&lt;a href=&quot;[^&quot;]*&quot;&gt;)?([^&lt;]*)(?:&lt;/a&gt;)?&lt;!--[^&lt;]*&lt;/h[1-9]&gt;</name>
+				<street>&lt;div class=&quot;result-box-col&quot;&gt;&lt;div&gt;&lt;strong&gt;([^,]*),.[0-9]+\s*[^&lt;]*&lt;/strong&gt;&lt;/div&gt;</street>
+				<city>&lt;div class=&quot;result-box-col&quot;&gt;&lt;div&gt;&lt;strong&gt;[^,]*,.[0-9]+\s*([^&lt;]*)&lt;/strong&gt;&lt;/div&gt;</city>
+				<zipcode>&lt;div class=&quot;result-box-col&quot;&gt;&lt;div&gt;&lt;strong&gt;[^,]*,.([0-9]+)\s*[^&lt;]*&lt;/strong&gt;&lt;/div&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+41">
+		<website name ="tel.local.ch" url="http://tel.local.ch/de/q/?ext=1&amp;phone=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;h[1-9](?:&gt;&lt;a)?\sclass=&quot;fn&quot;[^&gt;]*&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span class=&quot;street-address&quot;&gt;([^&lt;]*)&lt;/span&gt;</street>
+				<city>&lt;span class=&quot;locality&quot;&gt;([^&lt;]*)&lt;/span&gt;</city>
+				<zipcode>&lt;span class=&quot;postal-code&quot;>([^&lt;]*)&lt;/span&gt;</zipcode>
+			</entry>
+		</website>		
+		<website name="tel.search.ch" url="http://tel.search.ch/result.html?tel=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;div class=&quot;rname&quot;&gt;&lt;h[1-9]*&gt;&lt;a[^&gt;]*&gt;([^&lt;]*)&lt;/a&gt;</name>
+				<street>&lt;div class=&quot;raddr&quot;&gt;([^,]*),\s*&lt;span class=&quot;tel_addrpart&quot;&gt;\s*[0-9]*[^&lt;]*&lt;/span&gt;&lt;/div&gt;</street>
+				<city>&lt;div class=&quot;raddr&quot;&gt;[^,]*,\s*&lt;span class=&quot;tel_addrpart&quot;&gt;\s*[0-9]*([^&lt;/]*)(?:/[^&lt;]*)?&lt;/span&gt;&lt;/div&gt;</city>
+				<zipcode>&lt;div class=&quot;raddr&quot;&gt;[^,]*,\s*&lt;span class=&quot;tel_addrpart&quot;&gt;\s*([0-9]*)[^&lt;]*&lt;/span&gt;&lt;/div&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+423">
+		<website name="tel.search.ch" url="http://tel.search.ch/result.html?tel=00423$NUMBER" prefix="">
+			<entry>
+				<name>&lt;div class=&quot;rname&quot;&gt;&lt;h[1-9]&gt;&lt;a[^&gt;]*&gt;([^&lt;]*)&lt;/a&gt;</name>
+				<street>&lt;div class=&quot;raddr&quot;&gt;([^&lt;,]*),\s*[0-9]*[^&lt;]*&lt;/div&gt;</street>
+				<city>&lt;div class=&quot;raddr&quot;&gt;[^&lt;,]*,\s*[0-9]*([^&lt;^/]*)(?:/FL)?&lt;/div&gt;</city>
+				<zipcode>&lt;div class=&quot;raddr&quot;&gt;[^&lt;,]*,\s*([0-9]*)[^&lt;]*&lt;/div&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+43">
+		<website name="herold.at (Privat)" url="http://www.herold.at/servlet/at.herold.sp.servlet.SPWPSearchServlet?searchmask=2&amp;phone=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;h[1-9]&gt;&lt;a href=&quot;[^&quot;]*&quot;(?:\s*class=&quot;bold&quot;)?&gt;([^&lt;]*)&lt;/a&gt;&lt;/h[1-9]&gt;</name>
+				<street>&lt;div class=&quot;addrF&quot;&gt;&lt;p(?:\sclass=&quot;bold&quot;)?&gt;\s*(?:[^&lt;]+&lt;br/&gt;)?[^,]*,\s*([^&lt;]*)&lt;br&gt;&lt;/br&gt;&lt;/p&gt;</street>
+				<city>&lt;div class=&quot;addrF&quot;&gt;&lt;p(?:\sclass=&quot;bold&quot;)?&gt;\s*(?:[^&lt;]+&lt;br/&gt;)?\d+ ([^,]*),\s*[^&lt;]*&lt;br&gt;&lt;/br&gt;&lt;/p&gt;</city>
+				<zipcode>&lt;div class=&quot;addrF&quot;&gt;&lt;p(?:\sclass=&quot;bold&quot;)?&gt;\s*(?:[^&lt;]+&lt;br/&gt;)?(\d+) [^,]*,\s*[^&lt;]*&lt;br&gt;&lt;/br&gt;&lt;/p&gt;</zipcode>
+			</entry>
+		</website>
+		<website name="herold.at (Firma)" url="http://www.herold.at/servlet/at.herold.sp.servlet.SPYPSearchServlet?searchmask=2&amp;phone=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;h[1-9]&gt;&lt;a href=&quot;[^&quot;]*&quot;\s*class=&quot;bold&quot;&gt;([^&lt;]*)&lt;/a&gt;&lt;/h[1-9]&gt;</name>
+				<street>&lt;div class=&quot;addrF&quot;&gt;&lt;p class=&quot;bold&quot;&gt;\s*[^,]*,\s*([^&lt;]*)&lt;br/&gt;&lt;/p&gt;</street>
+				<city>&lt;div class=&quot;addrF&quot;&gt;&lt;p class=&quot;bold&quot;&gt;\s*[^\s]*([^,]*),\s[^&lt;]*&lt;br/&gt;&lt;/p&gt;</city>
+				<zipcode>&lt;div class=&quot;addrF&quot;&gt;&lt;p class=&quot;bold&quot;&gt;\s*([^\s]*)\s[^,]*,\s*[^&lt;]*&lt;br/&gt;&lt;/p&gt;</zipcode>
+			</entry>
+		</website>
+		<website name="tb-online.at" url="http://www.tb-online.at/index.php?pc=in&amp;telnummer=$NUMBER&amp;aktion=suchein" prefix="0">
+			<entry>
+				<!-- 
+				zipcode hidden as image...
+				-->
+				<name>&lt;p\s*class=&quot;name&quot;&gt;\s*([^&lt;]*)&lt;/p&gt;</name>
+				<street>&lt;p&gt;([^&lt;]*)&lt;/p&gt;\s*&lt;p&gt;&lt;img class=&quot;img&quot; src=&quot;grafikpng.php?[^&gt;]*&gt;&amp;nbsp;[^&lt;]*&lt;/p&gt;</street>
+				<city>&lt;p&gt;[^&lt;]*&lt;/p&gt;\s*&lt;p&gt;&lt;img class=&quot;img&quot; src=&quot;grafikpng.php?[^&gt;]*&gt;&amp;nbsp;([^&lt;]*)&lt;/p&gt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>				
+	</country>	
+	<country code="+45">
+		<website name="degulesider.dk" url="http://www.degulesider.dk/vbw/super/resultat.do?twoFieldName=$NUMBER&amp;twoFieldAddr=&amp;Image52.x=0&amp;Image52.y=0" prefix="0">
+			<entry>
+				<name>&lt;!--\sCompany Name\s--&gt;[^&gt;]*&gt;\s*([^&lt;]*)&lt;</name>
+				<street>&lt;!--\sCompany Address\s--&gt;\s*([^&lt;]*)&lt;</street>
+				<city>&lt;!--\sCompany Address\s--&gt;[^&gt;]*&gt;\s*?\d\d\d\d\s?([^&lt;]*)&lt;</city>
+				<zipcode>&lt;!--\sCompany Address\s--&gt;[^&gt;]*&gt;\s*?(\d\d\d\d)[^&lt;]*&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+46">
+		<website name="privatpersoner.eniro.se" url="http://privatpersoner.eniro.se/query?what=wp&amp;search_word=$NUMBER&amp;geo_area=" prefix="0">
+			<entry>
+				<name>fn expand(?:(?:.*owner-of-cell)|[^&gt;]*&gt;)[^&gt;]*&gt;([^&lt;]*)&lt;</name>
+				<street>street-address&quot;?&gt;([^&lt;]*)&lt;</street>
+				<city>locality&quot;?&gt;([^&lt;]*)&lt;</city>
+				<zipcode>postal-code&quot;?&gt;([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+47">
+		<website name="gulesider.no" url="http://www.gulesider.no/gs/categoryList.c?q=$NUMBER" prefix="0">
+			<entry>
+				<name>RESULT.ITEM.START(?:[^&gt;]*&gt;)+([^&lt;]*?)&lt;/h2&gt;</name>
+				<street>title=.Kart.&gt;([^,]*?),</street>
+				<city>title=.Kart.&gt;(?:[^,]*?,)+\s*?\d{4}\s([^&lt;]*?)&lt;</city>
+				<zipcode>title=.Kart.&gt;(?:[^,]*?,)+\s*?(\d{4})\s[^&lt;]*?&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+48">
+		<website name="teleadreson.pl" url="http://www.teleadreson.pl/" prefix="" post="searchtext=&amp;english=yes&amp;database=TADRES%2FADDR.&amp;menuitem=searchname&amp;obrotrange_min=0&amp;obrotrange_max=1000000000&amp;rokrange_min=0&amp;rokrange_max=9999&amp;liczbarange_min=0&amp;liczbarange_max=1000000000&amp;listreportstat=report&amp;listlimit=20&amp;vindexfirst=0&amp;recordnumberlast=1&amp;vindex=0&amp;recordnumber=1&amp;currenthtmlpage=HomePage&amp;flagset=&amp;database=TADRES%2FADDR.&amp;listlimit=20&amp;flagset=&amp;searchtext=%28$AREACODE%29$NUMBER&amp;searchsubmit=Search&amp;nacetext=&amp;sictext=&amp;pnatext=&amp;obrotrange_min=0&amp;obrotrange_max=1000000000&amp;rokrange_min=0&amp;rokrange_max=9999&amp;liczbarange_min=0&amp;liczbarange_max=1000000000&amp;listreportstat=report">
+			<entry>
+				<name>Company\sname(?:[^&gt;]*&gt;){3}([^&lt;]*?)&lt;</name>
+				<street>Address(?:[^&gt;]*&gt;){3}([^&lt;]*?)&lt;</street>
+				<city>City(?:[^&gt;]*&gt;){3}([^&lt;]*?)&lt;</city>
+				<zipcode>Zip\scode(?:[^&gt;]*&gt;){3}([^&lt;]*?)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+49">
+		<website name="www.dasoertliche.de" url="http://dasoertliche.de/?form_name=search_inv&amp;page=RUECKSUCHE&amp;context=RUECKSUCHE&amp;action=STANDARDSUCHE&amp;la=de&amp;rci=no&amp;ph=$NUMBER" prefix="0">
+	        <entry>
+	        	<name>class=&quot;entry&quot;\s*(?:onmouseover=&quot;&quot;)?\s*&gt;([^&lt;]*)&lt;/a&gt;</name>
+	        	<street>^\s*([^,&gt;]+),&amp;nbsp;\d{5}&amp;nbsp;[^&lt;]*&lt;br/&gt;</street>
+	        	<city>^[^,]*,&amp;nbsp;\d{5}&amp;nbsp;([^&lt;]*)&lt;br/&gt;</city>
+	        	<zipcode>^[^,]*,&amp;nbsp;(\d{5})&amp;nbsp;[^&lt;]*&lt;br/&gt;</zipcode>
+	        </entry>
+		</website>
+		<website name="www.dastelefonbuch.de" url="http://www.dastelefonbuch.de/?sourceid=Mozilla-search&amp;cmd=search&amp;kw=$NUMBER" prefix="0">
+			<entry>
+				<name>&lt;td\sclass=&quot;col1&quot;&gt;[^&gt;]*&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;td\sclass=&quot;col2&quot;&gt;([^&lt;]*)&lt;</street>
+				<city>&lt;td class=&quot;col3&quot;&gt;\d{5}&amp;nbsp;([^&lt;]*)&lt;</city>
+				<zipcode>&lt;td class=&quot;col3&quot;&gt;(\d{5})</zipcode>
+			</entry>
+		</website>
+<!-- this appears not to be working correctly. Klicktel tries to "guess" numbers by stripping the last digits
+		<website name="www.klicktel.de" url="http://www.klicktel.de/inverssuche/backwardssearch.html?newSearch=1&amp;boxtype=backwards&amp;vollstaendig=$NUMBER" prefix="0">
+	        <entry>
+	        	<name>class=&quot;title&quot;&gt;([^&lt;]+)&lt;/span&gt;</name>
+	        	<street>class=&quot;location&quot;&gt;([^&lt;]+)&lt;br /&gt;\d{5}\s+[^&lt;]+&lt;/span&gt;</street>
+	        	<city>class=&quot;location&quot;&gt;[^&lt;]+&lt;br /&gt;\d{5}\s+([^&lt;]+)&lt;/span&gt;</city>
+	        	<zipcode>class=&quot;location&quot;&gt;[^&lt;]+&lt;br /&gt;(\d{5})\s+[^&lt;]+&lt;/span&gt;</zipcode>
+	        </entry>
+		</website>
+-->
+		<website name="www.goyellow.de" url="http://www.goyellow.de/inverssuche/?TEL=$NUMBER" prefix="0">
+	        <entry>
+	        	<name>&lt;a href=&quot;[^&quot;]*&quot; onClick=&quot;[^&quot;]*&quot; title=&quot;[^&quot;]*&quot;&gt;([^&lt;]*)&lt;/a&gt;</name>
+		  		<street>&lt;p class=&quot;address&quot;&gt;([^&lt;]*)&lt;br /&gt;[\d]*\s*[^&lt;]*&lt;/p&gt;</street>
+	        	<city>&lt;p class=&quot;address&quot;&gt;[^&lt;]*&lt;br /&gt;[\d]*\s*([^&lt;]*)&lt;/p&gt;</city>
+	        	<zipcode>&lt;p class=&quot;address&quot;&gt;[^&lt;]*&lt;br /&gt;([\d]*)\s*[^&lt;]*&lt;/p&gt;</zipcode>
+	        </entry>
+		</website>
+		<website name="www.11880.com" url="http://www.11880.com/Suche/index.cfm?fuseaction=Suche.rueckwaertssucheresult&amp;init=true&amp;tel=$NUMBER" prefix="0">
+	        <entry>
+	        	<name>&lt;a style=&quot;text-decoration: underline;&quot; href=&quot;[^&quot;]*&quot; onclick=&quot;[^&quot;]*&quot; class=&quot;popup&quot;[^&gt;]*&gt;([^&lt;]*)&lt;/a&gt;</name>
+	        	<street>^\s*([^,]*), [\d]{5} [^&lt;]*&lt;br /&gt;</street>
+	        	<city>^\s*[^,]*, [\d]{5} ([^&lt;]*)&lt;br /&gt;</city>
+	        	<zipcode>^\s*[^,]*, ([\d]{5}) [^&lt;]*&lt;br /&gt;</zipcode>
+	        </entry>
+		</website>
+	</country>
+	<country code="+501">
+		<website name="belizeweb.com" url="http://www.belizeweb.com:8080/directory/index-new.jsp" cookie="(JSESSIONID=[^;]*);" nexturl="http://www.belizeweb.com:8080/directory/index-new.jsp?dirlist=$PART1-$PART2&amp;imageField.x=0&amp;imageField.y=0&amp;maxrecords=5" post="" hidden="(wrzlgrmpf)" prefix="">
+			<entry>
+				<name>Phone\sNumber(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+502">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=3&amp;npa=Guatemala&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Guatemala\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+503">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=2&amp;npa=El+Salvador&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}El Salvador\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+504">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=7&amp;npa=Honduras&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Honduras\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+505">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=5&amp;npa=Nicaragua&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Nicaragua\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+506">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=8&amp;npa=Costa+Rica&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Costa Rica\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+507">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=4&amp;npa=Panam%e1&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Panam%e1\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+508">
+		<website name="cheznoo.net" url="http://www.cheznoo.net/portaildata/annuaire/resultats.php" prefix="" post="nom=&amp;num=$NUMBER&amp;Recherche.x=27&amp;Recherche.y=11&amp;search_info=r1">
+			<entry>
+				<name>pour\s&lt;b&gt;(?:[^&gt;]*&gt;){12}(?:&amp;nbsp;)?([^&lt;]*)&lt;</name>
+				<street>pour\s&lt;b&gt;(?:[^&gt;]*&gt;){22}(?:&amp;nbsp;)?([^&lt;^:]*)::</street>
+				<city>pour\s&lt;b&gt;(?:[^&gt;]*&gt;){22}[^&lt;^:]*::([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+51">
+		<website name="paginasblancas.com.pe" url="http://paginasblancas.com.pe/resultados.asp?t=$NUMBER&amp;d=$CODE" prefix="">
+			<entry>
+				<name>Table12(?:[^&gt;]*?&gt;){6}([^&lt;]*)&lt;</name>
+				<street>cel05[^&gt;]*?&gt;([^&lt;]*)&lt;</street>
+				<city>cel05(?:[^&gt;]*?&gt;){2}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+52">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=9&amp;npa=M%e9xico&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}M%e9xico\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+54">
+		<website name="paginasdoradas.com" url="http://www.paginasdoradas.com/BuscarTelefonica.action?apellido=&amp;provinciasId=0&amp;localidad.descripcion=&amp;telefono.area=0$AREACODE&amp;telefono.prefijo=$PART1&amp;telefono.sufijo=$PART2" prefix="">
+			<entry>
+				<name>titu1[^&gt;]*&gt;([^&lt;]*)&lt;</name>
+				<street>textgris[^&gt;]*&gt;&lt;strong&gt;([^&lt;]*)&lt;</street>
+				<city>textgris[^&gt;]*&gt;&lt;strong&gt;[^&gt;]*&gt;\s-\s([^-]*)-</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+55">
+		<website name="listaonline.com.br" url="http://www.listaonline.com.br/pagamanet/web/companyCategory.aspx?ipa=16&amp;npa=Brasil&amp;ies=$CODE&amp;idi=3&amp;sp=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+56">
+		<website name="chilnet.cl" url="http://www.chilnet.cl/SE/results.asp?keywords=$NUMBER&amp;wordstype=ALL&amp;notkeyword=&amp;optcategory=companies&amp;optSearchBy=phonphone&amp;Countrychk=1&amp;optArea=ALL&amp;chkCompBranchs=branchs" prefix="" hidden="&lt;a\shref=&quot;/rc/company/results_company_mbr\.asp\?meco_code=([^&quot;]*)&quot;&gt;" nexturl="http://www.chilnet.cl/rc/company/results_company_mbr.asp?meco_code=$HIDDEN">
+			<entry>
+				<name>tradename&quot;&gt;([^&lt;]*)&lt;</name>
+				<street>taxid(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>taxid(?:[^&gt;]*&gt;){8}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+58">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=15&amp;npa=Venezuela&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Venezuela\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+590">
+		<website name="infobel.com" url="http://infobel.com/en/france/Inverse.aspx?qPhone=0590$NUMBER&amp;qSelLang3=&amp;SubmitREV=Search&amp;inphCoordType=EPSG" prefix="">
+			<entry>
+				<name>div\sclass=.result-head.&gt;&lt;h3&gt;1\.\s*([^&lt;]*)&lt;</name>
+				<street>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;([^,]*),</street>
+				<city>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*\d{5}\s*([^&lt;]*)&lt;</city>
+				<zipcode>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*(\d{5})</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+591">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=22&amp;npa=Bolivia&amp;ies=$CODE&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Costa Rica\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+593">
+		<website name="paginasamarillas.com" url="http://www.paginasamarillas.com/pagamanet/web/companyCategory.aspx?ipa=6&amp;npa=Ecuador&amp;ies=*&amp;idi=2&amp;txb=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=.txtTitleBlack.&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){3}([^&lt;]*)&lt;</street>
+				<city>&lt;span\sclass=.txtTitleBlack.&gt;(?:[^&gt;]*&gt;){5}Ecuador\s-\s([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+594">
+		<website name="infobel.com" url="http://infobel.com/en/france/Inverse.aspx?qPhone=0594$NUMBER&amp;qSelLang3=&amp;SubmitREV=Search&amp;inphCoordType=EPSG" prefix="">
+			<entry>
+				<name>div\sclass=.result-head.&gt;&lt;h3&gt;1\.\s*([^&lt;]*)&lt;</name>
+				<street>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;([^,]*),</street>
+				<city>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*\d{5}\s*([^&lt;]*)&lt;</city>
+				<zipcode>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*(\d{5})</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+595">
+		<website name="guiaslatinas.com.py" url="http://www.guiaslatinas.com.py/apag.php?mod=2&amp;ciu=0&amp;tel=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;span\sclass=resul&gt;([^&lt;]*)&lt;(?:[^&gt;]*?&gt;){10}[^\(]*\(0$AREACODE\)</name>
+				<street>&lt;b&gt;Direcci%f3n\s?:&lt;/b&gt;&lt;br&gt;([^&lt;]*)&lt;br&gt;[^\(]*\(0$AREACODE\)</street>
+				<city>&lt;b&gt;Direcci%f3n\s?:&lt;/b&gt;&lt;br&gt;[^&lt;]*&lt;br&gt;([^\(]*)\(0$AREACODE\)</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+596">
+		<website name="infobel.com" url="http://infobel.com/en/france/Inverse.aspx?qPhone=0596$NUMBER&amp;qSelLang3=&amp;SubmitREV=Search&amp;inphCoordType=EPSG" prefix="">
+			<entry>
+				<name>div\sclass=.result-head.&gt;&lt;h3&gt;1\.\s*([^&lt;]*)&lt;</name>
+				<street>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;([^,]*),</street>
+				<city>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*\d{5}\s*([^&lt;]*)&lt;</city>
+				<zipcode>div\sclass=.result-box-col.&gt;&lt;div&gt;&lt;strong&gt;[^,]*,[^\d]*(\d{5})</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+63">
+		<website name="pinoysearch.com" url="http://www.pinoysearch.com/index.php?view=r&amp;telno=$NUMBER&amp;Submit=Search" prefix="" nexturl="http://www.pinoysearch.com/$HIDDEN" hidden="sresult&quot;&gt;&lt;a\shref=&quot;([^&quot;]*)&quot;">
+			<entry>
+				<name>class=&quot;sresult2&quot;&gt;(?:&lt;br/&gt;)?&lt;b&gt;([^&lt;]*(?:&lt;/b&gt;[^&lt;]*)?)&lt;</name>
+				<street>Address\s:&lt;/td&gt;&lt;td&gt;([^&lt;]*)&lt;</street>
+				<city>Town/City\s:&lt;/td&gt;&lt;td&gt;([^&lt;]*)&lt;</city>
+				<zipcode>ZIP\sCode\s:&lt;/td&gt;&lt;td&gt;([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+65">
+		<website name="yellowpages.com.sg" url="http://www.yellowpages.com.sg/newiyp/wp/newwpsearch2008.do?searchCriteria=Company+Name+%2F+Residential&amp;phoneCriteria=$NUMBER&amp;locTerm=00&amp;stype=7&amp;applicationInd=wp&amp;searchType=4&amp;accessType=1&amp;productType=EIB&amp;searchTab=phoneTab&amp;areaCode=00" prefix="">
+			<entry>
+				<name>advertiserName=(.*?)&amp;amp;url</name>
+				<street>()</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+678">
+		<website name="vatu.com" url="http://www.vatu.com/index.php?p=an&amp;t=pb&amp;request=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;b&gt;name\sand\saddress(?:[^&gt;]*?&gt;){7}([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+689">
+		<website name="annuaireopt.pf" url="http://www.annuaireopt.pf/list_inv.jsp?nom=$NUMBER&amp;submit=Search" prefix="">
+			<entry>
+				<name>pginvtitre(?:[^&gt;]*?&gt;){2}([^&lt;]*)&lt;</name>
+				<street>pginvdesc(?:[^&gt;]*?&gt;){2}([^&lt;]*)&lt;br&gt;[^&lt;]*&lt;</street>
+				<city>pginvdesc(?:[^&gt;]*?&gt;){2}[^&lt;]*&lt;br&gt;[^&lt;]*&lt;br&gt;([^&lt;]*)&lt;</city>
+				<zipcode>pginvdesc(?:[^&gt;]*?&gt;){2}[^&lt;]*&lt;br&gt;([^&lt;]*)&lt;br&gt;[^&lt;]*&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+691">
+		<website name="telecom.fm" url="http://telecom.fm/cgi/phonebook.exe" prefix="" post="exchange=$AREACODE&amp;line=$NUMBER">
+			<entry>
+				<name>class=&quot;ph_na&quot;&gt;([^&lt;]*)&lt;</name>
+				<street>()</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+7">
+		<website name="yellowpages.ru" url="http://www.yellowpages.ru/eng/nd$CODE/qu7/sq30/wophone%3A$NUMBER" hidden="&lt;a\shref\=&quot;([^&quot;]*)&quot;\sclass\=&quot;comp_header" nexturl="http://www.yellowpages.ru$HIDDEN" prefix="">
+			<entry>
+				<name>Postal\saddress\s([^:]*):</name>
+				<street>target=&quot;_blank&quot;&gt;\d{6}&lt;/a&gt;,\s*[^,]*,([^&lt;]*)&lt;</street>
+				<city>target=&quot;_blank&quot;&gt;\d{6}&lt;/a&gt;,\s*([^,]*),</city>
+				<zipcode>target=&quot;_blank&quot;&gt;(\d{6})&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+731">
+		<website name="yellow-pages.kz" url="http://www.yellow-pages.kz/kz/en/phone_search/0/1/$NUMBER" prefix="">
+			<entry>
+				<name>&lt;/noindex&gt;&lt;div\sstyle=&quot;padding-left:10px;&quot;&gt;&lt;b&gt;([^&lt;]*?)&lt;</name>
+				<street>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(?:\d*?,)?([^&lt;]*?)&lt;</street>
+				<city>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;([^,]*?),</city>
+				<zipcode>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(\d*?),</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+81">
+		<website name="yellowpage-jp.com" url="http://yellowpage-jp.com/search.php?mids%5B%5D=6&amp;query=%280$AREACODE%29$PART1-$PART2&amp;andor=AND&amp;submit=Search&amp;action=results" hidden="&lt;a\shref\=.modules/mxdirectory/singlelink.php\?([^'^\&quot;]+).&gt;" nexturl="http://yellowpage-jp.com/modules/mxdirectory/singlelink.php?$HIDDEN" prefix="">
+			<entry>
+				<name>&lt;td\sstyle=.color:#ff6633;text-align:center.&gt;[^&gt;]*&gt;([^&lt;]*?)&lt;</name>
+				<street>http://yellowpage-jp.com/modules/mxdirectory/viewrating.php(?:[^&gt;]*&gt;){7}([^,]*,[^,]*),</street>
+				<city>http://yellowpage-jp.com/modules/mxdirectory/viewrating.php(?:[^&gt;]*&gt;){7}(?:[^,]*,){2}([^&lt;]*)&lt;</city>
+				<zipcode>&lt;b&gt;ZIP[^&gt;]*&gt;\s?([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+84">
+		<website name="yp.com.vn" url="http://www.yp.com.vn/eYP_VWhitePage.asp" cookie="\[([^;]*);" nexturl="http://www.yp.com.vn/YP_EListSubPhone.asp" post="Phone=$NUMBER&amp;Province=$CODE&amp;submit=Search" hidden="(wrzlgrmpf)" prefix="">
+			<entry>
+				<name>&lt;td\scolspan=.3.\sbgcolor=.#FFFF99.&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>td\sclass=.gensmall.&gt;Address(?:[^&gt;]*&gt;){2}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+853">
+		<website name="yellowpages.com.mo" url="http://www.yellowpages.com.mo/en/searchresult.asp?telid=$NUMBER&amp;lang=e" prefix="">
+			<entry>
+				<name>class=.(?:nm00e|nm220e).&gt;([^&lt;]*)&lt;</name>
+				<street>(?:iaddrt|icon_address)\.gif[^&gt;]*&gt;([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+855">
+		<website name="yellowpages-cambodia.com" url="http://www.yellowpages-cambodia.com/search/?q=0$AREACODE+$PART1+$PART2" prefix="">
+			<entry>
+				<name>fn\sorg&quot;[^&gt;]*&gt;([^&lt;]*)&lt;</name>
+				<street>street-address&quot;&gt;([^&lt;]*)&lt;</street>
+				<city>region&quot;&gt;([^&lt;]*)&lt;</city>
+				<zipcode>postal-code&quot;&gt;([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+8621">
+		<website name="yellowpage.com.cn" url="http://en.yellowpage.com.cn:8080/search.php?&amp;telephone=$NUMBER&amp;search=&amp;go=START+SEARCH" nexturl="http://en.yellowpage.com.cn:8080/search.php?search=&amp;page=0&amp;telephone=$NUMBER&amp;detail=$HIDDEN" hidden="detail=([^&quot;]*)&quot;" prefix="">
+			<entry>
+				<name>text_headline_14&quot;&gt;([^&lt;]*)&lt;</name>
+				<street>/data/company/(?:[^&gt;]*&gt;){18}([^,]*(?:,[^,]*)?),\s?\d{6}\s?&lt;/td&gt;</street>
+				<city>(Shanghai)</city>
+				<zipcode>/data/company/(?:[^&gt;]*&gt;){18}[^,]*(?:,[^,]*)?,\s?(\d{6})\s?&lt;/td&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+90">
+		<website name="ttrehber.tr.gov" url="http://www.ttrehber.gov.tr/trk-wp/IDA2?REQ=20&amp;IDAERROR=&amp;QRY=bus&amp;CTRY=trk&amp;LANG=tu&amp;PAGE=complexSearch&amp;LIP=complexSearch&amp;ACTION=search&amp;STP=C&amp;ACD=$AREACODE&amp;TEL=$NUMBER&amp;sorgula=Ki%FEi+%2F+Kurum+Sorgula" prefix="0" areacode="3">
+			<entry>
+				<name>&lt;td class=&quot;level0&quot;&gt;([^&lt;]*)&lt;/td&gt;&lt;td align=&quot;left&quot;&gt;</name>
+				<street>&lt;td align=&quot;left&quot;&gt;([^,]*),[^&lt;]*&lt;/td&gt;</street>
+				<city>&lt;td align=&quot;left&quot;&gt;[^,]*,(?:[^,]*,\s*[0-9]*([^,]*,[^&lt;]*)|\s*[0-9]*([^,]*,[^&lt;]*)|([^&lt;]*))&lt;/td&gt;</city>
+				<zipcode>&lt;td align=&quot;left&quot;&gt;[^,]*, ([0-9]*)[^&lt;]*&lt;/td&gt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+9111">
+		<website name="phonebook.bol.net.in" url="http://phonebook.bol.net.in/indvtel1.jsp?TELEPHONE_NO=$NUMBER" prefix="">
+			<entry>
+				<name>TelephoneNo(?:[^&gt;]*?&gt;){7}([^&lt;]*?)&lt;</name>
+				<street>TelephoneNo(?:[^&gt;]*?&gt;){10}([^&lt;]*?)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+9133">
+		<website name="calcutta.bsnl.co.in" url="http://www.calcutta.bsnl.co.in/directory/telno.php?telno=$NUMBER&amp;search=Search" prefix="">
+			<entry>
+				<name>&gt;Address&lt;(?:[^&gt;]*?&gt;){11}([^&lt;]*)&lt;</name>
+				<street>&gt;Address&lt;(?:[^&gt;]*?&gt;){15}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+9144">
+		<website name="chennai.bsnl.co.in" url="http://chennai.bsnl.co.in/newdq/telno.asp" cookie="\[([^;]*);" nexturl="http://chennai.bsnl.co.in/newdq/telno.asp" post="telno=$NUMBER&amp;B1=SEARCH" prefix="">
+			<entry>
+				<name>&gt;Address&lt;(?:[^&gt;]*?&gt;){11}([^&lt;]*)&lt;</name>
+				<street>&gt;Address&lt;(?:[^&gt;]*?&gt;){15}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+92">
+		<website name="pakdatabase.com" url="http://www.pakdatabase.com/directory/dirrespwd.asp" post="selection=0&amp;city=$CODE&amp;searchtype=P&amp;enter=$NUMBER&amp;hidefied=1" prefix="">
+			<entry>
+				<name>Draw\sthe\smore\sinfo(?:[^&gt;]*&gt;){10}([^\.]*)\.</name>
+				<street>Draw\sthe\smore\sinfo(?:[^&gt;]*&gt;){10}(?:[^\.]*)\.([^\&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+961">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Lebanon" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+962">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Jordan" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+963">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Syria" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+964">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Iraq" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+965">
+		<website name="ekyp.com" url="http://www.ekyp.com/search-3.php?firmname=&amp;phone=$NUMBER&amp;category=ANY&amp;submit=Search" prefix="">
+			<entry>
+				<name>nt\.gif(?:[^&gt;]*&gt;){5}([^&lt;]*?)&lt;</name>
+				<street>()</street>
+				<city>Area(?:[^&gt;]*&gt;){6}([^&lt;]*?)&lt;</city>
+				<zipcode>ZIP\sCode(?:[^&gt;]*&gt;){6}([^&lt;]*?)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+966">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Saudi%20Arabia" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+967">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Yemen" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+968">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Oman" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+971">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=United+Arab+Emirates" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+972">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Palestine" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+		<website name="441il.com" url="http://441il.com/en/looktra.php?area=0$AREACODE&amp;phone=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;TR&gt;&lt;TD&gt;([^&lt;]*)&lt;</name>
+				<street>&lt;TR&gt;&lt;TD&gt;(?:[^&gt;]*&gt;){2}([^&lt;]*)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+973">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Bahrain" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+974">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Qatar" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+977">
+		<website name="ypofnepal.com" url="http://www.ypofnepal.com/search/?start=1&amp;q=$NUMBER" nexturl="http://www.ypofnepal.com$HIDDEN" prefix="" hidden="var\slst=[^']*'([^']*)'">
+			<entry>
+				<name>&lt;h2\sid=.name.&gt;([^&lt;]*)&lt;</name>
+				<street>street-address.&gt;([^&lt;]*)&lt;</street>
+				<city>locality&quot;&gt;([^&lt;]*)&lt;</city>
+				<zipcode>postal-code&quot;&gt;([^&lt;]*)&lt;</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+98">
+		<website name="ameinfo.com" url="http://www.ameinfo.com/cgi-bin/db/search.cgi?query=$NUMBER&amp;substring=0&amp;Country=Iran" prefix="">
+			<entry>
+				<name>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){4}([^&lt;]*)&lt;</street>
+				<city>style=&quot;font-size:10pt;&quot;&gt;&lt;b&gt;(?:[^&gt;]*&gt;){5}([^&lt;]*)&lt;</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+992">
+		<website name="yellow-pages.kz" url="http://www.yellow-pages.kz/tj/en/phone_search/0/1/$NUMBER" prefix="">
+			<entry>
+				<name>&lt;/noindex&gt;&lt;div\sstyle=&quot;padding-left:10px;&quot;&gt;&lt;b&gt;([^&lt;]*?)&lt;</name>
+				<street>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(?:\d*?,)?([^&lt;]*?)&lt;</street>
+				<city>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;([^,]*?),</city>
+				<zipcode>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(\d*?),</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+993">
+		<website name="yellow-pages.kz" url="http://www.yellow-pages.kz/tr/en/phone_search/0/1/$NUMBER" prefix="">
+			<entry>
+				<name>&lt;/noindex&gt;&lt;div\sstyle=&quot;padding-left:10px;&quot;&gt;&lt;b&gt;([^&lt;]*?)&lt;</name>
+				<street>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(?:\d*?,)?([^&lt;]*?)&lt;</street>
+				<city>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;([^,]*?),</city>
+				<zipcode>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(\d*?),</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+994">
+		<website name="yellow-pages.kz" url="http://www.yellow-pages.kz/az/en/phone_search/0/1/$NUMBER" prefix="">
+			<entry>
+				<name>&lt;/noindex&gt;&lt;div\sstyle=&quot;padding-left:10px;&quot;&gt;&lt;b&gt;([^&lt;]*?)&lt;</name>
+				<street>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(?:\d*?,)?([^&lt;]*?)&lt;</street>
+				<city>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;([^,]*?),</city>
+				<zipcode>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(\d*?),</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+995">
+		<website name="yellowpages.ge" url="http://www.yellowpages.ge/csearch.php?lan=2&amp;phone=$NUMBER" prefix="">
+			<entry>
+				<name>&lt;font\sface=&quot;&quot;\ssize=2&gt;&amp;nbsp;&lt;b&gt;([^&lt;]*)&lt;</name>
+				<street>i/r-e.gif(?:[^&gt;]*&gt;){8}([^&lt;]*?)&lt;</street>
+				<city>()</city>
+				<zipcode>()</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+996">
+		<website name="yellow-pages.kz" url="http://www.yellow-pages.kz/kg/en/phone_search/0/1/$NUMBER" prefix="">
+			<entry>
+				<name>&lt;/noindex&gt;&lt;div\sstyle=&quot;padding-left:10px;&quot;&gt;&lt;b&gt;([^&lt;]*?)&lt;</name>
+				<street>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(?:\d*?,)?([^&lt;]*?)&lt;</street>
+				<city>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;([^,]*?),</city>
+				<zipcode>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(\d*?),</zipcode>
+			</entry>
+		</website>
+	</country>
+	<country code="+998">
+		<website name="yellow-pages.kz" url="http://www.yellow-pages.kz/uz/en/phone_search/0/1/$NUMBER" prefix="">
+			<entry>
+				<name>&lt;/noindex&gt;&lt;div\sstyle=&quot;padding-left:10px;&quot;&gt;&lt;b&gt;([^&lt;]*?)&lt;</name>
+				<street>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(?:\d*?,)?([^&lt;]*?)&lt;</street>
+				<city>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;([^,]*?),</city>
+				<zipcode>\.\.\.&lt;/a>&lt;br&gt;&lt;br&gt;[^,]*?,\s(\d*?),</zipcode>
+			</entry>
+		</website>
+	</country>
+</reverselookup>
+	
+
+	
Index: /ipk/source/swapinfos_permanentclock_1_0/var/swap/extensions/PermanentClock/maintainer.info
===================================================================
--- /ipk/source/swapinfos_permanentclock_1_0/var/swap/extensions/PermanentClock/maintainer.info	(revision 5870)
+++ /ipk/source/swapinfos_permanentclock_1_0/var/swap/extensions/PermanentClock/maintainer.info	(revision 5870)
@@ -0,0 +1,2 @@
+nabil1978@web.de
+PermanentClock
Index: /ipk/source/swapinfos_permanentclock_1_0/var/swap/extensions/PermanentClock/plugin.py
===================================================================
--- /ipk/source/swapinfos_permanentclock_1_0/var/swap/extensions/PermanentClock/plugin.py	(revision 5870)
+++ /ipk/source/swapinfos_permanentclock_1_0/var/swap/extensions/PermanentClock/plugin.py	(revision 5870)
@@ -0,0 +1,215 @@
+##
+## Permanent Clock
+## by AliAbdul
+##
+from Components.ActionMap import ActionMap
+from Components.config import config, ConfigInteger, ConfigSubsection, ConfigYesNo
+from Components.Language import language
+from Components.MenuList import MenuList
+from enigma import ePoint, eTimer, getDesktop
+from os import environ
+from Plugins.Plugin import PluginDescriptor
+from Screens.Screen import Screen
+from Tools.Directories import resolveFilename, SCOPE_LANGUAGE
+import gettext
+
+##############################################################################
+
+SKIN = """
+	<screen position="0,0" size="90,24" zPosition="10" title="Permanent Clock" flags="wfNoBorder">
+		<widget source="global.CurrentTime" render="Label" position="0,0" size="90,24" font="Regular;24" valign="center" halign="center" transparent="1">
+			<convert type="ClockToText">Default</convert>
+		</widget>
+	</screen>"""
+
+##############################################################################
+
+config.plugins.PermanentClock = ConfigSubsection()
+config.plugins.PermanentClock.enabled = ConfigYesNo(default=True)
+config.plugins.PermanentClock.position_x = ConfigInteger(default=590)
+config.plugins.PermanentClock.position_y = ConfigInteger(default=35)
+
+##############################################################################
+
+lang = language.getLanguage()
+environ["LANGUAGE"] = lang[:2]
+gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
+gettext.textdomain("enigma2")
+gettext.bindtextdomain("PermanentClock", resolveFilename(SCOPE_LANGUAGE))
+
+def _(txt):
+	t = gettext.dgettext("PermanentClock", txt)
+	if t == txt:
+		t = gettext.gettext(txt)
+	return t
+
+##############################################################################
+
+class TitleScreen(Screen):
+	def __init__(self, session, parent=None):
+		Screen.__init__(self, session, parent)
+		self.onLayoutFinish.append(self.setScreenTitle)
+
+	def setScreenTitle(self):
+		self.setTitle(_("Permanent Clock"))
+
+##############################################################################
+
+class PermanentClockScreen(Screen):
+	def __init__(self, session):
+		Screen.__init__(self, session)
+		self.skin = SKIN
+		self.onShow.append(self.movePosition)
+
+	def movePosition(self):
+		if self.instance:
+			self.instance.move(ePoint(config.plugins.PermanentClock.position_x.value, config.plugins.PermanentClock.position_y.value))
+
+##############################################################################
+
+class PermanentClock():
+	def __init__(self):
+		self.dialog = None
+
+	def gotSession(self, session):
+		self.dialog = session.instantiateDialog(PermanentClockScreen)
+		self.showHide()
+
+	def changeVisibility(self):
+		if config.plugins.PermanentClock.enabled.value:
+			config.plugins.PermanentClock.enabled.value = False
+		else:
+			config.plugins.PermanentClock.enabled.value = True
+		config.plugins.PermanentClock.enabled.save()
+		self.showHide()
+
+	def showHide(self):
+		if config.plugins.PermanentClock.enabled.value:
+			self.dialog.show()
+		else:
+			self.dialog.hide()
+
+pClock = PermanentClock()
+
+##############################################################################
+
+class PermanentClockPositioner(Screen):
+	def __init__(self, session):
+		Screen.__init__(self, session)
+		self.skin = SKIN
+		
+		self["actions"] = ActionMap(["WizardActions"],
+		{
+			"left": self.left,
+			"up": self.up,
+			"right": self.right,
+			"down": self.down,
+			"ok": self.ok,
+			"back": self.exit
+		}, -1)
+		
+		desktop = getDesktop(0)
+		self.desktopWidth = desktop.size().width()
+		self.desktopHeight = desktop.size().height()
+		
+		self.moveTimer = eTimer()
+		self.moveTimer.timeout.get().append(self.movePosition)
+		self.moveTimer.start(50, 1)
+
+	def movePosition(self):
+		self.instance.move(ePoint(config.plugins.PermanentClock.position_x.value, config.plugins.PermanentClock.position_y.value))
+		self.moveTimer.start(50, 1)
+
+	def left(self):
+		value = config.plugins.PermanentClock.position_x.value
+		value -= 1
+		if value < 0:
+			value = 0
+		config.plugins.PermanentClock.position_x.value = value
+
+	def up(self):
+		value = config.plugins.PermanentClock.position_y.value
+		value -= 1
+		if value < 0:
+			value = 0
+		config.plugins.PermanentClock.position_y.value = value
+
+	def right(self):
+		value = config.plugins.PermanentClock.position_x.value
+		value += 1
+		if value > self.desktopWidth:
+			value = self.desktopWidth
+		config.plugins.PermanentClock.position_x.value = value
+
+	def down(self):
+		value = config.plugins.PermanentClock.position_y.value
+		value += 1
+		if value > self.desktopHeight:
+			value = self.desktopHeight
+		config.plugins.PermanentClock.position_y.value = value
+
+	def ok(self):
+		config.plugins.PermanentClock.position_x.save()
+		config.plugins.PermanentClock.position_y.save()
+		self.close()
+
+	def exit(self):
+		config.plugins.PermanentClock.position_x.cancel()
+		config.plugins.PermanentClock.position_y.cancel()
+		self.close()
+
+##############################################################################
+
+class PermanentClockMenu(TitleScreen):
+	skin = """
+		<screen position="150,235" size="420,105" title="Permanent Clock">
+			<widget name="list" position="10,10" size="400,85" />
+		</screen>"""
+
+	def __init__(self, session):
+		TitleScreen.__init__(self, session)
+		self.session = session
+		self["list"] = MenuList([])
+		self["actions"] = ActionMap(["OkCancelActions"], {"ok": self.okClicked, "cancel": self.close}, -1)
+		self.onLayoutFinish.append(self.showMenu)
+
+	def showMenu(self):
+		list = []
+		if config.plugins.PermanentClock.enabled.value:
+			list.append(_("Deactivate permanent clock"))
+		else:
+			list.append(_("Activate permanent clock"))
+		list.append(_("Change permanent clock position"))
+		self["list"].setList(list)
+
+	def okClicked(self):
+		sel = self["list"].getCurrent()
+		if sel == _("Deactivate permanent clock") or sel == _("Activate permanent clock"):
+			if pClock.dialog is None:
+				pClock.gotSession(self.session)
+			pClock.changeVisibility()
+			self.showMenu()
+		else:
+			if pClock.dialog is None:
+				pClock.gotSession(self.session)
+			pClock.dialog.hide()
+			self.session.openWithCallback(self.positionerCallback, PermanentClockPositioner)
+
+	def positionerCallback(self, callback=None):
+		pClock.showHide()
+
+##############################################################################
+
+def sessionstart(reason, **kwargs):
+	if reason == 0:
+		pClock.gotSession(kwargs["session"])
+
+def main(session, **kwargs):
+	session.open(PermanentClockMenu)
+
+##############################################################################
+
+def Plugins(**kwargs):
+	return [
+		PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART], fnc=sessionstart),
+		PluginDescriptor(name=_("Permanent Clock"), description=_("Shows the clock permanent on the screen"), where=PluginDescriptor.WHERE_PLUGINMENU, fnc=main)]
