summaryrefslogtreecommitdiff
path: root/plugins/streamdev/streamdev-cvs/server
diff options
context:
space:
mode:
authorkwacker <vdr@w-i-r.com>2010-04-11 13:46:11 +0200
committerkwacker <vdr@w-i-r.com>2010-04-11 13:46:11 +0200
commit9b144d30e0ea8ce900c37b96ba2cbdda14b0ae88 (patch)
tree3a52de029f950dcd9f9856a53fd67abef8519e68 /plugins/streamdev/streamdev-cvs/server
parent9cd931834ecadbf5efefdf484abb966e9248ebbb (diff)
downloadx-vdr-9b144d30e0ea8ce900c37b96ba2cbdda14b0ae88.tar.gz
x-vdr-9b144d30e0ea8ce900c37b96ba2cbdda14b0ae88.tar.bz2
Burn 0.2.0-beta3 und Streamdev mit Paches aktualisiert
Diffstat (limited to 'plugins/streamdev/streamdev-cvs/server')
-rw-r--r--plugins/streamdev/streamdev-cvs/server/CVS/Entries34
-rw-r--r--plugins/streamdev/streamdev-cvs/server/CVS/Entries.Log1
-rw-r--r--plugins/streamdev/streamdev-cvs/server/CVS/Repository1
-rw-r--r--plugins/streamdev/streamdev-cvs/server/CVS/Root1
-rw-r--r--plugins/streamdev/streamdev-cvs/server/component.c49
-rw-r--r--plugins/streamdev/streamdev-cvs/server/component.h51
-rw-r--r--plugins/streamdev/streamdev-cvs/server/componentHTTP.c18
-rw-r--r--plugins/streamdev/streamdev-cvs/server/componentHTTP.h18
-rw-r--r--plugins/streamdev/streamdev-cvs/server/componentIGMP.c447
-rw-r--r--plugins/streamdev/streamdev-cvs/server/componentIGMP.h62
-rw-r--r--plugins/streamdev/streamdev-cvs/server/componentVTP.c18
-rw-r--r--plugins/streamdev/streamdev-cvs/server/componentVTP.h18
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connection.c255
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connection.h99
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connectionHTTP.c296
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connectionHTTP.h70
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connectionIGMP.c64
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connectionIGMP.h45
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connectionVTP.c1768
-rw-r--r--plugins/streamdev/streamdev-cvs/server/connectionVTP.h93
-rw-r--r--plugins/streamdev/streamdev-cvs/server/http/CVS/Entries1
-rw-r--r--plugins/streamdev/streamdev-cvs/server/http/CVS/Repository1
-rw-r--r--plugins/streamdev/streamdev-cvs/server/http/CVS/Root1
-rw-r--r--plugins/streamdev/streamdev-cvs/server/livefilter.c39
-rw-r--r--plugins/streamdev/streamdev-cvs/server/livefilter.h32
-rw-r--r--plugins/streamdev/streamdev-cvs/server/livestreamer.c689
-rw-r--r--plugins/streamdev/streamdev-cvs/server/livestreamer.h82
-rw-r--r--plugins/streamdev/streamdev-cvs/server/menuHTTP.c429
-rw-r--r--plugins/streamdev/streamdev-cvs/server/menuHTTP.h143
-rw-r--r--plugins/streamdev/streamdev-cvs/server/recplayer.c288
-rw-r--r--plugins/streamdev/streamdev-cvs/server/recplayer.h63
-rw-r--r--plugins/streamdev/streamdev-cvs/server/server.c173
-rw-r--r--plugins/streamdev/streamdev-cvs/server/server.h49
-rw-r--r--plugins/streamdev/streamdev-cvs/server/setup.c141
-rw-r--r--plugins/streamdev/streamdev-cvs/server/setup.h48
-rw-r--r--plugins/streamdev/streamdev-cvs/server/streamer.c162
-rw-r--r--plugins/streamdev/streamdev-cvs/server/streamer.h102
-rw-r--r--plugins/streamdev/streamdev-cvs/server/suspend.c57
-rw-r--r--plugins/streamdev/streamdev-cvs/server/suspend.dat1206
-rw-r--r--plugins/streamdev/streamdev-cvs/server/suspend.h36
40 files changed, 7150 insertions, 0 deletions
diff --git a/plugins/streamdev/streamdev-cvs/server/CVS/Entries b/plugins/streamdev/streamdev-cvs/server/CVS/Entries
new file mode 100644
index 0000000..1a9cebe
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/CVS/Entries
@@ -0,0 +1,34 @@
+/component.c/1.4/Fri Feb 13 10:39:22 2009//
+/component.h/1.3/Fri Feb 13 10:39:22 2009//
+/componentHTTP.c/1.2/Mon May 9 20:22:29 2005//
+/componentHTTP.h/1.2/Mon May 9 20:22:29 2005//
+/componentIGMP.c/1.2/Fri Jul 3 21:44:19 2009//
+/componentIGMP.h/1.1/Fri Feb 13 10:39:22 2009//
+/componentVTP.c/1.2/Mon May 9 20:22:29 2005//
+/componentVTP.h/1.2/Mon May 9 20:22:29 2005//
+/connection.c/1.13/Fri Sep 18 10:43:26 2009//
+/connection.h/1.8/Fri Sep 18 10:43:26 2009//
+/connectionHTTP.c/1.17/Fri Jun 19 06:32:45 2009//
+/connectionHTTP.h/1.6/Tue Oct 14 11:05:48 2008//
+/connectionIGMP.c/1.1/Fri Feb 13 10:39:22 2009//
+/connectionIGMP.h/1.1/Fri Feb 13 10:39:22 2009//
+/connectionVTP.c/1.27/Fri Jan 29 12:03:02 2010//
+/connectionVTP.h/1.11/Wed Jul 1 10:46:16 2009//
+/livefilter.c/1.7/Fri Feb 13 13:02:40 2009//
+/livefilter.h/1.5/Mon Apr 7 14:27:31 2008//
+/livestreamer.c/1.30/Sat Feb 20 23:02:10 2010//
+/livestreamer.h/1.20/Mon Jul 6 06:23:29 2009//
+/menuHTTP.c/1.6/Sat Feb 20 22:18:14 2010//
+/menuHTTP.h/1.3/Tue Sep 15 10:39:18 2009//
+/recplayer.c/1.1/Wed Jul 1 11:00:49 2009//
+/recplayer.h/1.1/Wed Jul 1 11:00:49 2009//
+/server.c/1.10/Fri Feb 13 10:39:22 2009//
+/server.h/1.6/Wed Oct 22 11:59:32 2008//
+/setup.c/1.9/Tue Oct 13 06:38:47 2009//
+/setup.h/1.3/Fri Sep 18 10:43:26 2009//
+/streamer.c/1.19/Fri Jun 19 06:32:45 2009//
+/streamer.h/1.11/Fri Jun 19 06:32:45 2009//
+/suspend.c/1.3/Wed Oct 22 11:59:32 2008//
+/suspend.dat/1.1.1.1/Thu Dec 30 22:44:26 2004//
+/suspend.h/1.2/Wed Oct 22 11:59:32 2008//
+D
diff --git a/plugins/streamdev/streamdev-cvs/server/CVS/Entries.Log b/plugins/streamdev/streamdev-cvs/server/CVS/Entries.Log
new file mode 100644
index 0000000..5674fc6
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/CVS/Entries.Log
@@ -0,0 +1 @@
+A D/http////
diff --git a/plugins/streamdev/streamdev-cvs/server/CVS/Repository b/plugins/streamdev/streamdev-cvs/server/CVS/Repository
new file mode 100644
index 0000000..785255b
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/CVS/Repository
@@ -0,0 +1 @@
+streamdev/server
diff --git a/plugins/streamdev/streamdev-cvs/server/CVS/Root b/plugins/streamdev/streamdev-cvs/server/CVS/Root
new file mode 100644
index 0000000..2c7f6ce
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/CVS/Root
@@ -0,0 +1 @@
+:pserver:anoncvs@vdr-developer.org:/var/cvsroot
diff --git a/plugins/streamdev/streamdev-cvs/server/component.c b/plugins/streamdev/streamdev-cvs/server/component.c
new file mode 100644
index 0000000..70d861a
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/component.c
@@ -0,0 +1,49 @@
+/*
+ * $Id: component.c,v 1.4 2009/02/13 10:39:22 schmirl Exp $
+ */
+
+#include "server/component.h"
+#include "server/connection.h"
+
+cServerComponent::cServerComponent(const char *Protocol, const char *ListenIp,
+ uint ListenPort, int Type, int IpProto):
+ m_Protocol(Protocol),
+ m_Listen(Type, IpProto),
+ m_ListenIp(ListenIp),
+ m_ListenPort(ListenPort)
+{
+}
+
+cServerComponent::~cServerComponent()
+{
+}
+
+bool cServerComponent::Initialize(void)
+{
+ if (!m_Listen.Listen(m_ListenIp, m_ListenPort, 5)) {
+ esyslog("Streamdev: Couldn't listen (%s) %s:%d: %m",
+ m_Protocol, m_ListenIp, m_ListenPort);
+ return false;
+ }
+ isyslog("Streamdev: Listening (%s) on port %d", m_Protocol, m_ListenPort);
+ return true;
+}
+
+void cServerComponent::Destruct(void)
+{
+ m_Listen.Close();
+}
+
+cServerConnection *cServerComponent::Accept(void)
+{
+ cServerConnection *client = NewClient();
+ if (client->Accept(m_Listen)) {
+ isyslog("Streamdev: Accepted new client (%s) %s:%d", m_Protocol,
+ client->RemoteIp().c_str(), client->RemotePort());
+ return client;
+ } else {
+ esyslog("Streamdev: Couldn't accept (%s): %m", m_Protocol);
+ delete client;
+ }
+ return NULL;
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/component.h b/plugins/streamdev/streamdev-cvs/server/component.h
new file mode 100644
index 0000000..7efd4ba
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/component.h
@@ -0,0 +1,51 @@
+/*
+ * $Id: component.h,v 1.3 2009/02/13 10:39:22 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SERVERS_COMPONENT_H
+#define VDR_STREAMDEV_SERVERS_COMPONENT_H
+
+#include "tools/socket.h"
+#include "tools/select.h"
+
+#include <vdr/tools.h>
+
+class cServerConnection;
+
+/* Basic TCP listen server, all functions virtual if a derivation wants to do
+ things different */
+
+class cServerComponent: public cListObject {
+private:
+ const char *m_Protocol;
+ cTBSocket m_Listen;
+ const char *m_ListenIp;
+ uint m_ListenPort;
+
+protected:
+ /* Returns a new connection object for Accept() */
+ virtual cServerConnection *NewClient(void) = 0;
+
+public:
+ cServerComponent(const char *Protocol, const char *ListenIp, uint ListenPort, int Type = SOCK_STREAM, int IpProto = 0);
+ virtual ~cServerComponent();
+
+ /* Starts listening on the specified Port, override if you want to do things
+ different */
+ virtual bool Initialize(void);
+
+ /* Stops listening, override if you want to do things different */
+ virtual void Destruct(void);
+
+ /* Get the listening socket's file number */
+ virtual int Socket(void) const { return (int)m_Listen; }
+
+ /* Adds the listening socket to the Select object */
+ virtual void Add(cTBSelect &Select) const { Select.Add(m_Listen); }
+
+ /* Accepts the connection on a NewClient() object and calls the
+ Welcome() on it, override if you want to do things different */
+ virtual cServerConnection *Accept(void);
+};
+
+#endif // VDR_STREAMDEV_SERVERS_COMPONENT_H
diff --git a/plugins/streamdev/streamdev-cvs/server/componentHTTP.c b/plugins/streamdev/streamdev-cvs/server/componentHTTP.c
new file mode 100644
index 0000000..70e95e9
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/componentHTTP.c
@@ -0,0 +1,18 @@
+/*
+ * $Id: componentHTTP.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
+ */
+
+#include "server/componentHTTP.h"
+#include "server/connectionHTTP.h"
+#include "server/setup.h"
+
+cComponentHTTP::cComponentHTTP(void):
+ cServerComponent("HTTP", StreamdevServerSetup.HTTPBindIP,
+ StreamdevServerSetup.HTTPServerPort)
+{
+}
+
+cServerConnection *cComponentHTTP::NewClient(void)
+{
+ return new cConnectionHTTP;
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/componentHTTP.h b/plugins/streamdev/streamdev-cvs/server/componentHTTP.h
new file mode 100644
index 0000000..29dc087
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/componentHTTP.h
@@ -0,0 +1,18 @@
+/*
+ * $Id: componentHTTP.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
+ */
+
+#ifndef VDR_STREAMDEV_HTTPSERVER_H
+#define VDR_STREAMDEV_HTTPSERVER_H
+
+#include "server/component.h"
+
+class cComponentHTTP: public cServerComponent {
+protected:
+ virtual cServerConnection *NewClient(void);
+
+public:
+ cComponentHTTP(void);
+};
+
+#endif // VDR_STREAMDEV_HTTPSERVER_H
diff --git a/plugins/streamdev/streamdev-cvs/server/componentIGMP.c b/plugins/streamdev/streamdev-cvs/server/componentIGMP.c
new file mode 100644
index 0000000..d9f8811
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/componentIGMP.c
@@ -0,0 +1,447 @@
+/*
+ * $Id: componentIGMP.c,v 1.2 2009/07/03 21:44:19 schmirl Exp $
+ */
+#include <netinet/ip.h>
+#include <netinet/igmp.h>
+
+#include "server/componentIGMP.h"
+#include "server/connectionIGMP.h"
+#include "server/setup.h"
+
+#ifndef IGMP_ALL_HOSTS
+#define IGMP_ALL_HOSTS htonl(0xE0000001L)
+#endif
+#ifndef IGMP_ALL_ROUTER
+#define IGMP_ALL_ROUTER htonl(0xE0000002L)
+#endif
+
+// IGMP parameters according to RFC2236. All time values in seconds.
+#define IGMP_ROBUSTNESS 2
+#define IGMP_QUERY_INTERVAL 125
+#define IGMP_QUERY_RESPONSE_INTERVAL 10
+#define IGMP_GROUP_MEMBERSHIP_INTERVAL (2 * IGMP_QUERY_INTERVAL + IGMP_QUERY_RESPONSE_INTERVAL)
+#define IGMP_OTHER_QUERIER_PRESENT_INTERVAL (2 * IGMP_QUERY_INTERVAL + IGMP_QUERY_RESPONSE_INTERVAL / 2)
+#define IGMP_STARTUP_QUERY_INTERVAL (IGMP_QUERY_INTERVAL / 4)
+#define IGMP_STARTUP_QUERY_COUNT IGMP_ROBUSTNESS
+// This value is 1/10 sec. RFC default is 10. Reduced to minimum to free unused channels ASAP
+#define IGMP_LAST_MEMBER_QUERY_INTERVAL_TS 1
+#define IGMP_LAST_MEMBER_QUERY_COUNT IGMP_ROBUSTNESS
+
+// operations on struct timeval
+#define TV_CMP(a, cmp, b) (a.tv_sec == b.tv_sec ? a.tv_usec cmp b.tv_usec : a.tv_sec cmp b.tv_sec)
+#define TV_SET(tv) (tv.tv_sec || tv.tv_usec)
+#define TV_CLR(tv) memset(&tv, 0, sizeof(tv))
+#define TV_CPY(dst, src) memcpy(&dst, &src, sizeof(dst))
+#define TV_ADD(dst, ts) dst.tv_sec += ts / 10; dst.tv_usec += (ts % 10) * 100000; if (dst.tv_usec >= 1000000) { dst.tv_usec -= 1000000; dst.tv_sec++; }
+
+class cMulticastGroup: public cListObject
+{
+public:
+ cConnectionIGMP *connection;
+ in_addr_t group;
+ in_addr_t reporter;
+ struct timeval timeout;
+ struct timeval v1timer;
+ struct timeval retransmit;
+
+ cMulticastGroup(in_addr_t Group);
+};
+
+cMulticastGroup::cMulticastGroup(in_addr_t Group) :
+ connection(NULL),
+ group(Group),
+ reporter(0)
+{
+ TV_CLR(timeout);
+ TV_CLR(v1timer);
+ TV_CLR(retransmit);
+}
+
+void logIGMP(uint8_t type, struct in_addr Src, struct in_addr Dst, struct in_addr Grp)
+{
+ const char* msg;
+ switch (type) {
+ case IGMP_MEMBERSHIP_QUERY: msg = "membership query"; break;
+ case IGMP_V1_MEMBERSHIP_REPORT: msg = "V1 membership report"; break;
+ case IGMP_V2_MEMBERSHIP_REPORT: msg = "V2 membership report"; break;
+ case IGMP_V2_LEAVE_GROUP: msg = "leave group"; break;
+ default: msg = "unknown"; break;
+ }
+ char* s = strdup(inet_ntoa(Src));
+ char* d = strdup(inet_ntoa(Dst));
+ dsyslog("streamdev-server IGMP: Received %s from %s (dst %s) for %s", msg, s, d, inet_ntoa(Grp));
+ free(s);
+ free(d);
+}
+
+/* Taken from http://tools.ietf.org/html/rfc1071 */
+uint16_t inetChecksum(uint16_t *addr, int count)
+{
+ uint32_t sum = 0;
+ while (count > 1) {
+ sum += *addr++;
+ count -= 2;
+ }
+
+ if( count > 0 )
+ sum += * (uint8_t *) addr;
+
+ while (sum>>16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return ~sum;
+}
+
+cComponentIGMP::cComponentIGMP(void):
+ cServerComponent("IGMP", "0.0.0.0", 0, SOCK_RAW, IPPROTO_IGMP),
+ cThread("IGMP timeout handler"),
+ m_BindIp(inet_addr(StreamdevServerSetup.IGMPBindIP)),
+ m_MaxChannelNumber(0),
+ m_StartupQueryCount(IGMP_STARTUP_QUERY_COUNT),
+ m_Querier(true)
+{
+}
+
+cComponentIGMP::~cComponentIGMP(void)
+{
+}
+
+cMulticastGroup* cComponentIGMP::FindGroup(in_addr_t Group) const
+{
+ cMulticastGroup *group = m_Groups.First();
+ while (group && group->group != Group)
+ group = m_Groups.Next(group);
+ return group;
+}
+
+bool cComponentIGMP::Initialize(void)
+{
+ if (cServerComponent::Initialize() && IGMPMembership(IGMP_ALL_ROUTER))
+ {
+ for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+ {
+ if (channel->GroupSep())
+ continue;
+ int num = channel->Number();
+ if (!IGMPMembership(htonl(MULTICAST_PRIV_MIN + num)))
+ break;
+ m_MaxChannelNumber = num;
+ }
+ if (m_MaxChannelNumber == 0)
+ {
+ IGMPMembership(IGMP_ALL_ROUTER, false);
+ esyslog("streamdev-server IGMP: no multicast group joined");
+ }
+ else
+ {
+ Start();
+ }
+ }
+ return m_MaxChannelNumber > 0;
+}
+
+void cComponentIGMP::Destruct(void)
+{
+ if (m_MaxChannelNumber > 0)
+ {
+ Cancel(3);
+ for (cChannel *channel = Channels.First(); channel; channel = Channels.Next(channel))
+ {
+ if (channel->GroupSep())
+ continue;
+ int num = channel->Number();
+ if (num > m_MaxChannelNumber)
+ break;
+ IGMPMembership(htonl(MULTICAST_PRIV_MIN + num), false);
+ }
+ IGMPMembership(IGMP_ALL_ROUTER, false);
+ }
+ m_MaxChannelNumber = 0;
+ cServerComponent::Destruct();
+}
+
+cServerConnection *cComponentIGMP::NewClient(void)
+{
+ return new cConnectionIGMP("IGMP", StreamdevServerSetup.IGMPClientPort, (eStreamType) StreamdevServerSetup.IGMPStreamType);
+}
+
+cServerConnection* cComponentIGMP::Accept(void)
+{
+ ssize_t recv_len;
+ int ip_hdrlen, ip_datalen;
+ struct ip *ip;
+ struct igmp *igmp;
+
+ while ((recv_len = ::recvfrom(Socket(), m_ReadBuffer, sizeof(m_ReadBuffer), 0, NULL, NULL)) < 0 && errno == EINTR)
+ errno = 0;
+
+ if (recv_len < 0) {
+ esyslog("streamdev-server IGMP: read failed: %m");
+ return NULL;
+ }
+ else if (recv_len < (ssize_t) sizeof(struct ip)) {
+ esyslog("streamdev-server IGMP: IP packet too short");
+ return NULL;
+ }
+
+ ip = (struct ip*) m_ReadBuffer;
+
+ // filter out my own packets
+ if (ip->ip_src.s_addr == m_BindIp)
+ return NULL;
+
+ ip_hdrlen = ip->ip_hl << 2;
+#ifdef __FreeBSD__
+ ip_datalen = ip->ip_len;
+#else
+ ip_datalen = ntohs(ip->ip_len) - ip_hdrlen;
+#endif
+ if (ip->ip_p != IPPROTO_IGMP) {
+ esyslog("streamdev-server IGMP: Unexpected protocol %hhu", ip->ip_p);
+ return NULL;
+ }
+ if (recv_len < ip_hdrlen + IGMP_MINLEN) {
+ esyslog("streamdev-server IGMP: packet too short");
+ return NULL;
+ }
+ igmp = (struct igmp*) (m_ReadBuffer + ip_hdrlen);
+ uint16_t chksum = igmp->igmp_cksum;
+ igmp->igmp_cksum = 0;
+ if (chksum != inetChecksum((uint16_t *)igmp, ip_datalen))
+ {
+ esyslog("INVALID CHECKSUM %d %d %d %lu 0x%x 0x%x", (int) ntohs(ip->ip_len), ip_hdrlen, ip_datalen, (unsigned long int) recv_len, chksum, inetChecksum((uint16_t *)igmp, ip_datalen));
+ return NULL;
+ }
+ logIGMP(igmp->igmp_type, ip->ip_src, ip->ip_dst, igmp->igmp_group);
+ return ProcessMessage(igmp, igmp->igmp_group.s_addr, ip->ip_src.s_addr);
+}
+
+cServerConnection* cComponentIGMP::ProcessMessage(struct igmp *Igmp, in_addr_t Group, in_addr_t Sender)
+{
+ cServerConnection* conn = NULL;
+ cMulticastGroup* group;
+ LOCK_THREAD;
+ switch (Igmp->igmp_type) {
+ case IGMP_MEMBERSHIP_QUERY:
+ if (ntohl(Sender) < ntohl(m_BindIp))
+ IGMPStartOtherQuerierPresentTimer();
+ break;
+ case IGMP_V1_MEMBERSHIP_REPORT:
+ case IGMP_V2_MEMBERSHIP_REPORT:
+ group = FindGroup(Group);
+ if (!group) {
+ group = new cMulticastGroup(Group);
+ m_Groups.Add(group);
+ }
+ if (!group->connection) {
+ IGMPStartMulticast(group);
+ conn = group->connection;
+ }
+ IGMPStartTimer(group, Sender);
+ if (Igmp->igmp_type == IGMP_V1_MEMBERSHIP_REPORT)
+ IGMPStartV1HostTimer(group);
+ break;
+ case IGMP_V2_LEAVE_GROUP:
+ group = FindGroup(Group);
+ if (group && !TV_SET(group->v1timer)) {
+ if (group->reporter == Sender) {
+ IGMPStartTimerAfterLeave(group, m_Querier ? IGMP_LAST_MEMBER_QUERY_INTERVAL_TS : Igmp->igmp_code);
+ if (m_Querier)
+ IGMPSendGroupQuery(group);
+ IGMPStartRetransmitTimer(group);
+ }
+ m_CondWait.Signal();
+ }
+ break;
+ default:
+ break;
+ }
+ return conn;
+}
+
+void cComponentIGMP::Action()
+{
+ while (Running()) {
+ struct timeval now;
+ struct timeval next;
+
+ gettimeofday(&now, NULL);
+ TV_CPY(next, now);
+ next.tv_sec += IGMP_QUERY_INTERVAL;
+
+ cMulticastGroup *del = NULL;
+ {
+ LOCK_THREAD;
+ if (TV_CMP(m_GeneralQueryTimer, <, now)) {
+ dsyslog("General Query");
+ IGMPSendGeneralQuery();
+ IGMPStartGeneralQueryTimer();
+ }
+ if (TV_CMP(next, >, m_GeneralQueryTimer))
+ TV_CPY(next, m_GeneralQueryTimer);
+
+ for (cMulticastGroup *group = m_Groups.First(); group; group = m_Groups.Next(group)) {
+ if (TV_CMP(group->timeout, <, now)) {
+ IGMPStopMulticast(group);
+ IGMPClearRetransmitTimer(group);
+ if (del)
+ m_Groups.Del(del);
+ del = group;
+ }
+ else if (m_Querier && TV_SET(group->retransmit) && TV_CMP(group->retransmit, <, now)) {
+ IGMPSendGroupQuery(group);
+ IGMPStartRetransmitTimer(group);
+ if (TV_CMP(next, >, group->retransmit))
+ TV_CPY(next, group->retransmit);
+ }
+ else if (TV_SET(group->v1timer) && TV_CMP(group->v1timer, <, now)) {
+ TV_CLR(group->v1timer);
+ }
+ else {
+ if (TV_CMP(next, >, group->timeout))
+ TV_CPY(next, group->timeout);
+ if (TV_SET(group->retransmit) && TV_CMP(next, >, group->retransmit))
+ TV_CPY(next, group->retransmit);
+ if (TV_SET(group->v1timer) && TV_CMP(next, >, group->v1timer))
+ TV_CPY(next, group->v1timer);
+ }
+ }
+ if (del)
+ m_Groups.Del(del);
+ }
+
+ int sleep = (next.tv_sec - now.tv_sec) * 1000;
+ sleep += (next.tv_usec - now.tv_usec) / 1000;
+ if (next.tv_usec < now.tv_usec)
+ sleep += 1000;
+ dsyslog("Sleeping %d ms", sleep);
+ m_CondWait.Wait(sleep);
+ }
+}
+
+bool cComponentIGMP::IGMPMembership(in_addr_t Group, bool Add)
+{
+ struct ip_mreqn mreq;
+ mreq.imr_multiaddr.s_addr = Group;
+ mreq.imr_address.s_addr = INADDR_ANY;
+ mreq.imr_ifindex = 0;
+ if (setsockopt(Socket(), IPPROTO_IP, Add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
+ {
+ esyslog("streamdev-server IGMP: unable to %s %s: %m", Add ? "join" : "leave", inet_ntoa(mreq.imr_multiaddr));
+ if (errno == ENOBUFS)
+ esyslog("consider increasing sys.net.ipv4.igmp_max_memberships");
+ return false;
+ }
+ return true;
+}
+
+void cComponentIGMP::IGMPSendQuery(in_addr_t Group, int Timeout)
+{
+ struct sockaddr_in dst;
+ struct igmp query;
+
+ dst.sin_family = AF_INET;
+ dst.sin_port = IPPROTO_IGMP;
+ dst.sin_addr.s_addr = Group;
+ query.igmp_type = IGMP_MEMBERSHIP_QUERY;
+ query.igmp_code = Timeout * 10;
+ query.igmp_cksum = 0;
+ query.igmp_group.s_addr = (Group == IGMP_ALL_HOSTS) ? 0 : Group;
+ query.igmp_cksum = inetChecksum((uint16_t *) &query, sizeof(query));
+
+ for (int i = 0; i < 5 && ::sendto(Socket(), &query, sizeof(query), 0, (sockaddr*)&dst, sizeof(dst)) == -1; i++) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ esyslog("streamdev-server IGMP: unable to query group %s: %m", inet_ntoa(dst.sin_addr));
+ break;
+ }
+ cCondWait::SleepMs(10);
+ }
+}
+
+// Querier state actions
+void cComponentIGMP::IGMPStartGeneralQueryTimer()
+{
+ m_Querier = true;
+ if (m_StartupQueryCount) {
+ gettimeofday(&m_GeneralQueryTimer, NULL);
+ m_GeneralQueryTimer.tv_sec += IGMP_STARTUP_QUERY_INTERVAL;
+ m_StartupQueryCount--;
+ }
+ else {
+ gettimeofday(&m_GeneralQueryTimer, NULL);
+ m_GeneralQueryTimer.tv_sec += IGMP_QUERY_INTERVAL;
+ }
+}
+
+void cComponentIGMP::IGMPStartOtherQuerierPresentTimer()
+{
+ m_Querier = false;
+ m_StartupQueryCount = 0;
+ gettimeofday(&m_GeneralQueryTimer, NULL);
+ m_GeneralQueryTimer.tv_sec += IGMP_OTHER_QUERIER_PRESENT_INTERVAL;
+}
+
+void cComponentIGMP::IGMPSendGeneralQuery()
+{
+ IGMPSendQuery(IGMP_ALL_HOSTS, IGMP_QUERY_RESPONSE_INTERVAL);
+}
+
+// Group state actions
+void cComponentIGMP::IGMPStartTimer(cMulticastGroup* Group, in_addr_t Member)
+{
+ gettimeofday(&Group->timeout, NULL);
+ Group->timeout.tv_sec += IGMP_GROUP_MEMBERSHIP_INTERVAL;
+ TV_CLR(Group->retransmit);
+ Group->reporter = Member;
+
+}
+
+void cComponentIGMP::IGMPStartV1HostTimer(cMulticastGroup* Group)
+{
+ gettimeofday(&Group->v1timer, NULL);
+ Group->v1timer.tv_sec += IGMP_GROUP_MEMBERSHIP_INTERVAL;
+}
+
+void cComponentIGMP::IGMPStartTimerAfterLeave(cMulticastGroup* Group, unsigned int MaxResponseTimeTs)
+{
+ //Group->Update(time(NULL) + MaxResponseTime * IGMP_LAST_MEMBER_QUERY_COUNT / 10);
+ MaxResponseTimeTs *= IGMP_LAST_MEMBER_QUERY_COUNT;
+ gettimeofday(&Group->timeout, NULL);
+ TV_ADD(Group->timeout, MaxResponseTimeTs);
+ TV_CLR(Group->retransmit);
+ Group->reporter = 0;
+}
+
+void cComponentIGMP::IGMPStartRetransmitTimer(cMulticastGroup* Group)
+{
+ gettimeofday(&Group->retransmit, NULL);
+ TV_ADD(Group->retransmit, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS);
+}
+
+void cComponentIGMP::IGMPClearRetransmitTimer(cMulticastGroup* Group)
+{
+ TV_CLR(Group->retransmit);
+}
+
+void cComponentIGMP::IGMPSendGroupQuery(cMulticastGroup* Group)
+{
+ IGMPSendQuery(Group->group, IGMP_LAST_MEMBER_QUERY_INTERVAL_TS);
+}
+
+void cComponentIGMP::IGMPStartMulticast(cMulticastGroup* Group)
+{
+ in_addr_t g = ntohl(Group->group);
+ if (g > MULTICAST_PRIV_MIN && g <= MULTICAST_PRIV_MAX) {
+ cChannel *channel = Channels.GetByNumber(g - MULTICAST_PRIV_MIN);
+ Group->connection = (cConnectionIGMP*) NewClient();
+ if (!Group->connection->Start(channel, Group->group)) {
+ DELETENULL(Group->connection);
+ }
+ }
+}
+
+void cComponentIGMP::IGMPStopMulticast(cMulticastGroup* Group)
+{
+ if (Group->connection)
+ Group->connection->Stop();
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/componentIGMP.h b/plugins/streamdev/streamdev-cvs/server/componentIGMP.h
new file mode 100644
index 0000000..09d8fde
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/componentIGMP.h
@@ -0,0 +1,62 @@
+/*
+ * $Id: componentIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_IGMPSERVER_H
+#define VDR_STREAMDEV_IGMPSERVER_H
+
+#include <sys/time.h>
+#include <time.h>
+#include <vdr/thread.h>
+#include "server/component.h"
+
+class cConnectionIGMP;
+class cMulticastGroup;
+
+class cComponentIGMP: public cServerComponent, public cThread {
+private:
+ char m_ReadBuffer[2048];
+ cList<cMulticastGroup> m_Groups;
+ in_addr_t m_BindIp;
+ int m_MaxChannelNumber;
+ struct timeval m_GeneralQueryTimer;
+ int m_StartupQueryCount;
+ bool m_Querier;
+ cCondWait m_CondWait;
+
+ cMulticastGroup* FindGroup(in_addr_t Group) const;
+
+ /* Add or remove local host to multicast group */
+ bool IGMPMembership(in_addr_t Group, bool Add = true);
+ void IGMPSendQuery(in_addr_t Group, int Timeout);
+
+ cServerConnection* ProcessMessage(struct igmp *Igmp, in_addr_t Group, in_addr_t Sender);
+
+ void IGMPStartGeneralQueryTimer();
+ void IGMPStartOtherQuerierPresentTimer();
+ void IGMPSendGeneralQuery();
+
+ void IGMPStartTimer(cMulticastGroup* Group, in_addr_t Member);
+ void IGMPStartV1HostTimer(cMulticastGroup* Group);
+ void IGMPStartTimerAfterLeave(cMulticastGroup* Group, unsigned int MaxResponseTime);
+ void IGMPStartRetransmitTimer(cMulticastGroup* Group);
+ void IGMPClearRetransmitTimer(cMulticastGroup* Group);
+ void IGMPSendGroupQuery(cMulticastGroup* Group);
+ void IGMPStartMulticast(cMulticastGroup* Group);
+ void IGMPStopMulticast(cMulticastGroup* Group);
+
+ virtual void Action();
+
+protected:
+ virtual cServerConnection *NewClient(void);
+
+public:
+ virtual bool Initialize(void);
+ virtual void Destruct(void);
+ virtual cServerConnection* Accept(void);
+
+ cComponentIGMP(void);
+ ~cComponentIGMP(void);
+};
+
+#endif // VDR_STREAMDEV_IGMPSERVER_H
diff --git a/plugins/streamdev/streamdev-cvs/server/componentVTP.c b/plugins/streamdev/streamdev-cvs/server/componentVTP.c
new file mode 100644
index 0000000..ed2df1c
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/componentVTP.c
@@ -0,0 +1,18 @@
+/*
+ * $Id: componentVTP.c,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
+ */
+
+#include "server/componentVTP.h"
+#include "server/connectionVTP.h"
+#include "server/setup.h"
+
+cComponentVTP::cComponentVTP(void):
+ cServerComponent("VTP", StreamdevServerSetup.VTPBindIP,
+ StreamdevServerSetup.VTPServerPort)
+{
+}
+
+cServerConnection *cComponentVTP::NewClient(void)
+{
+ return new cConnectionVTP;
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/componentVTP.h b/plugins/streamdev/streamdev-cvs/server/componentVTP.h
new file mode 100644
index 0000000..4f61eb5
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/componentVTP.h
@@ -0,0 +1,18 @@
+/*
+ * $Id: componentVTP.h,v 1.2 2005/05/09 20:22:29 lordjaxom Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SERVERS_SERVERVTP_H
+#define VDR_STREAMDEV_SERVERS_SERVERVTP_H
+
+#include "server/component.h"
+
+class cComponentVTP: public cServerComponent {
+protected:
+ virtual cServerConnection *NewClient(void);
+
+public:
+ cComponentVTP(void);
+};
+
+#endif // VDR_STREAMDEV_SERVERS_SERVERVTP_H
diff --git a/plugins/streamdev/streamdev-cvs/server/connection.c b/plugins/streamdev/streamdev-cvs/server/connection.c
new file mode 100644
index 0000000..eccb3c4
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connection.c
@@ -0,0 +1,255 @@
+/*
+ * $Id: connection.c,v 1.13 2009/09/18 10:43:26 schmirl Exp $
+ */
+
+#include "server/connection.h"
+#include "server/setup.h"
+#include "server/suspend.h"
+#include "common.h"
+
+#include <vdr/tools.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+cServerConnection::cServerConnection(const char *Protocol, int Type):
+ cTBSocket(Type),
+ m_Protocol(Protocol),
+ m_DeferClose(false),
+ m_Pending(false),
+ m_ReadBytes(0),
+ m_WriteBytes(0),
+ m_WriteIndex(0)
+{
+}
+
+cServerConnection::~cServerConnection()
+{
+}
+
+const cChannel* cServerConnection::ChannelFromString(const char *String, int *Apid) {
+ const cChannel *channel = NULL;
+ char *string = strdup(String);
+ char *ptr, *end;
+ int apididx = 0;
+
+ if ((ptr = strrchr(string, '+')) != NULL) {
+ *(ptr++) = '\0';
+ apididx = strtoul(ptr, &end, 10);
+ Dprintf("found apididx: %d\n", apididx);
+ }
+
+ if (isnumber(string)) {
+ int temp = strtol(String, NULL, 10);
+ if (temp >= 1 && temp <= Channels.MaxNumber())
+ channel = Channels.GetByNumber(temp);
+ } else {
+ channel = Channels.GetByChannelID(tChannelID::FromString(string));
+
+ if (channel == NULL) {
+ int i = 1;
+ while ((channel = Channels.GetByNumber(i, 1)) != NULL) {
+ if (String == channel->Name())
+ break;
+
+ i = channel->Number() + 1;
+ }
+ }
+ }
+
+ if (channel != NULL && apididx > 0) {
+ int apid = 0, index = 1;
+
+ for (int i = 0; channel->Apid(i) != 0; ++i, ++index) {
+ if (index == apididx) {
+ apid = channel->Apid(i);
+ break;
+ }
+ }
+
+ if (apid == 0) {
+ for (int i = 0; channel->Dpid(i) != 0; ++i, ++index) {
+ if (index == apididx) {
+ apid = channel->Dpid(i);
+ break;
+ }
+ }
+ }
+
+ if (Apid != NULL)
+ *Apid = apid;
+ }
+
+ free(string);
+ return channel;
+}
+
+bool cServerConnection::Read(void)
+{
+ int b;
+ if ((b = cTBSocket::Read(m_ReadBuffer + m_ReadBytes,
+ sizeof(m_ReadBuffer) - m_ReadBytes - 1)) < 0) {
+ esyslog("ERROR: read from client (%s) %s:%d failed: %m",
+ m_Protocol, RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ if (b == 0) {
+ isyslog("client (%s) %s:%d has closed connection",
+ m_Protocol, RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ m_ReadBytes += b;
+ m_ReadBuffer[m_ReadBytes] = '\0';
+
+ char *end;
+ bool result = true;
+ while ((end = strchr(m_ReadBuffer, '\012')) != NULL) {
+ *end = '\0';
+ if (end > m_ReadBuffer && *(end - 1) == '\015')
+ *(end - 1) = '\0';
+
+ if (!Command(m_ReadBuffer))
+ return false;
+
+ m_ReadBytes -= ++end - m_ReadBuffer;
+ if (m_ReadBytes > 0)
+ memmove(m_ReadBuffer, end, m_ReadBytes);
+ }
+
+ if (m_ReadBytes == sizeof(m_ReadBuffer) - 1) {
+ esyslog("ERROR: streamdev: input buffer overflow (%s) for %s:%d",
+ m_Protocol, RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ return result;
+}
+
+bool cServerConnection::Write(void)
+{
+ int b;
+ if ((b = cTBSocket::Write(m_WriteBuffer + m_WriteIndex,
+ m_WriteBytes - m_WriteIndex)) < 0) {
+ esyslog("ERROR: streamdev: write to client (%s) %s:%d failed: %m",
+ m_Protocol, RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ m_WriteIndex += b;
+ if (m_WriteIndex == m_WriteBytes) {
+ m_WriteIndex = 0;
+ m_WriteBytes = 0;
+ if (m_Pending)
+ Command(NULL);
+ if (m_DeferClose)
+ return false;
+ Flushed();
+ }
+ return true;
+}
+
+bool cServerConnection::Respond(const char *Message, bool Last, ...)
+{
+ char *buffer;
+ int length;
+ va_list ap;
+ va_start(ap, Last);
+ length = vasprintf(&buffer, Message, ap);
+ va_end(ap);
+
+ if (length < 0) {
+ esyslog("ERROR: streamdev: buffer allocation failed (%s) for %s:%d",
+ m_Protocol, RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ if (m_WriteBytes + length + 2 > sizeof(m_WriteBuffer)) {
+ esyslog("ERROR: streamdev: output buffer overflow (%s) for %s:%d",
+ m_Protocol, RemoteIp().c_str(), RemotePort());
+ free(buffer);
+ return false;
+ }
+ Dprintf("OUT: |%s|\n", buffer);
+ memcpy(m_WriteBuffer + m_WriteBytes, buffer, length);
+ free(buffer);
+
+ m_WriteBytes += length;
+ m_WriteBuffer[m_WriteBytes++] = '\015';
+ m_WriteBuffer[m_WriteBytes++] = '\012';
+ m_Pending = !Last;
+ return true;
+}
+
+cDevice *cServerConnection::GetDevice(const cChannel *Channel, int Priority)
+{
+ cDevice *device = NULL;
+
+ /*Dprintf("+ Statistics:\n");
+ Dprintf("+ Current Channel: %d\n", cDevice::CurrentChannel());
+ Dprintf("+ Current Device: %d\n", cDevice::ActualDevice()->CardIndex());
+ Dprintf("+ Transfer Mode: %s\n", cDevice::ActualDevice()
+ == cDevice::PrimaryDevice() ? "false" : "true");
+ Dprintf("+ Replaying: %s\n", cDevice::PrimaryDevice()->Replaying() ? "true"
+ : "false");*/
+
+ Dprintf(" * GetDevice(const cChannel*, int)\n");
+ Dprintf(" * -------------------------------\n");
+
+ device = cDevice::GetDevice(Channel, Priority, false);
+
+ Dprintf(" * Found following device: %p (%d)\n", device,
+ device ? device->CardIndex() + 1 : 0);
+ if (device == cDevice::ActualDevice())
+ Dprintf(" * is actual device\n");
+ if (!cSuspendCtl::IsActive() && StreamdevServerSetup.SuspendMode != smAlways)
+ Dprintf(" * NOT suspended\n");
+
+ if (!device || (device == cDevice::ActualDevice()
+ && !cSuspendCtl::IsActive()
+ && StreamdevServerSetup.SuspendMode != smAlways)) {
+ // mustn't switch actual device
+ // maybe a device would be free if THIS connection did turn off its streams?
+ Dprintf(" * trying again...\n");
+ const cChannel *current = Channels.GetByNumber(cDevice::CurrentChannel());
+ isyslog("streamdev-server: Detaching current receiver");
+ Detach();
+ device = cDevice::GetDevice(Channel, Priority, false);
+ Attach();
+ Dprintf(" * Found following device: %p (%d)\n", device,
+ device ? device->CardIndex() + 1 : 0);
+ if (device == cDevice::ActualDevice())
+ Dprintf(" * is actual device\n");
+ if (!cSuspendCtl::IsActive()
+ && StreamdevServerSetup.SuspendMode != smAlways)
+ Dprintf(" * NOT suspended\n");
+ if (current && !TRANSPONDER(Channel, current))
+ Dprintf(" * NOT same transponder\n");
+ if (device && (device == cDevice::ActualDevice()
+ && !cSuspendCtl::IsActive()
+ && StreamdevServerSetup.SuspendMode != smAlways
+ && current != NULL
+ && !TRANSPONDER(Channel, current))) {
+ // now we would have to switch away live tv...let's see if live tv
+ // can be handled by another device
+ cDevice *newdev = NULL;
+ for (int i = 0; i < cDevice::NumDevices(); ++i) {
+ cDevice *dev = cDevice::GetDevice(i);
+ if (dev->ProvidesChannel(current, 0) && dev != device) {
+ newdev = dev;
+ break;
+ }
+ }
+ Dprintf(" * Found device for live tv: %p (%d)\n", newdev,
+ newdev ? newdev->CardIndex() + 1 : 0);
+ if (newdev == NULL || newdev == device)
+ // no suitable device to continue live TV, giving up...
+ device = NULL;
+ else
+ newdev->SwitchChannel(current, true);
+ }
+ }
+
+ return device;
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/connection.h b/plugins/streamdev/streamdev-cvs/server/connection.h
new file mode 100644
index 0000000..73cb3d5
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connection.h
@@ -0,0 +1,99 @@
+/*
+ * $Id: connection.h,v 1.8 2009/09/18 10:43:26 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SERVER_CONNECTION_H
+#define VDR_STREAMDEV_SERVER_CONNECTION_H
+
+#include "tools/socket.h"
+#include "common.h"
+
+class cChannel;
+class cDevice;
+
+/* Basic capabilities of a straight text-based protocol, most functions
+ virtual to support more complicated protocols */
+
+class cServerConnection: public cListObject, public cTBSocket
+{
+private:
+ const char *m_Protocol;
+ bool m_DeferClose;
+ bool m_Pending;
+
+ char m_ReadBuffer[MAXPARSEBUFFER];
+ uint m_ReadBytes;
+
+ char m_WriteBuffer[MAXPARSEBUFFER];
+ uint m_WriteBytes;
+ uint m_WriteIndex;
+
+protected:
+ /* Will be called when a command terminated by a newline has been
+ received */
+ virtual bool Command(char *Cmd) = 0;
+
+ /* Will put Message into the response queue, which will be sent in the next
+ server cycle. Note that Message will be line-terminated by Respond.
+ Only one line at a time may be sent. If there are lines to follow, set
+ Last to false. Command(NULL) will be called in the next cycle, so you can
+ post the next line. */
+ virtual bool Respond(const char *Message, bool Last = true, ...);
+ //__attribute__ ((format (printf, 2, 4)));
+
+ static const cChannel *ChannelFromString(const char *String, int *Apid = NULL);
+
+public:
+ /* If you derive, specify a short string such as HTTP for Protocol, which
+ will be displayed in error messages */
+ cServerConnection(const char *Protocol, int Type = SOCK_STREAM);
+ virtual ~cServerConnection();
+
+ /* If true, any client IP will be accepted */
+ virtual bool CanAuthenticate(void) { return false; }
+
+ /* Gets called if the client has been accepted by the core */
+ virtual void Welcome(void) { }
+
+ /* Gets called if the client has been rejected by the core */
+ virtual void Reject(void) { DeferClose(); }
+
+ /* Get the client socket's file number */
+ virtual int Socket(void) const { return (int)*this; }
+
+ /* Determine if there is data to send or any command pending */
+ virtual bool HasData(void) const;
+
+ /* Gets called by server when the socket can accept more data. Writes
+ the buffer filled up by Respond(). Calls Command(NULL) if there is a
+ command pending. Returns false in case of an error */
+ virtual bool Write(void);
+
+ /* Gets called by server when there is incoming data to read. Calls
+ Command() for each line. Returns false in case of an error, or if
+ the connection shall be closed and removed by the server */
+ virtual bool Read(void);
+
+ /* Is polled regularely by the server. Returns true if the connection
+ needs to be terminated. */
+ virtual bool Abort(void) const = 0;
+
+ /* Will make the socket close after sending all queued output data */
+ void DeferClose(void) { m_DeferClose = true; }
+
+ /* Will retrieve an unused device for transmitting data. Use the returned
+ cDevice in a following call to StartTransfer */
+ cDevice *GetDevice(const cChannel *Channel, int Priority);
+
+ virtual void Flushed(void) {}
+
+ virtual void Detach(void) = 0;
+ virtual void Attach(void) = 0;
+};
+
+inline bool cServerConnection::HasData(void) const
+{
+ return m_WriteBytes > 0 || m_Pending || m_DeferClose;
+}
+
+#endif // VDR_STREAMDEV_SERVER_CONNECTION_H
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionHTTP.c b/plugins/streamdev/streamdev-cvs/server/connectionHTTP.c
new file mode 100644
index 0000000..83e568d
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connectionHTTP.c
@@ -0,0 +1,296 @@
+/*
+ * $Id: connectionHTTP.c,v 1.17 2009/06/19 06:32:45 schmirl Exp $
+ */
+
+#include <ctype.h>
+
+#include "server/connectionHTTP.h"
+#include "server/menuHTTP.h"
+#include "server/server.h"
+#include "server/setup.h"
+
+cConnectionHTTP::cConnectionHTTP(void):
+ cServerConnection("HTTP"),
+ m_Status(hsRequest),
+ m_LiveStreamer(NULL),
+ m_StreamerParameter(""),
+ m_Channel(NULL),
+ m_Apid(0),
+ m_StreamType((eStreamType)StreamdevServerSetup.HTTPStreamType),
+ m_ChannelList(NULL)
+{
+ Dprintf("constructor hsRequest\n");
+}
+
+cConnectionHTTP::~cConnectionHTTP()
+{
+ delete m_LiveStreamer;
+}
+
+bool cConnectionHTTP::CanAuthenticate(void)
+{
+ return opt_auth != NULL;
+}
+
+bool cConnectionHTTP::Command(char *Cmd)
+{
+ Dprintf("command %s\n", Cmd);
+ switch (m_Status) {
+ case hsRequest:
+ Dprintf("Request\n");
+ m_Request = Cmd;
+ m_Status = hsHeaders;
+ return true;
+
+ case hsHeaders:
+ if (*Cmd == '\0') {
+ m_Status = hsBody;
+ return ProcessRequest();
+ }
+ if (strncasecmp(Cmd, "Host:", 5) == 0) {
+ Dprintf("Host-Header\n");
+ m_Host = (std::string) skipspace(Cmd + 5);
+ return true;
+ }
+ else if (strncasecmp(Cmd, "Authorization:", 14) == 0) {
+ Cmd = skipspace(Cmd + 14);
+ if (strncasecmp(Cmd, "Basic", 5) == 0) {
+ Dprintf("'Authorization Basic'-Header\n");
+ m_Authorization = (std::string) skipspace(Cmd + 5);
+ return true;
+ }
+ }
+ Dprintf("header\n");
+ return true;
+ default:
+ // skip additional blank lines
+ if (*Cmd == '\0')
+ return true;
+ break;
+ }
+ return false; // ??? shouldn't happen
+}
+
+bool cConnectionHTTP::ProcessRequest(void)
+{
+ Dprintf("process\n");
+ if (!StreamdevHosts.Acceptable(RemoteIpAddr()))
+ {
+ if (!opt_auth || m_Authorization.empty() || m_Authorization.compare(opt_auth) != 0) {
+ isyslog("streamdev-server: HTTP authorization required");
+ DeferClose();
+ return Respond("HTTP/1.0 401 Authorization Required")
+ && Respond("WWW-authenticate: basic Realm=\"Streamdev-Server\")")
+ && Respond("");
+ }
+ }
+ if (m_Request.substr(0, 4) == "GET " && CmdGET(m_Request.substr(4))) {
+ switch (m_Job) {
+ case hjListing:
+ if (m_ChannelList)
+ return Respond("%s", true, m_ChannelList->HttpHeader().c_str());
+ break;
+
+ case hjTransfer:
+ if (m_Channel == NULL) {
+ DeferClose();
+ return Respond("HTTP/1.0 404 not found");
+ }
+
+ m_LiveStreamer = new cStreamdevLiveStreamer(0, m_StreamerParameter);
+ cDevice *device = GetDevice(m_Channel, 0);
+ if (device != NULL) {
+ device->SwitchChannel(m_Channel, false);
+ if (m_LiveStreamer->SetChannel(m_Channel, m_StreamType, m_Apid)) {
+ m_LiveStreamer->SetDevice(device);
+ if (!SetDSCP())
+ LOG_ERROR_STR("unable to set DSCP sockopt");
+ if (m_StreamType == stES && (m_Apid != 0 || ISRADIO(m_Channel))) {
+ return Respond("HTTP/1.0 200 OK")
+ && Respond("Content-Type: audio/mpeg")
+ && Respond("icy-name: %s", true, m_Channel->Name())
+ && Respond("");
+ } else {
+ return Respond("HTTP/1.0 200 OK")
+ && Respond("Content-Type: video/mpeg")
+ && Respond("");
+ }
+ }
+ }
+ DELETENULL(m_LiveStreamer);
+ DeferClose();
+ return Respond("HTTP/1.0 409 Channel not available")
+ && Respond("");
+ }
+ }
+
+ DeferClose();
+ return Respond("HTTP/1.0 400 Bad Request")
+ && Respond("");
+}
+
+void cConnectionHTTP::Flushed(void)
+{
+ std::string line;
+
+ if (m_Status != hsBody)
+ return;
+
+ switch (m_Job) {
+ case hjListing:
+ if (m_ChannelList) {
+ if (m_ChannelList->HasNext()) {
+ if (!Respond("%s", true, m_ChannelList->Next().c_str()))
+ DeferClose();
+ }
+ else {
+ DELETENULL(m_ChannelList);
+ m_Status = hsFinished;
+ DeferClose();
+ }
+ return;
+ }
+ // should never be reached
+ esyslog("streamdev-server cConnectionHTTP::Flushed(): no channel list");
+ m_Status = hsFinished;
+ break;
+
+ case hjTransfer:
+ Dprintf("streamer start\n");
+ m_LiveStreamer->Start(this);
+ m_Status = hsFinished;
+ break;
+ }
+}
+
+bool cConnectionHTTP::CmdGET(const std::string &Opts)
+{
+ const char *ptr, *sp, *pp, *fp, *xp, *qp, *ep;
+ const cChannel *chan;
+ int apid = 0;
+
+ ptr = Opts.c_str();
+
+ // find begin of URL
+ sp = skipspace(ptr);
+ // find end of URL (\0 or first space character)
+ for (ep = sp; *ep && !isspace(*ep); ep++)
+ ;
+ // find begin of query string (first ?)
+ for (qp = sp; qp < ep && *qp != '?'; qp++)
+ ;
+ // find begin of filename (last /)
+ for (fp = qp; fp > sp && *fp != '/'; --fp)
+ ;
+ // find begin of section params (first ;)
+ for (pp = sp; pp < fp && *pp != ';'; pp++)
+ ;
+ // find filename extension (first .)
+ for (xp = fp; xp < qp && *xp != '.'; xp++)
+ ;
+ if (qp - xp > 5) // too long for a filename extension
+ xp = qp;
+
+ std::string type, filespec, fileext, query;
+ // Streamtype with leading / stripped off
+ if (pp > sp)
+ type = Opts.substr(sp - ptr + 1, pp - sp - 1);
+ // Section parameters with leading ; stripped off
+ if (fp > pp)
+ m_StreamerParameter = Opts.substr(pp - ptr + 1, fp - pp - 1);
+ // file basename with leading / stripped off
+ if (xp > fp)
+ filespec = Opts.substr(fp - ptr + 1, xp - fp - 1);
+ // file extension including leading .
+ fileext = Opts.substr(xp - ptr, qp - xp);
+ // query string including leading ?
+ query = Opts.substr(qp - ptr, ep - qp);
+
+ Dprintf("before channelfromstring: type(%s) param(%s) filespec(%s) fileext(%s) query(%s)\n", type.c_str(), m_StreamerParameter.c_str(), filespec.c_str(), fileext.c_str(), query.c_str());
+
+ const char* pType = type.c_str();
+ if (strcasecmp(pType, "PS") == 0) {
+ m_StreamType = stPS;
+ } else if (strcasecmp(pType, "PES") == 0) {
+ m_StreamType = stPES;
+ } else if (strcasecmp(pType, "TS") == 0) {
+ m_StreamType = stTS;
+ } else if (strcasecmp(pType, "ES") == 0) {
+ m_StreamType = stES;
+ } else if (strcasecmp(pType, "Extern") == 0) {
+ m_StreamType = stExtern;
+ }
+
+ std::string groupTarget;
+ cChannelIterator *iterator = NULL;
+
+ if (filespec.compare("tree") == 0) {
+ const cChannel* c = NULL;
+ size_t groupIndex = query.find("group=");
+ if (groupIndex != std::string::npos)
+ c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
+ iterator = new cListTree(c);
+ groupTarget = filespec + fileext;
+ } else if (filespec.compare("groups") == 0) {
+ iterator = new cListGroups();
+ groupTarget = (std::string) "group" + fileext;
+ } else if (filespec.compare("group") == 0) {
+ const cChannel* c = NULL;
+ size_t groupIndex = query.find("group=");
+ if (groupIndex != std::string::npos)
+ c = cChannelList::GetGroup(atoi(query.c_str() + groupIndex + 6));
+ iterator = new cListGroup(c);
+ } else if (filespec.compare("channels") == 0) {
+ iterator = new cListChannels();
+ } else if (filespec.compare("all") == 0 ||
+ (filespec.empty() && fileext.empty())) {
+ iterator = new cListAll();
+ }
+
+ if (iterator) {
+ if (filespec.empty() || fileext.compare(".htm") == 0 || fileext.compare(".html") == 0) {
+ m_ChannelList = new cHtmlChannelList(iterator, m_StreamType, (filespec + fileext + query).c_str(), groupTarget.c_str());
+ m_Job = hjListing;
+ } else if (fileext.compare(".m3u") == 0) {
+ std::string base;
+ if (*(m_Host.c_str()))
+ base = "http://" + m_Host + "/";
+ else
+ base = (std::string) "http://" + LocalIp() + ":" +
+ (const char*) itoa(StreamdevServerSetup.HTTPServerPort) + "/";
+ if (type.empty())
+ {
+ switch (m_StreamType)
+ {
+ case stTS: base += "TS/"; break;
+ case stPS: base += "PS/"; break;
+ case stPES: base += "PES/"; break;
+ case stES: base += "ES/"; break;
+ case stExtern: base += "Extern/"; break;
+ default: break;
+
+ }
+ } else {
+ base += type;
+ if (!m_StreamerParameter.empty())
+ base += ";" + m_StreamerParameter;
+ base += "/";
+ }
+ m_ChannelList = new cM3uChannelList(iterator, base.c_str());
+ m_Job = hjListing;
+ } else {
+ delete iterator;
+ return false;
+ }
+ } else if ((chan = ChannelFromString(filespec.c_str(), &apid)) != NULL) {
+ m_Channel = chan;
+ m_Apid = apid;
+ Dprintf("Apid is %d\n", apid);
+ m_Job = hjTransfer;
+ } else
+ return false;
+
+ Dprintf("after channelfromstring\n");
+ return true;
+}
+
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionHTTP.h b/plugins/streamdev/streamdev-cvs/server/connectionHTTP.h
new file mode 100644
index 0000000..0548959
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connectionHTTP.h
@@ -0,0 +1,70 @@
+/*
+ * $Id: connectionHTTP.h,v 1.6 2008/10/14 11:05:48 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
+#define VDR_STREAMDEV_SERVERS_CONNECTIONHTTP_H
+
+#include "connection.h"
+#include "server/livestreamer.h"
+
+#include <tools/select.h>
+
+class cChannel;
+class cStreamdevLiveStreamer;
+class cChannelList;
+
+class cConnectionHTTP: public cServerConnection {
+private:
+ enum eHTTPStatus {
+ hsRequest,
+ hsHeaders,
+ hsBody,
+ hsFinished,
+ };
+
+ enum eHTTPJob {
+ hjTransfer,
+ hjListing,
+ };
+
+ std::string m_Request;
+ std::string m_Host;
+ std::string m_Authorization;
+ //std::map<std::string,std::string> m_Headers; TODO: later?
+ eHTTPStatus m_Status;
+ eHTTPJob m_Job;
+ // job: transfer
+ cStreamdevLiveStreamer *m_LiveStreamer;
+ std::string m_StreamerParameter;
+ const cChannel *m_Channel;
+ int m_Apid;
+ eStreamType m_StreamType;
+ // job: listing
+ cChannelList *m_ChannelList;
+
+protected:
+ bool ProcessRequest(void);
+
+public:
+ cConnectionHTTP(void);
+ virtual ~cConnectionHTTP();
+
+ virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
+ virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
+
+ virtual bool CanAuthenticate(void);
+
+ virtual bool Command(char *Cmd);
+ bool CmdGET(const std::string &Opts);
+
+ virtual bool Abort(void) const;
+ virtual void Flushed(void);
+};
+
+inline bool cConnectionHTTP::Abort(void) const
+{
+ return m_LiveStreamer && m_LiveStreamer->Abort();
+}
+
+#endif // VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionIGMP.c b/plugins/streamdev/streamdev-cvs/server/connectionIGMP.c
new file mode 100644
index 0000000..dc08798
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connectionIGMP.c
@@ -0,0 +1,64 @@
+/*
+ * $Id: connectionIGMP.c,v 1.1 2009/02/13 10:39:22 schmirl Exp $
+ */
+
+#include <ctype.h>
+
+#include "server/connectionIGMP.h"
+#include "server/server.h"
+#include "server/setup.h"
+#include <vdr/channels.h>
+
+cConnectionIGMP::cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType) :
+ cServerConnection(Name, SOCK_DGRAM),
+ m_LiveStreamer(NULL),
+ m_ClientPort(ClientPort),
+ m_StreamType(StreamType)
+{
+}
+
+cConnectionIGMP::~cConnectionIGMP()
+{
+ delete m_LiveStreamer;
+}
+
+bool cConnectionIGMP::Start(cChannel *Channel, in_addr_t Dst)
+{
+ if (Channel != NULL) {
+ cDevice *device = GetDevice(Channel, 0);
+ if (device != NULL) {
+ device->SwitchChannel(Channel, false);
+ struct in_addr ip;
+ ip.s_addr = Dst;
+ if (Connect(inet_ntoa(ip), m_ClientPort)) {
+ m_LiveStreamer = new cStreamdevLiveStreamer(0);
+ if (m_LiveStreamer->SetChannel(Channel, m_StreamType)) {
+ m_LiveStreamer->SetDevice(device);
+ if (!SetDSCP())
+ LOG_ERROR_STR("unable to set DSCP sockopt");
+ Dprintf("streamer start\n");
+ m_LiveStreamer->Start(this);
+ return true;
+ }
+ else
+ esyslog("streamdev-server IGMP: SetDevice failed");
+ DELETENULL(m_LiveStreamer);
+ }
+ else
+ esyslog("streamdev-server IGMP: Connect failed: %m");
+ }
+ else
+ esyslog("streamdev-server IGMP: GetDevice failed");
+ }
+ else
+ esyslog("streamdev-server IGMP: Channel not found");
+ return false;
+}
+
+void cConnectionIGMP::Stop()
+{
+ if (m_LiveStreamer) {
+ m_LiveStreamer->Stop();
+ DELETENULL(m_LiveStreamer);
+ }
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionIGMP.h b/plugins/streamdev/streamdev-cvs/server/connectionIGMP.h
new file mode 100644
index 0000000..90abd58
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connectionIGMP.h
@@ -0,0 +1,45 @@
+/*
+ * $Id: connectionIGMP.h,v 1.1 2009/02/13 10:39:22 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
+#define VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
+
+#include "connection.h"
+#include "server/livestreamer.h"
+
+#include <tools/select.h>
+
+#define MULTICAST_PRIV_MIN ((uint32_t) 0xefff0000)
+#define MULTICAST_PRIV_MAX ((uint32_t) 0xeffffeff)
+
+class cStreamdevLiveStreamer;
+
+class cConnectionIGMP: public cServerConnection {
+private:
+ cStreamdevLiveStreamer *m_LiveStreamer;
+ int m_ClientPort;
+ eStreamType m_StreamType;
+
+public:
+ cConnectionIGMP(const char* Name, int ClientPort, eStreamType StreamType);
+ virtual ~cConnectionIGMP();
+
+ bool Start(cChannel *Channel, in_addr_t Dst);
+ void Stop();
+
+ /* Not used here */
+ virtual bool Command(char *Cmd) { return false; }
+
+ virtual void Attach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Attach(); }
+ virtual void Detach(void) { if (m_LiveStreamer != NULL) m_LiveStreamer->Detach(); }
+
+ virtual bool Abort(void) const;
+};
+
+inline bool cConnectionIGMP::Abort(void) const
+{
+ return !m_LiveStreamer || m_LiveStreamer->Abort();
+}
+
+#endif // VDR_STREAMDEV_SERVERS_CONNECTIONIGMP_H
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionVTP.c b/plugins/streamdev/streamdev-cvs/server/connectionVTP.c
new file mode 100644
index 0000000..7ff60e5
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connectionVTP.c
@@ -0,0 +1,1768 @@
+/*
+ * $Id: connectionVTP.c,v 1.27 2010/01/29 12:03:02 schmirl Exp $
+ */
+
+#include "server/connectionVTP.h"
+#include "server/livestreamer.h"
+#include "server/suspend.h"
+#include "setup.h"
+
+#include <vdr/tools.h>
+#include <vdr/videodir.h>
+#include <vdr/menu.h>
+#include <tools/select.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdarg.h>
+
+/* VTP Response codes:
+ 220: Service ready
+ 221: Service closing connection
+ 451: Requested action aborted: try again
+ 500: Syntax error or Command unrecognized
+ 501: Wrong parameters or missing parameters
+ 550: Requested action not taken
+ 551: Data connection not accepted
+ 560: Channel not available currently
+ 561: Capability not known
+ 562: Pid not available currently
+ 563: Recording not available (currently?)
+*/
+
+enum eDumpModeStreamdev { dmsdAll, dmsdPresent, dmsdFollowing, dmsdAtTime, dmsdFromToTime };
+
+// --- cLSTEHandler -----------------------------------------------------------
+
+class cLSTEHandler
+{
+private:
+#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM)
+ enum eStates { Channel, Event, Title, Subtitle, Description, Vps, Content,
+ EndEvent, EndChannel, EndEPG };
+#elif APIVERSNUM >= 10711
+ enum eStates { Channel, Event, Title, Subtitle, Description, Vps, Content, Rating,
+ EndEvent, EndChannel, EndEPG };
+#else
+ enum eStates { Channel, Event, Title, Subtitle, Description, Vps,
+ EndEvent, EndChannel, EndEPG };
+#endif /* PARENTALRATING */
+ cConnectionVTP *m_Client;
+ cSchedulesLock *m_SchedulesLock;
+ const cSchedules *m_Schedules;
+ const cSchedule *m_Schedule;
+ const cEvent *m_Event;
+ int m_Errno;
+ cString m_Error;
+ eStates m_State;
+ bool m_Traverse;
+ time_t m_ToTime;
+public:
+ cLSTEHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTEHandler();
+ bool Next(bool &Last);
+};
+
+cLSTEHandler::cLSTEHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_SchedulesLock(new cSchedulesLock(false, 500)),
+ m_Schedules(cSchedules::Schedules(*m_SchedulesLock)),
+ m_Schedule(NULL),
+ m_Event(NULL),
+ m_Errno(0),
+ m_State(Channel),
+ m_Traverse(false),
+ m_ToTime(0)
+{
+ eDumpModeStreamdev dumpmode = dmsdAll;
+ time_t attime = 0;
+ time_t fromtime = 0;
+
+ if (m_Schedules != NULL && *Option) {
+ char buf[strlen(Option) + 1];
+ strcpy(buf, Option);
+ const char *delim = " \t";
+ char *strtok_next;
+ char *p = strtok_r(buf, delim, &strtok_next);
+ while (p && dumpmode == dmsdAll) {
+ if (strcasecmp(p, "NOW") == 0)
+ dumpmode = dmsdPresent;
+ else if (strcasecmp(p, "NEXT") == 0)
+ dumpmode = dmsdFollowing;
+ else if (strcasecmp(p, "AT") == 0) {
+ dumpmode = dmsdAtTime;
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (isnumber(p))
+ attime = strtol(p, NULL, 10);
+ else {
+ m_Errno = 501;
+ m_Error = "Invalid time";
+ break;
+ }
+ } else {
+ m_Errno = 501;
+ m_Error = "Missing time";
+ break;
+ }
+ }
+ else if (strcasecmp(p, "FROM") == 0) {
+ dumpmode = dmsdFromToTime;
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (isnumber(p))
+ fromtime = strtol(p, NULL, 10);
+ else {
+ m_Errno = 501;
+ m_Error = "Invalid time";
+ break;
+ }
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (strcasecmp(p, "TO") == 0) {
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (isnumber(p))
+ m_ToTime = strtol(p, NULL, 10);
+ else {
+ m_Errno = 501;
+ m_Error = "Invalid time";
+ break;
+ }
+ } else {
+ m_Errno = 501;
+ m_Error = "Missing time";
+ break;
+ }
+ }
+ }
+ } else {
+ m_Errno = 501;
+ m_Error = "Missing time";
+ break;
+ }
+ } else if (!m_Schedule) {
+ cChannel* Channel = NULL;
+ if (isnumber(p))
+ Channel = Channels.GetByNumber(strtol(Option, NULL, 10));
+ else
+ Channel = Channels.GetByChannelID(tChannelID::FromString(
+ Option));
+ if (Channel) {
+ m_Schedule = m_Schedules->GetSchedule(Channel->GetChannelID());
+ if (!m_Schedule) {
+ m_Errno = 550;
+ m_Error = "No schedule found";
+ break;
+ }
+ } else {
+ m_Errno = 550;
+ m_Error = cString::sprintf("Channel \"%s\" not defined", p);
+ break;
+ }
+ } else {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Unknown option: \"%s\"", p);
+ break;
+ }
+ p = strtok_r(NULL, delim, &strtok_next);
+ }
+ } else if (m_Schedules == NULL) {
+ m_Errno = 451;
+ m_Error = "EPG data is being modified, try again";
+ }
+
+ if (*m_Error == NULL) {
+ if (m_Schedule != NULL)
+ m_Schedules = NULL;
+ else if (m_Schedules != NULL)
+ m_Schedule = m_Schedules->First();
+
+ if (m_Schedule != NULL && m_Schedule->Events() != NULL) {
+ switch (dumpmode) {
+ case dmsdAll: m_Event = m_Schedule->Events()->First();
+ m_Traverse = true;
+ break;
+ case dmsdPresent: m_Event = m_Schedule->GetPresentEvent();
+ break;
+ case dmsdFollowing: m_Event = m_Schedule->GetFollowingEvent();
+ break;
+ case dmsdAtTime: m_Event = m_Schedule->GetEventAround(attime);
+ break;
+ case dmsdFromToTime:
+ if (m_Schedule->Events()->Count() <= 1) {
+ m_Event = m_Schedule->Events()->First();
+ break;
+ }
+ if (fromtime < m_Schedule->Events()->First()->StartTime()) {
+ fromtime = m_Schedule->Events()->First()->StartTime();
+ }
+ if (m_ToTime > m_Schedule->Events()->Last()->EndTime()) {
+ m_ToTime = m_Schedule->Events()->Last()->EndTime();
+ }
+ m_Event = m_Schedule->GetEventAround(fromtime);
+ m_Traverse = true;
+ break;
+ }
+ }
+ }
+}
+
+cLSTEHandler::~cLSTEHandler()
+{
+ delete m_SchedulesLock;
+}
+
+bool cLSTEHandler::Next(bool &Last)
+{
+ if (*m_Error != NULL) {
+ Last = true;
+ cString str(m_Error);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, "%s", *str);
+ }
+
+ Last = false;
+ switch (m_State) {
+ case Channel:
+ if (m_Schedule != NULL) {
+ cChannel *channel = Channels.GetByChannelID(m_Schedule->ChannelID(),
+ true);
+ if (channel != NULL) {
+ m_State = Event;
+ return m_Client->Respond(-215, "C %s %s",
+ *channel->GetChannelID().ToString(),
+ channel->Name());
+ } else {
+ esyslog("ERROR: vdr streamdev: unable to find channel %s by ID",
+ *m_Schedule->ChannelID().ToString());
+ m_State = EndChannel;
+ return Next(Last);
+ }
+ } else {
+ m_State = EndEPG;
+ return Next(Last);
+ }
+ break;
+
+ case Event:
+ if (m_Event != NULL) {
+ m_State = Title;
+#ifdef __FreeBSD__
+ return m_Client->Respond(-215, "E %u %d %d %X", m_Event->EventID(),
+#else
+ return m_Client->Respond(-215, "E %u %ld %d %X", m_Event->EventID(),
+#endif
+ m_Event->StartTime(), m_Event->Duration(),
+ m_Event->TableID());
+ } else {
+ m_State = EndChannel;
+ return Next(Last);
+ }
+ break;
+
+ case Title:
+ m_State = Subtitle;
+ if (!isempty(m_Event->Title()))
+ return m_Client->Respond(-215, "T %s", m_Event->Title());
+ else
+ return Next(Last);
+ break;
+
+ case Subtitle:
+ m_State = Description;
+ if (!isempty(m_Event->ShortText()))
+ return m_Client->Respond(-215, "S %s", m_Event->ShortText());
+ else
+ return Next(Last);
+ break;
+
+ case Description:
+ m_State = Vps;
+ if (!isempty(m_Event->Description())) {
+ char *copy = strdup(m_Event->Description());
+ cString cpy(copy, true);
+ strreplace(copy, '\n', '|');
+ return m_Client->Respond(-215, "D %s", copy);
+ } else
+ return Next(Last);
+ break;
+
+ case Vps:
+#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM) || APIVERSNUM >= 10711
+ m_State = Content;
+#else
+ m_State = EndEvent;
+#endif /* PARENTALRATING */
+ if (m_Event->Vps())
+#ifdef __FreeBSD__
+ return m_Client->Respond(-215, "V %d", m_Event->Vps());
+#else
+ return m_Client->Respond(-215, "V %ld", m_Event->Vps());
+#endif
+ else
+ return Next(Last);
+ break;
+
+#if defined(USE_PARENTALRATING) || defined(PARENTALRATINGCONTENTVERSNUM)
+ case Content:
+ m_State = EndEvent;
+ if (!isempty(m_Event->GetContentsString())) {
+ char *copy = strdup(m_Event->GetContentsString());
+ cString cpy(copy, true);
+ strreplace(copy, '\n', '|');
+ return m_Client->Respond(-215, "G %i %i %s", m_Event->Contents() & 0xF0, m_Event->Contents() & 0x0F, copy);
+ } else
+ return Next(Last);
+ break;
+#elif APIVERSNUM >= 10711
+ case Content:
+ m_State = Rating;
+ if (!isempty(m_Event->ContentToString(m_Event->Contents()))) {
+ char *copy = strdup(m_Event->ContentToString(m_Event->Contents()));
+ cString cpy(copy, true);
+ strreplace(copy, '\n', '|');
+ return m_Client->Respond(-215, "G %i %i %s", m_Event->Contents() & 0xF0, m_Event->Contents() & 0x0F, copy);
+ } else
+ return Next(Last);
+ break;
+
+ case Rating:
+ m_State = EndEvent;
+ if (m_Event->ParentalRating())
+ return m_Client->Respond(-215, "R %d", m_Event->ParentalRating());
+ else
+ return Next(Last);
+ break;
+#endif
+
+ case EndEvent:
+ if (m_Traverse) {
+ m_Event = m_Schedule->Events()->Next(m_Event);
+ if ((m_Event != NULL) && (m_ToTime != 0) && (m_Event->StartTime() > m_ToTime)) {
+ m_Event = NULL;
+ }
+ }
+ else
+ m_Event = NULL;
+
+ if (m_Event != NULL)
+ m_State = Event;
+ else
+ m_State = EndChannel;
+
+ return m_Client->Respond(-215, "e");
+
+ case EndChannel:
+ if (m_Schedules != NULL) {
+ m_Schedule = m_Schedules->Next(m_Schedule);
+ if (m_Schedule != NULL) {
+ if (m_Schedule->Events() != NULL)
+ m_Event = m_Schedule->Events()->First();
+ m_State = Channel;
+ }
+ }
+
+ if (m_Schedules == NULL || m_Schedule == NULL)
+ m_State = EndEPG;
+
+ return m_Client->Respond(-215, "c");
+
+ case EndEPG:
+ Last = true;
+ return m_Client->Respond(215, "End of EPG data");
+ }
+ return false;
+}
+
+// --- cLSTCHandler -----------------------------------------------------------
+
+class cLSTCHandler
+{
+private:
+ cConnectionVTP *m_Client;
+ const cChannel *m_Channel;
+ char *m_Option;
+ int m_Errno;
+ cString m_Error;
+ bool m_Traverse;
+public:
+ cLSTCHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTCHandler();
+ bool Next(bool &Last);
+};
+
+cLSTCHandler::cLSTCHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_Channel(NULL),
+ m_Option(NULL),
+ m_Errno(0),
+ m_Traverse(false)
+{
+ if (!Channels.Lock(false, 500)) {
+ m_Errno = 451;
+ m_Error = "Channels are being modified - try again";
+ } else if (*Option) {
+ if (isnumber(Option)) {
+ m_Channel = Channels.GetByNumber(strtol(Option, NULL, 10));
+ if (m_Channel == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Channel \"%s\" not defined", Option);
+ return;
+ }
+ } else {
+ int i = 1;
+ m_Traverse = true;
+ m_Option = strdup(Option);
+ while (i <= Channels.MaxNumber()) {
+ m_Channel = Channels.GetByNumber(i, 1);
+ if (strcasestr(m_Channel->Name(), Option) != NULL)
+ break;
+ i = m_Channel->Number() + 1;
+ }
+
+ if (i > Channels.MaxNumber()) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Channel \"%s\" not defined", Option);
+ return;
+ }
+ }
+ } else if (Channels.MaxNumber() >= 1) {
+ m_Channel = Channels.GetByNumber(1, 1);
+ m_Traverse = true;
+ } else {
+ m_Errno = 550;
+ m_Error = "No channels defined";
+ }
+}
+
+cLSTCHandler::~cLSTCHandler()
+{
+ Channels.Unlock();
+ if (m_Option != NULL)
+ free(m_Option);
+}
+
+bool cLSTCHandler::Next(bool &Last)
+{
+ if (*m_Error != NULL) {
+ Last = true;
+ cString str(m_Error);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, "%s", *str);
+ }
+
+ int number;
+ char *buffer;
+
+ number = m_Channel->Number();
+ buffer = strdup(*m_Channel->ToText());
+ buffer[strlen(buffer) - 1] = '\0'; // remove \n
+ cString str(buffer, true);
+
+ Last = true;
+ if (m_Traverse) {
+ int i = m_Channel->Number() + 1;
+ while (i <= Channels.MaxNumber()) {
+ m_Channel = Channels.GetByNumber(i, 1);
+ if (m_Channel != NULL) {
+ if (m_Option == NULL || strcasestr(m_Channel->Name(),
+ m_Option) != NULL)
+ break;
+ i = m_Channel->Number() + 1;
+ } else {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Channel \"%d\" not found", i);
+ }
+ }
+
+ if (i < Channels.MaxNumber() + 1)
+ Last = false;
+ }
+
+ return m_Client->Respond(Last ? 250 : -250, "%d %s", number, buffer);
+}
+
+// --- cLSTTHandler -----------------------------------------------------------
+
+class cLSTTHandler
+{
+private:
+ cConnectionVTP *m_Client;
+ cTimer *m_Timer;
+ int m_Index;
+ int m_Errno;
+ cString m_Error;
+ bool m_Traverse;
+public:
+ cLSTTHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTTHandler();
+ bool Next(bool &Last);
+};
+
+cLSTTHandler::cLSTTHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_Timer(NULL),
+ m_Index(0),
+ m_Errno(0),
+ m_Traverse(false)
+{
+ if (*Option) {
+ if (isnumber(Option)) {
+ m_Timer = Timers.Get(strtol(Option, NULL, 10) - 1);
+ if (m_Timer == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Timer \"%s\" not defined", Option);
+ }
+ } else {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Error in timer number \"%s\"", Option);
+ }
+ } else if (Timers.Count()) {
+ m_Traverse = true;
+ m_Index = 0;
+ m_Timer = Timers.Get(m_Index);
+ if (m_Timer == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1);
+ }
+ } else {
+ m_Errno = 550;
+ m_Error = "No timers defined";
+ }
+}
+
+cLSTTHandler::~cLSTTHandler()
+{
+}
+
+bool cLSTTHandler::Next(bool &Last)
+{
+ if (*m_Error != NULL) {
+ Last = true;
+ cString str(m_Error);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, "%s", *str);
+ }
+
+ bool result;
+ char *buffer;
+ Last = !m_Traverse || m_Index >= Timers.Count() - 1;
+ buffer = strdup(*m_Timer->ToText());
+ buffer[strlen(buffer) - 1] = '\0'; // strip \n
+ result = m_Client->Respond(Last ? 250 : -250, "%d %s", m_Timer->Index() + 1,
+ buffer);
+ free(buffer);
+
+ if (m_Traverse && !Last) {
+ m_Timer = Timers.Get(++m_Index);
+ if (m_Timer == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Timer \"%d\" not found", m_Index + 1);
+ }
+ }
+ return result;
+}
+
+// --- cLSTRHandler -----------------------------------------------------------
+
+class cLSTRHandler
+{
+private:
+ enum eStates { Recording, Event, Title, Subtitle, Description, Components, Vps,
+ EndRecording };
+ cConnectionVTP *m_Client;
+ cRecording *m_Recording;
+ const cEvent *m_Event;
+ int m_Index;
+ int m_Errno;
+ cString m_Error;
+ bool m_Traverse;
+ bool m_Info;
+ eStates m_State;
+ int m_CurrentComponent;
+public:
+ cLSTRHandler(cConnectionVTP *Client, const char *Option);
+ ~cLSTRHandler();
+ bool Next(bool &Last);
+};
+
+cLSTRHandler::cLSTRHandler(cConnectionVTP *Client, const char *Option):
+ m_Client(Client),
+ m_Recording(NULL),
+ m_Event(NULL),
+ m_Index(0),
+ m_Errno(0),
+ m_Traverse(false),
+ m_Info(false),
+ m_State(Recording),
+ m_CurrentComponent(0)
+{
+ if (*Option) {
+ if (isnumber(Option)) {
+ m_Recording = Recordings.Get(strtol(Option, NULL, 10) - 1);
+#if defined(USE_STREAMDEVEXT) || APIVERSNUM >= 10705
+ m_Event = m_Recording->Info()->GetEvent();
+#endif
+ m_Info = true;
+ if (m_Recording == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Recording \"%s\" not found", Option);
+ }
+ }
+ else {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Error in Recording number \"%s\"", Option);
+ }
+ }
+ else if (Recordings.Count()) {
+ m_Traverse = true;
+ m_Index = 0;
+ m_Recording = Recordings.Get(m_Index);
+ if (m_Recording == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1);
+ }
+ }
+ else {
+ m_Errno = 550;
+ m_Error = "No recordings available";
+ }
+}
+
+cLSTRHandler::~cLSTRHandler()
+{
+}
+
+bool cLSTRHandler::Next(bool &Last)
+{
+ if (*m_Error != NULL) {
+ Last = true;
+ cString str(m_Error);
+ m_Error = NULL;
+ return m_Client->Respond(m_Errno, "%s", *str);
+ }
+
+ if (m_Info) {
+ Last = false;
+ switch (m_State) {
+ case Recording:
+ if (m_Recording != NULL) {
+ m_State = Event;
+ return m_Client->Respond(-215, "C %s%s%s",
+ *m_Recording->Info()->ChannelID().ToString(),
+ m_Recording->Info()->ChannelName() ? " " : "",
+ m_Recording->Info()->ChannelName() ? m_Recording->Info()->ChannelName() : "");
+ }
+ else {
+ m_State = EndRecording;
+ return Next(Last);
+ }
+ break;
+
+ case Event:
+ m_State = Title;
+ if (m_Event != NULL) {
+ return m_Client->Respond(-215, "E %u %ld %d %X %X", (unsigned int) m_Event->EventID(),
+ m_Event->StartTime(), m_Event->Duration(),
+ m_Event->TableID(), m_Event->Version());
+ }
+ return Next(Last);
+
+ case Title:
+ m_State = Subtitle;
+ return m_Client->Respond(-215, "T %s", m_Recording->Info()->Title());
+
+ case Subtitle:
+ m_State = Description;
+ if (!isempty(m_Recording->Info()->ShortText())) {
+ return m_Client->Respond(-215, "S %s", m_Recording->Info()->ShortText());
+ }
+ return Next(Last);
+
+ case Description:
+ m_State = Components;
+ if (!isempty(m_Recording->Info()->Description())) {
+ m_State = Components;
+ char *copy = strdup(m_Recording->Info()->Description());
+ cString cpy(copy, true);
+ strreplace(copy, '\n', '|');
+ return m_Client->Respond(-215, "D %s", copy);
+ }
+ return Next(Last);
+
+ case Components:
+ if (m_Recording->Info()->Components()) {
+ if (m_CurrentComponent < m_Recording->Info()->Components()->NumComponents()) {
+ tComponent *p = m_Recording->Info()->Components()->Component(m_CurrentComponent);
+ m_CurrentComponent++;
+ if (!Setup.UseDolbyDigital && p->stream == 0x02 && p->type == 0x05)
+ return Next(Last);
+
+ return m_Client->Respond(-215, "X %s", *p->ToString());
+ }
+ }
+ m_State = Vps;
+ return Next(Last);
+
+ case Vps:
+ m_State = EndRecording;
+ if (m_Event != NULL) {
+ if (m_Event->Vps()) {
+ return m_Client->Respond(-215, "V %ld", m_Event->Vps());
+ }
+ }
+ return Next(Last);
+
+ case EndRecording:
+ Last = true;
+ return m_Client->Respond(215, "End of recording information");
+ }
+ }
+ else {
+ bool result;
+ Last = !m_Traverse || m_Index >= Recordings.Count() - 1;
+ result = m_Client->Respond(Last ? 250 : -250, "%d %s", m_Recording->Index() + 1, m_Recording->Title(' ', true));
+
+ if (m_Traverse && !Last) {
+ m_Recording = Recordings.Get(++m_Index);
+ if (m_Recording == NULL) {
+ m_Errno = 501;
+ m_Error = cString::sprintf("Recording \"%d\" not found", m_Index + 1);
+ }
+ }
+ return result;
+ }
+ return false;
+}
+
+// --- cConnectionVTP ---------------------------------------------------------
+
+cConnectionVTP::cConnectionVTP(void):
+ cServerConnection("VTP"),
+ m_LiveSocket(NULL),
+ m_LiveStreamer(NULL),
+ m_FilterSocket(NULL),
+ m_FilterStreamer(NULL),
+ m_RecSocket(NULL),
+ m_DataSocket(NULL),
+ m_LastCommand(NULL),
+ m_StreamType(stTSPIDS),
+ m_FiltersSupport(false),
+ m_RecPlayer(NULL),
+ m_LSTEHandler(NULL),
+ m_LSTCHandler(NULL),
+ m_LSTTHandler(NULL),
+ m_LSTRHandler(NULL)
+{
+}
+
+cConnectionVTP::~cConnectionVTP()
+{
+ if (m_LastCommand != NULL)
+ free(m_LastCommand);
+ delete m_LiveStreamer;
+ delete m_LiveSocket;
+ delete m_RecSocket;
+ delete m_FilterStreamer;
+ delete m_FilterSocket;
+ delete m_DataSocket;
+ delete m_LSTTHandler;
+ delete m_LSTCHandler;
+ delete m_LSTEHandler;
+ delete m_LSTRHandler;
+ delete m_RecPlayer;
+}
+
+inline bool cConnectionVTP::Abort(void) const
+{
+ return m_LiveStreamer && m_LiveStreamer->Abort();
+}
+
+void cConnectionVTP::Welcome(void)
+{
+ Respond(220, "Welcome to Video Disk Recorder (VTP)");
+}
+
+void cConnectionVTP::Reject(void)
+{
+ Respond(221, "Too many clients or client not allowed to connect");
+ cServerConnection::Reject();
+}
+
+void cConnectionVTP::Detach(void)
+{
+ if (m_LiveStreamer) m_LiveStreamer->Detach();
+ if (m_FilterStreamer) m_FilterStreamer->Detach();
+}
+
+void cConnectionVTP::Attach(void)
+{
+ if (m_LiveStreamer) m_LiveStreamer->Attach();
+ if (m_FilterStreamer) m_FilterStreamer->Attach();
+}
+
+bool cConnectionVTP::Command(char *Cmd)
+{
+ char *param = NULL;
+
+ if (Cmd != NULL) {
+ if (m_LastCommand != NULL) {
+ esyslog("ERROR: streamdev: protocol violation (VTP) from %s:%d",
+ RemoteIp().c_str(), RemotePort());
+ return false;
+ }
+
+ if ((param = strchr(Cmd, ' ')) != NULL)
+ *(param++) = '\0';
+ else
+ param = Cmd + strlen(Cmd);
+ m_LastCommand = strdup(Cmd);
+ } else {
+ Cmd = m_LastCommand;
+ param = NULL;
+ }
+
+ if (strcasecmp(Cmd, "LSTE") == 0) return CmdLSTE(param);
+ else if (strcasecmp(Cmd, "LSTR") == 0) return CmdLSTR(param);
+ else if (strcasecmp(Cmd, "LSTT") == 0) return CmdLSTT(param);
+ else if (strcasecmp(Cmd, "LSTC") == 0) return CmdLSTC(param);
+
+ if (param == NULL) {
+ esyslog("ERROR: streamdev: this seriously shouldn't happen at %s:%d",
+ __FILE__, __LINE__);
+ return false;
+ }
+
+ if (strcasecmp(Cmd, "CAPS") == 0) return CmdCAPS(param);
+ else if (strcasecmp(Cmd, "PROV") == 0) return CmdPROV(param);
+ else if (strcasecmp(Cmd, "PORT") == 0) return CmdPORT(param);
+ else if (strcasecmp(Cmd, "READ") == 0) return CmdREAD(param);
+ else if (strcasecmp(Cmd, "TUNE") == 0) return CmdTUNE(param);
+ else if (strcasecmp(Cmd, "PLAY") == 0) return CmdPLAY(param);
+ else if (strcasecmp(Cmd, "ADDP") == 0) return CmdADDP(param);
+ else if (strcasecmp(Cmd, "DELP") == 0) return CmdDELP(param);
+ else if (strcasecmp(Cmd, "ADDF") == 0) return CmdADDF(param);
+ else if (strcasecmp(Cmd, "DELF") == 0) return CmdDELF(param);
+ else if (strcasecmp(Cmd, "ABRT") == 0) return CmdABRT(param);
+ else if (strcasecmp(Cmd, "QUIT") == 0) return CmdQUIT();
+ else if (strcasecmp(Cmd, "SUSP") == 0) return CmdSUSP();
+ // Commands adopted from SVDRP
+ else if (strcasecmp(Cmd, "STAT") == 0) return CmdSTAT(param);
+ else if (strcasecmp(Cmd, "MODT") == 0) return CmdMODT(param);
+ else if (strcasecmp(Cmd, "NEWT") == 0) return CmdNEWT(param);
+ else if (strcasecmp(Cmd, "DELT") == 0) return CmdDELT(param);
+ else if (strcasecmp(Cmd, "NEXT") == 0) return CmdNEXT(param);
+ else if (strcasecmp(Cmd, "NEWC") == 0) return CmdNEWC(param);
+ else if (strcasecmp(Cmd, "MODC") == 0) return CmdMODC(param);
+ else if (strcasecmp(Cmd, "MOVC") == 0) return CmdMOVC(param);
+ else if (strcasecmp(Cmd, "DELC") == 0) return CmdDELC(param);
+ else if (strcasecmp(Cmd, "DELR") == 0) return CmdDELR(param);
+ else if (strcasecmp(Cmd, "RENR") == 0) return CmdRENR(param);
+ else
+ return Respond(500, "Unknown Command \"%s\"", Cmd);
+}
+
+bool cConnectionVTP::CmdCAPS(char *Opts)
+{
+ if (strcasecmp(Opts, "TS") == 0) {
+ m_StreamType = stTS;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ if (strcasecmp(Opts, "TSPIDS") == 0) {
+ m_StreamType = stTSPIDS;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ if (strcasecmp(Opts, "PS") == 0) {
+ m_StreamType = stPS;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ if (strcasecmp(Opts, "PES") == 0) {
+ m_StreamType = stPES;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ if (strcasecmp(Opts, "EXTERN") == 0) {
+ m_StreamType = stExtern;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ //
+ // Deliver section filters data in separate, channel-independent data stream
+ //
+ if (strcasecmp(Opts, "FILTERS") == 0) {
+ m_FiltersSupport = true;
+ return Respond(220, "Capability \"%s\" accepted", Opts);
+ }
+
+ return Respond(561, "Capability \"%s\" not known", Opts);
+}
+
+bool cConnectionVTP::CmdPROV(char *Opts)
+{
+ const cChannel *chan;
+ int prio;
+ char *ep;
+
+ prio = strtol(Opts, &ep, 10);
+ if (ep == Opts || !isspace(*ep))
+ return Respond(501, "Use: PROV Priority Channel");
+
+ Opts = skipspace(ep);
+ if ((chan = ChannelFromString(Opts)) == NULL)
+ return Respond(550, "Undefined channel \"%s\"", Opts);
+
+ return GetDevice(chan, prio) != NULL
+ ? Respond(220, "Channel available")
+ : Respond(560, "Channel not available");
+}
+
+bool cConnectionVTP::CmdPORT(char *Opts)
+{
+ uint id, dataport = 0;
+ char dataip[20];
+ char *ep, *ipoffs;
+ int n;
+
+ id = strtoul(Opts, &ep, 10);
+ if (ep == Opts || !isspace(*ep))
+ return Respond(500, "Use: PORT Id Destination");
+
+ if (id >= si_Count)
+ return Respond(501, "Wrong connection id %d", id);
+
+ Opts = skipspace(ep);
+ n = 0;
+ ipoffs = dataip;
+ while ((ep = strchr(Opts, ',')) != NULL) {
+ if (n < 4) {
+ memcpy(ipoffs, Opts, ep - Opts);
+ ipoffs += ep - Opts;
+ if (n < 3) *(ipoffs++) = '.';
+ } else if (n == 4) {
+ *ep = 0;
+ dataport = strtoul(Opts, NULL, 10) << 8;
+ } else
+ break;
+ Opts = ep + 1;
+ ++n;
+ }
+ *ipoffs = '\0';
+
+ if (n != 5)
+ return Respond(501, "Argument count invalid (must be 6 values)");
+
+ dataport |= strtoul(Opts, NULL, 10);
+
+ isyslog("Streamdev: Setting data connection to %s:%d", dataip, dataport);
+
+ switch (id) {
+ case siLiveFilter:
+ m_FiltersSupport = true;
+ if(m_FilterStreamer)
+ m_FilterStreamer->Stop();
+ delete m_FilterSocket;
+
+ m_FilterSocket = new cTBSocket(SOCK_STREAM);
+ if (!m_FilterSocket->Connect(dataip, dataport)) {
+ esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
+ dataip, dataport, strerror(errno));
+ DELETENULL(m_FilterSocket);
+ return Respond(551, "Couldn't open data connection");
+ }
+
+ if(!m_FilterStreamer)
+ m_FilterStreamer = new cStreamdevFilterStreamer;
+ m_FilterStreamer->Start(m_FilterSocket);
+ m_FilterStreamer->Activate(true);
+
+ return Respond(220, "Port command ok, data connection opened");
+ break;
+
+ case siLive:
+ if(m_LiveSocket && m_LiveStreamer)
+ m_LiveStreamer->Stop();
+ delete m_LiveSocket;
+
+ m_LiveSocket = new cTBSocket(SOCK_STREAM);
+ if (!m_LiveSocket->Connect(dataip, dataport)) {
+ esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
+ dataip, dataport, strerror(errno));
+ DELETENULL(m_LiveSocket);
+ return Respond(551, "Couldn't open data connection");
+ }
+
+ if (!m_LiveSocket->SetDSCP())
+ LOG_ERROR_STR("unable to set DSCP sockopt");
+ if (m_LiveStreamer)
+ m_LiveStreamer->Start(m_LiveSocket);
+
+ return Respond(220, "Port command ok, data connection opened");
+ break;
+
+ case siReplay:
+ delete m_RecSocket;
+
+ m_RecSocket = new cTBSocket(SOCK_STREAM);
+ if (!m_RecSocket->Connect(dataip, dataport)) {
+ esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
+ dataip, dataport, strerror(errno));
+ DELETENULL(m_RecSocket);
+ return Respond(551, "Couldn't open data connection");
+ }
+
+ if (!m_RecSocket->SetDSCP())
+ LOG_ERROR_STR("unable to set DSCP sockopt");
+
+ return Respond(220, "Port command ok, data connection opened");
+ break;
+
+ case siDataRespond:
+ delete m_DataSocket;
+
+ m_DataSocket = new cTBSocket(SOCK_STREAM);
+ if (!m_DataSocket->Connect(dataip, dataport)) {
+ esyslog("ERROR: Streamdev: Couldn't open data connection to %s:%d: %s",
+ dataip, dataport, strerror(errno));
+ DELETENULL(m_DataSocket);
+ return Respond(551, "Couldn't open data connection");
+ }
+ return Respond(220, "Port command ok, data connection opened");
+ break;
+
+ default:
+ return Respond(501, "No handler for id %u", id);
+ }
+}
+
+bool cConnectionVTP::CmdREAD(char *Opts)
+{
+ if (*Opts) {
+ char *tail;
+ uint64_t position = strtoll(Opts, &tail, 10);
+ if (tail && tail != Opts) {
+ tail = skipspace(tail);
+ if (tail && tail != Opts) {
+ int size = strtol(tail, NULL, 10);
+ uint8_t* data = (uint8_t*)malloc(size+4);
+ unsigned long count_readed = m_RecPlayer->getBlock(data, position, size);
+ unsigned long count_written = m_RecSocket->SysWrite(data, count_readed);
+
+ free(data);
+ return Respond(220, "%lu Bytes submitted", count_written);
+ }
+ else {
+ return Respond(501, "Missing position");
+ }
+ }
+ else {
+ return Respond(501, "Missing size");
+ }
+ }
+ else {
+ return Respond(501, "Missing position");
+ }
+}
+
+bool cConnectionVTP::CmdTUNE(char *Opts)
+{
+ const cChannel *chan;
+ cDevice *dev;
+
+ if ((chan = ChannelFromString(Opts)) == NULL)
+ return Respond(550, "Undefined channel \"%s\"", Opts);
+
+ if ((dev = GetDevice(chan, 0)) == NULL)
+ return Respond(560, "Channel not available");
+
+ if (!dev->SwitchChannel(chan, false))
+ return Respond(560, "Channel not available");
+
+ delete m_LiveStreamer;
+ m_LiveStreamer = new cStreamdevLiveStreamer(1);
+ m_LiveStreamer->SetChannel(chan, m_StreamType);
+ m_LiveStreamer->SetDevice(dev);
+ if(m_LiveSocket)
+ m_LiveStreamer->Start(m_LiveSocket);
+
+ if(m_FiltersSupport) {
+ if(!m_FilterStreamer)
+ m_FilterStreamer = new cStreamdevFilterStreamer;
+ m_FilterStreamer->SetDevice(dev);
+ //m_FilterStreamer->SetChannel(chan);
+ }
+
+ return Respond(220, "Channel tuned");
+}
+
+bool cConnectionVTP::CmdPLAY(char *Opts)
+{
+ if (*Opts) {
+ if (isnumber(Opts)) {
+ cRecording *recording = Recordings.Get(strtol(Opts, NULL, 10) - 1);
+ if (recording) {
+ if (m_RecPlayer) {
+ delete m_RecPlayer;
+ }
+ m_RecPlayer = new RecPlayer(recording);
+ return Respond(220, "%llu (Bytes), %u (Frames)", (long long unsigned int) m_RecPlayer->getLengthBytes(), (unsigned int) m_RecPlayer->getLengthFrames());
+ }
+ else {
+ return Respond(550, "Recording \"%s\" not found", Opts);
+ }
+ }
+ else {
+ return Respond(500, "Use: PLAY record");
+ }
+ }
+ else {
+ return Respond(500, "Use: PLAY record");
+ }
+}
+
+bool cConnectionVTP::CmdADDP(char *Opts)
+{
+ int pid;
+ char *end;
+
+ pid = strtoul(Opts, &end, 10);
+ if (end == Opts || (*end != '\0' && *end != ' '))
+ return Respond(500, "Use: ADDP Pid");
+
+ return m_LiveStreamer && m_LiveStreamer->SetPid(pid, true)
+ ? Respond(220, "Pid %d available", pid)
+ : Respond(560, "Pid %d not available", pid);
+}
+
+bool cConnectionVTP::CmdDELP(char *Opts)
+{
+ int pid;
+ char *end;
+
+ pid = strtoul(Opts, &end, 10);
+ if (end == Opts || (*end != '\0' && *end != ' '))
+ return Respond(500, "Use: DELP Pid");
+
+ return m_LiveStreamer && m_LiveStreamer->SetPid(pid, false)
+ ? Respond(220, "Pid %d stopped", pid)
+ : Respond(560, "Pid %d not transferring", pid);
+}
+
+bool cConnectionVTP::CmdADDF(char *Opts)
+{
+ int pid, tid, mask;
+ char *ep;
+
+ if (m_FilterStreamer == NULL)
+ return Respond(560, "Can't set filters without a filter stream");
+
+ pid = strtol(Opts, &ep, 10);
+ if (ep == Opts || (*ep != ' '))
+ return Respond(500, "Use: ADDF Pid Tid Mask");
+ Opts = skipspace(ep);
+ tid = strtol(Opts, &ep, 10);
+ if (ep == Opts || (*ep != ' '))
+ return Respond(500, "Use: ADDF Pid Tid Mask");
+ Opts = skipspace(ep);
+ mask = strtol(Opts, &ep, 10);
+ if (ep == Opts || (*ep != '\0' && *ep != ' '))
+ return Respond(500, "Use: ADDF Pid Tid Mask");
+
+ return m_FilterStreamer->SetFilter(pid, tid, mask, true)
+ ? Respond(220, "Filter %d transferring", pid)
+ : Respond(560, "Filter %d not available", pid);
+}
+
+bool cConnectionVTP::CmdDELF(char *Opts)
+{
+ int pid, tid, mask;
+ char *ep;
+
+ if (m_FilterStreamer == NULL)
+ return Respond(560, "Can't delete filters without a stream");
+
+ pid = strtol(Opts, &ep, 10);
+ if (ep == Opts || (*ep != ' '))
+ return Respond(500, "Use: DELF Pid Tid Mask");
+ Opts = skipspace(ep);
+ tid = strtol(Opts, &ep, 10);
+ if (ep == Opts || (*ep != ' '))
+ return Respond(500, "Use: DELF Pid Tid Mask");
+ Opts = skipspace(ep);
+ mask = strtol(Opts, &ep, 10);
+ if (ep == Opts || (*ep != '\0' && *ep != ' '))
+ return Respond(500, "Use: DELF Pid Tid Mask");
+
+ m_FilterStreamer->SetFilter(pid, tid, mask, false);
+ return Respond(220, "Filter %d stopped", pid);
+}
+
+bool cConnectionVTP::CmdABRT(char *Opts)
+{
+ uint id;
+ char *ep;
+
+ id = strtoul(Opts, &ep, 10);
+ if (ep == Opts || (*ep != '\0' && *ep != ' '))
+ return Respond(500, "Use: ABRT Id");
+
+ switch (id) {
+ case siLive:
+ DELETENULL(m_LiveStreamer);
+ DELETENULL(m_LiveSocket);
+ break;
+ case siLiveFilter:
+ DELETENULL(m_FilterStreamer);
+ DELETENULL(m_FilterSocket);
+ break;
+ case siReplay:
+ DELETENULL(m_RecPlayer);
+ DELETENULL(m_RecSocket);
+ break;
+ case siDataRespond:
+ DELETENULL(m_DataSocket);
+ break;
+ default:
+ return Respond(501, "Wrong connection id %d", id);
+ break;
+
+ }
+
+ return Respond(220, "Data connection closed");
+}
+
+bool cConnectionVTP::CmdQUIT(void)
+{
+ DeferClose();
+ return Respond(221, "Video Disk Recorder closing connection");
+}
+
+bool cConnectionVTP::CmdSUSP(void)
+{
+ if (StreamdevServerSetup.SuspendMode == smAlways || cSuspendCtl::IsActive())
+ return Respond(220, "Server is suspended");
+ else if (StreamdevServerSetup.SuspendMode == smOffer
+ && StreamdevServerSetup.AllowSuspend) {
+ cControl::Launch(new cSuspendCtl);
+ return Respond(220, "Server is suspended");
+ } else
+ return Respond(550, "Client may not suspend server");
+}
+
+// Functions extended from SVDRP
+
+template<class cHandler>
+bool cConnectionVTP::CmdLSTX(cHandler *&Handler, char *Option)
+{
+ if (Option != NULL) {
+ delete Handler;
+ Handler = new cHandler(this, Option);
+ }
+
+ bool last = false;
+ bool result = false;
+ if (Handler != NULL)
+ result = Handler->Next(last);
+ else
+ esyslog("ERROR: vdr streamdev: Handler in LSTX command is NULL");
+ if (!result || last)
+ DELETENULL(Handler);
+
+ return result;
+}
+
+bool cConnectionVTP::CmdLSTE(char *Option)
+{
+ return CmdLSTX(m_LSTEHandler, Option);
+}
+
+bool cConnectionVTP::CmdLSTC(char *Option)
+{
+ return CmdLSTX(m_LSTCHandler, Option);
+}
+
+bool cConnectionVTP::CmdLSTT(char *Option)
+{
+ return CmdLSTX(m_LSTTHandler, Option);
+}
+
+bool cConnectionVTP::CmdLSTR(char *Option)
+{
+ return CmdLSTX(m_LSTRHandler, Option);
+}
+
+// Functions adopted from SVDRP
+#define INIT_WRAPPER() bool _res
+#define Reply(c,m...) _res = Respond(c,m)
+#define EXIT_WRAPPER() return _res
+
+bool cConnectionVTP::CmdSTAT(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ if (strcasecmp(Option, "DISK") == 0) {
+ int FreeMB, UsedMB;
+ int Percent = VideoDiskSpace(&FreeMB, &UsedMB);
+ Reply(250, "%dMB %dMB %d%%", FreeMB + UsedMB, FreeMB, Percent);
+ }
+ else if (strcasecmp(Option, "NAME") == 0) {
+ Reply(250, "vdr - The Video Disk Recorder with Streamdev-Server");
+ }
+ else if (strcasecmp(Option, "VERSION") == 0) {
+ Reply(250, "VDR: %s | Streamdev: %s", VDRVERSION, VERSION);
+ }
+ else if (strcasecmp(Option, "RECORDS") == 0) {
+ bool recordings = Recordings.Load();
+ Recordings.Sort();
+ if (recordings) {
+ cRecording *recording = Recordings.Last();
+ Reply(250, "%d", recording->Index() + 1);
+ }
+ else {
+ Reply(250, "0");
+ }
+ }
+ else if (strcasecmp(Option, "CHANNELS") == 0) {
+ Reply(250, "%d", Channels.MaxNumber());
+ }
+ else if (strcasecmp(Option, "TIMERS") == 0) {
+ Reply(250, "%d", Timers.Count());
+ }
+ else if (strcasecmp(Option, "CHARSET") == 0) {
+ Reply(250, "%s", cCharSetConv::SystemCharacterTable());
+ }
+ else if (strcasecmp(Option, "TIME") == 0) {
+ time_t timeNow = time(NULL);
+ struct tm* timeStruct = localtime(&timeNow);
+ int timeOffset = timeStruct->tm_gmtoff;
+
+ Reply(250, "%lu %i", (unsigned long) timeNow, timeOffset);
+ }
+ else
+ Reply(501, "Invalid Option \"%s\"", Option);
+ }
+ else
+ Reply(501, "No option given");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdMODT(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ char *tail;
+ int n = strtol(Option, &tail, 10);
+ if (tail && tail != Option) {
+ tail = skipspace(tail);
+ cTimer *timer = Timers.Get(n - 1);
+ if (timer) {
+ cTimer t = *timer;
+ if (strcasecmp(tail, "ON") == 0)
+ t.SetFlags(tfActive);
+ else if (strcasecmp(tail, "OFF") == 0)
+ t.ClrFlags(tfActive);
+ else if (!t.Parse(tail)) {
+ Reply(501, "Error in timer settings");
+ EXIT_WRAPPER();
+ }
+ *timer = t;
+ Timers.SetModified();
+ isyslog("timer %s modified (%s)", *timer->ToDescr(),
+ timer->HasFlags(tfActive) ? "active" : "inactive");
+ Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
+ } else
+ Reply(501, "Timer \"%d\" not defined", n);
+ } else
+ Reply(501, "Error in timer number");
+ } else
+ Reply(501, "Missing timer settings");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdNEWT(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ cTimer *timer = new cTimer;
+ if (timer->Parse(Option)) {
+ cTimer *t = Timers.GetTimer(timer);
+ if (!t) {
+ Timers.Add(timer);
+ Timers.SetModified();
+ isyslog("timer %s added", *timer->ToDescr());
+ Reply(250, "%d %s", timer->Index() + 1, *timer->ToText());
+ EXIT_WRAPPER();
+ } else
+ Reply(550, "Timer already defined: %d %s", t->Index() + 1,
+ *t->ToText());
+ } else
+ Reply(501, "Error in timer settings");
+ delete timer;
+ } else
+ Reply(501, "Missing timer settings");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdDELT(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ int number = 0;
+ bool force = false;
+ char buf[strlen(Option) + 1];
+ strcpy(buf, Option);
+ const char *delim = " \t";
+ char *strtok_next;
+ char *p = strtok_r(buf, delim, &strtok_next);
+
+ if (isnumber(p)) {
+ number = strtol(p, NULL, 10) - 1;
+ }
+ else if (strcasecmp(p, "FORCE") == 0) {
+ force = true;
+ }
+ if ((p = strtok_r(NULL, delim, &strtok_next)) != NULL) {
+ if (isnumber(p)) {
+ number = strtol(p, NULL, 10) - 1;
+ }
+ else if (strcasecmp(p, "FORCE") == 0) {
+ force = true;
+ }
+ else {
+ Reply(501, "Timer not found or wrong syntax");
+ }
+ }
+
+ cTimer *timer = Timers.Get(number);
+ if (timer) {
+ if (timer->Recording()) {
+ if (force) {
+ timer->Skip();
+ cRecordControls::Process(time(NULL));
+ }
+ else {
+ Reply(550, "Timer \"%i\" is recording", number);
+ EXIT_WRAPPER();
+ }
+ }
+ isyslog("deleting timer %s", *timer->ToDescr());
+ Timers.Del(timer);
+ Timers.SetModified();
+ Reply(250, "Timer \"%i\" deleted", number);
+ } else
+ Reply(501, "Timer \"%i\" not defined", number);
+ } else
+ Reply(501, "Missing timer option");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdNEXT(const char *Option)
+{
+ INIT_WRAPPER();
+ cTimer *t = Timers.GetNextActiveTimer();
+ if (t) {
+ time_t Start = t->StartTime();
+ int Number = t->Index() + 1;
+ if (!*Option)
+ Reply(250, "%d %s", Number, *TimeToString(Start));
+ else if (strcasecmp(Option, "ABS") == 0)
+ Reply(250, "%d %ld", Number, Start);
+ else if (strcasecmp(Option, "REL") == 0)
+ Reply(250, "%d %ld", Number, Start - time(NULL));
+ else
+ Reply(501, "Unknown option: \"%s\"", Option);
+ }
+ else
+ Reply(550, "No active timers");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdNEWC(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ cChannel ch;
+ if (ch.Parse(Option)) {
+ if (Channels.HasUniqueChannelID(&ch)) {
+ cChannel *channel = new cChannel;
+ *channel = ch;
+ Channels.Add(channel);
+ Channels.ReNumber();
+ Channels.SetModified(true);
+ isyslog("new channel %d %s", channel->Number(), *channel->ToText());
+ Reply(250, "%d %s", channel->Number(), *channel->ToText());
+ }
+ else {
+ Reply(501, "Channel settings are not unique");
+ }
+ }
+ else {
+ Reply(501, "Error in channel settings");
+ }
+ }
+ else {
+ Reply(501, "Missing channel settings");
+ }
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdMODC(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ char *tail;
+ int n = strtol(Option, &tail, 10);
+ if (tail && tail != Option) {
+ tail = skipspace(tail);
+ if (!Channels.BeingEdited()) {
+ cChannel *channel = Channels.GetByNumber(n);
+ if (channel) {
+ cChannel ch;
+ if (ch.Parse(tail)) {
+ if (Channels.HasUniqueChannelID(&ch, channel)) {
+ *channel = ch;
+ Channels.ReNumber();
+ Channels.SetModified(true);
+ isyslog("modifed channel %d %s", channel->Number(), *channel->ToText());
+ Reply(250, "%d %s", channel->Number(), *channel->ToText());
+ }
+ else {
+ Reply(501, "Channel settings are not unique");
+ }
+ }
+ else {
+ Reply(501, "Error in channel settings");
+ }
+ }
+ else {
+ Reply(501, "Channel \"%d\" not defined", n);
+ }
+ }
+ else {
+ Reply(550, "Channels are being edited - try again later");
+ }
+ }
+ else {
+ Reply(501, "Error in channel number");
+ }
+ }
+ else {
+ Reply(501, "Missing channel settings");
+ }
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdMOVC(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ if (!Channels.BeingEdited() && !Timers.BeingEdited()) {
+ char *tail;
+ int From = strtol(Option, &tail, 10);
+ if (tail && tail != Option) {
+ tail = skipspace(tail);
+ if (tail && tail != Option) {
+ int To = strtol(tail, NULL, 10);
+ int CurrentChannelNr = cDevice::CurrentChannel();
+ cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr);
+ cChannel *FromChannel = Channels.GetByNumber(From);
+ if (FromChannel) {
+ cChannel *ToChannel = Channels.GetByNumber(To);
+ if (ToChannel) {
+ int FromNumber = FromChannel->Number();
+ int ToNumber = ToChannel->Number();
+ if (FromNumber != ToNumber) {
+ Channels.Move(FromChannel, ToChannel);
+ Channels.ReNumber();
+ Channels.SetModified(true);
+ if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
+ if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring()) {
+ Channels.SwitchTo(CurrentChannel->Number());
+ }
+ else {
+ cDevice::SetCurrentChannel(CurrentChannel);
+ }
+ }
+ isyslog("channel %d moved to %d", FromNumber, ToNumber);
+ Reply(250,"Channel \"%d\" moved to \"%d\"", From, To);
+ }
+ else {
+ Reply(501, "Can't move channel to same postion");
+ }
+ }
+ else {
+ Reply(501, "Channel \"%d\" not defined", To);
+ }
+ }
+ else {
+ Reply(501, "Channel \"%d\" not defined", From);
+ }
+ }
+ else {
+ Reply(501, "Error in channel number");
+ }
+ }
+ else {
+ Reply(501, "Error in channel number");
+ }
+ }
+ else {
+ Reply(550, "Channels or timers are being edited - try again later");
+ }
+ }
+ else {
+ Reply(501, "Missing channel number");
+ }
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdDELC(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ if (isnumber(Option)) {
+ if (!Channels.BeingEdited()) {
+ cChannel *channel = Channels.GetByNumber(strtol(Option, NULL, 10));
+ if (channel) {
+ for (cTimer *timer = Timers.First(); timer; timer = Timers.Next(timer)) {
+ if (timer->Channel() == channel) {
+ Reply(550, "Channel \"%s\" is in use by timer %d", Option, timer->Index() + 1);
+ return false;
+ }
+ }
+ int CurrentChannelNr = cDevice::CurrentChannel();
+ cChannel *CurrentChannel = Channels.GetByNumber(CurrentChannelNr);
+ if (CurrentChannel && channel == CurrentChannel) {
+ int n = Channels.GetNextNormal(CurrentChannel->Index());
+ if (n < 0)
+ n = Channels.GetPrevNormal(CurrentChannel->Index());
+ CurrentChannel = Channels.Get(n);
+ CurrentChannelNr = 0; // triggers channel switch below
+ }
+ Channels.Del(channel);
+ Channels.ReNumber();
+ Channels.SetModified(true);
+ isyslog("channel %s deleted", Option);
+ if (CurrentChannel && CurrentChannel->Number() != CurrentChannelNr) {
+ if (!cDevice::PrimaryDevice()->Replaying() || cDevice::PrimaryDevice()->Transferring())
+ Channels.SwitchTo(CurrentChannel->Number());
+ else
+ cDevice::SetCurrentChannel(CurrentChannel);
+ }
+ Reply(250, "Channel \"%s\" deleted", Option);
+ }
+ else
+ Reply(501, "Channel \"%s\" not defined", Option);
+ }
+ else
+ Reply(550, "Channels are being edited - try again later");
+ }
+ else
+ Reply(501, "Error in channel number \"%s\"", Option);
+ }
+ else {
+ Reply(501, "Missing channel number");
+ }
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdDELR(const char *Option)
+{
+ INIT_WRAPPER();
+ if (*Option) {
+ if (isnumber(Option)) {
+ cRecording *recording = Recordings.Get(strtol(Option, NULL, 10) - 1);
+ if (recording) {
+ cRecordControl *rc = cRecordControls::GetRecordControl(recording->FileName());
+ if (!rc) {
+ if (recording->Delete()) {
+ Reply(250, "Recording \"%s\" deleted", Option);
+ ::Recordings.DelByName(recording->FileName());
+ }
+ else
+ Reply(554, "Error while deleting recording!");
+ }
+ else
+ Reply(550, "Recording \"%s\" is in use by timer %d", Option, rc->Timer()->Index() + 1);
+ }
+ else
+ Reply(550, "Recording \"%s\" not found%s", Option, Recordings.Count() ? "" : " (use LSTR before deleting)");
+ }
+ else
+ Reply(501, "Error in recording number \"%s\"", Option);
+ }
+ else
+ Reply(501, "Missing recording number");
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::CmdRENR(const char *Option)
+{
+ INIT_WRAPPER();
+#if defined(LIEMIKUUTIO)
+ bool recordings = Recordings.Update(true);
+ if (recordings) {
+ if (*Option) {
+ char *tail;
+ int n = strtol(Option, &tail, 10);
+ cRecording *recording = Recordings.Get(n - 1);
+ if (recording && tail && tail != Option) {
+#if APIVERSNUM < 10704
+ int priority = recording->priority;
+ int lifetime = recording->lifetime;
+#endif
+ char *oldName = strdup(recording->Name());
+ tail = skipspace(tail);
+#if APIVERSNUM < 10704
+ if (recording->Rename(tail, &priority, &lifetime)) {
+#else
+ if (recording->Rename(tail)) {
+#endif
+ Reply(250, "Renamed \"%s\" to \"%s\"", oldName, recording->Name());
+ Recordings.ChangeState();
+ Recordings.TouchUpdate();
+ }
+ else {
+ Reply(501, "Renaming \"%s\" to \"%s\" failed", oldName, tail);
+ }
+ free(oldName);
+ }
+ else {
+ Reply(501, "Recording not found or wrong syntax");
+ }
+ }
+ else {
+ Reply(501, "Missing Input settings");
+ }
+ }
+ else {
+ Reply(550, "No recordings available");
+ }
+#else
+ Reply(501, "Rename not supported, please use LIEMIEXT");
+#endif /* LIEMIKUUTIO */
+ EXIT_WRAPPER();
+}
+
+bool cConnectionVTP::Respond(int Code, const char *Message, ...)
+{
+ va_list ap;
+ va_start(ap, Message);
+#if APIVERSNUM < 10515
+ char *buffer;
+ if (vasprintf(&buffer, Message, ap) < 0)
+ buffer = strdup("???");
+ cString str(buffer, true);
+#else
+ cString str = cString::sprintf(Message, ap);
+#endif
+ va_end(ap);
+
+ if (Code >= 0 && m_LastCommand != NULL) {
+ free(m_LastCommand);
+ m_LastCommand = NULL;
+ }
+
+ return cServerConnection::Respond("%03d%c%s", Code >= 0,
+ Code < 0 ? -Code : Code,
+ Code < 0 ? '-' : ' ', *str);
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/connectionVTP.h b/plugins/streamdev/streamdev-cvs/server/connectionVTP.h
new file mode 100644
index 0000000..b938fe6
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/connectionVTP.h
@@ -0,0 +1,93 @@
+#ifndef VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
+#define VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
+
+#include "server/connection.h"
+#include "server/recplayer.h"
+
+class cTBSocket;
+class cStreamdevLiveStreamer;
+class cStreamdevFilterStreamer;
+class cLSTEHandler;
+class cLSTCHandler;
+class cLSTTHandler;
+class cLSTRHandler;
+
+class cConnectionVTP: public cServerConnection {
+ friend class cLSTEHandler;
+#if !defined __GNUC__ || __GNUC__ >= 3
+ using cServerConnection::Respond;
+#endif
+
+private:
+ cTBSocket *m_LiveSocket;
+ cStreamdevLiveStreamer *m_LiveStreamer;
+ cTBSocket *m_FilterSocket;
+ cStreamdevFilterStreamer *m_FilterStreamer;
+ cTBSocket *m_RecSocket;
+ cTBSocket *m_DataSocket;
+
+ char *m_LastCommand;
+ eStreamType m_StreamType;
+ bool m_FiltersSupport;
+ RecPlayer *m_RecPlayer;
+
+ // Members adopted for SVDRP
+ cLSTEHandler *m_LSTEHandler;
+ cLSTCHandler *m_LSTCHandler;
+ cLSTTHandler *m_LSTTHandler;
+ cLSTRHandler *m_LSTRHandler;
+
+protected:
+ template<class cHandler>
+ bool CmdLSTX(cHandler *&Handler, char *Option);
+
+public:
+ cConnectionVTP(void);
+ virtual ~cConnectionVTP();
+
+ virtual void Welcome(void);
+ virtual void Reject(void);
+
+ virtual bool Abort(void) const;
+ virtual void Detach(void);
+ virtual void Attach(void);
+
+ virtual bool Command(char *Cmd);
+ bool CmdCAPS(char *Opts);
+ bool CmdPROV(char *Opts);
+ bool CmdPORT(char *Opts);
+ bool CmdREAD(char *Opts);
+ bool CmdTUNE(char *Opts);
+ bool CmdPLAY(char *Opts);
+ bool CmdADDP(char *Opts);
+ bool CmdDELP(char *Opts);
+ bool CmdADDF(char *Opts);
+ bool CmdDELF(char *Opts);
+ bool CmdABRT(char *Opts);
+ bool CmdQUIT(void);
+ bool CmdSUSP(void);
+
+ // Thread-safe implementations of SVDRP commands
+ bool CmdLSTE(char *Opts);
+ bool CmdLSTC(char *Opts);
+ bool CmdLSTT(char *Opts);
+ bool CmdLSTR(char *Opts);
+
+ // Commands adopted from SVDRP
+ bool CmdSTAT(const char *Option);
+ bool CmdMODT(const char *Option);
+ bool CmdNEWT(const char *Option);
+ bool CmdDELT(const char *Option);
+ bool CmdNEXT(const char *Option);
+ bool CmdNEWC(const char *Option);
+ bool CmdMODC(const char *Option);
+ bool CmdMOVC(const char *Option);
+ bool CmdDELC(const char *Option);
+ bool CmdDELR(const char *Option);
+ bool CmdRENR(const char *Option);
+
+ bool Respond(int Code, const char *Message, ...)
+ __attribute__ ((format (printf, 3, 4)));
+};
+
+#endif // VDR_STREAMDEV_SERVERS_CONNECTIONVTP_H
diff --git a/plugins/streamdev/streamdev-cvs/server/http/CVS/Entries b/plugins/streamdev/streamdev-cvs/server/http/CVS/Entries
new file mode 100644
index 0000000..1784810
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/http/CVS/Entries
@@ -0,0 +1 @@
+D
diff --git a/plugins/streamdev/streamdev-cvs/server/http/CVS/Repository b/plugins/streamdev/streamdev-cvs/server/http/CVS/Repository
new file mode 100644
index 0000000..49fadb8
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/http/CVS/Repository
@@ -0,0 +1 @@
+streamdev/server/http
diff --git a/plugins/streamdev/streamdev-cvs/server/http/CVS/Root b/plugins/streamdev/streamdev-cvs/server/http/CVS/Root
new file mode 100644
index 0000000..2c7f6ce
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/http/CVS/Root
@@ -0,0 +1 @@
+:pserver:anoncvs@vdr-developer.org:/var/cvsroot
diff --git a/plugins/streamdev/streamdev-cvs/server/livefilter.c b/plugins/streamdev/streamdev-cvs/server/livefilter.c
new file mode 100644
index 0000000..67b0e37
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/livefilter.c
@@ -0,0 +1,39 @@
+/*
+ * $Id: livefilter.c,v 1.7 2009/02/13 13:02:40 schmirl Exp $
+ */
+
+#include "server/livefilter.h"
+#include "server/streamer.h"
+#include "common.h"
+
+#ifndef TS_SYNC_BYTE
+# define TS_SYNC_BYTE 0x47
+#endif
+
+cStreamdevLiveFilter::cStreamdevLiveFilter(cStreamdevStreamer *Streamer) {
+ m_Streamer = Streamer;
+}
+
+void cStreamdevLiveFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
+{
+ uchar buffer[TS_SIZE];
+ int length = Length;
+ int pos = 0;
+
+ while (length > 0) {
+ int chunk = min(length, TS_SIZE - 5);
+ buffer[0] = TS_SYNC_BYTE;
+ buffer[1] = ((Pid >> 8) & 0x3f) | (pos==0 ? 0x40 : 0); /* bit 6: payload unit start indicator (PUSI) */
+ buffer[2] = Pid & 0xff;
+ buffer[3] = Tid;
+ // this makes it a proprietary stream
+ buffer[4] = (uchar)chunk;
+ memcpy(buffer + 5, Data + pos, chunk);
+ length -= chunk;
+ pos += chunk;
+
+ int p = m_Streamer->Put(buffer, TS_SIZE);
+ if (p != TS_SIZE)
+ m_Streamer->ReportOverflow(TS_SIZE - p);
+ }
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/livefilter.h b/plugins/streamdev/streamdev-cvs/server/livefilter.h
new file mode 100644
index 0000000..13e8956
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/livefilter.h
@@ -0,0 +1,32 @@
+/*
+ * $Id: livefilter.h,v 1.5 2008/04/07 14:27:31 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMEV_LIVEFILTER_H
+#define VDR_STREAMEV_LIVEFILTER_H
+
+#include <vdr/config.h>
+
+#include <vdr/filter.h>
+
+class cStreamdevStreamer;
+
+class cStreamdevLiveFilter: public cFilter {
+private:
+ cStreamdevStreamer *m_Streamer;
+
+protected:
+ virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
+
+public:
+ cStreamdevLiveFilter(cStreamdevStreamer *Streamer);
+
+ void Set(u_short Pid, u_char Tid, u_char Mask) {
+ cFilter::Set(Pid, Tid, Mask);
+ }
+ void Del(u_short Pid, u_char Tid, u_char Mask) {
+ cFilter::Del(Pid, Tid, Mask);
+ }
+};
+
+#endif // VDR_STREAMEV_LIVEFILTER_H
diff --git a/plugins/streamdev/streamdev-cvs/server/livestreamer.c b/plugins/streamdev/streamdev-cvs/server/livestreamer.c
new file mode 100644
index 0000000..3162fa2
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/livestreamer.c
@@ -0,0 +1,689 @@
+#include <assert.h>
+
+#include <libsi/section.h>
+#include <libsi/descriptor.h>
+
+#include "remux/ts2ps.h"
+#include "remux/ts2pes.h"
+#include "remux/ts2es.h"
+#include "remux/extern.h"
+
+#include <vdr/ringbuffer.h>
+
+#include "server/livestreamer.h"
+#include "server/livefilter.h"
+#include "common.h"
+
+using namespace Streamdev;
+
+// --- cStreamdevLiveReceiver -------------------------------------------------
+
+class cStreamdevLiveReceiver: public cReceiver {
+ friend class cStreamdevStreamer;
+
+private:
+ cStreamdevStreamer *m_Streamer;
+
+protected:
+ virtual void Activate(bool On);
+ virtual void Receive(uchar *Data, int Length);
+
+public:
+ cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID, int Priority, const int *Pids);
+ virtual ~cStreamdevLiveReceiver();
+};
+
+cStreamdevLiveReceiver::cStreamdevLiveReceiver(cStreamdevStreamer *Streamer, tChannelID ChannelID,
+ int Priority, const int *Pids):
+ cReceiver(ChannelID, Priority, 0, Pids),
+ m_Streamer(Streamer)
+{
+}
+
+cStreamdevLiveReceiver::~cStreamdevLiveReceiver()
+{
+ Dprintf("Killing live receiver\n");
+ Detach();
+}
+
+void cStreamdevLiveReceiver::Receive(uchar *Data, int Length) {
+ int p = m_Streamer->Receive(Data, Length);
+ if (p != Length)
+ m_Streamer->ReportOverflow(Length - p);
+}
+
+inline void cStreamdevLiveReceiver::Activate(bool On)
+{
+ Dprintf("LiveReceiver->Activate(%d)\n", On);
+ m_Streamer->Activate(On);
+}
+
+// --- cStreamdevPatFilter ----------------------------------------------------
+
+class cStreamdevPatFilter : public cFilter {
+private:
+ int pmtPid;
+ int pmtSid;
+ int pmtVersion;
+ uchar tspat_buf[TS_SIZE];
+ cStreamdevBuffer siBuffer;
+
+ const cChannel *m_Channel;
+ cStreamdevLiveStreamer *m_Streamer;
+
+ virtual void Process(u_short Pid, u_char Tid, const u_char *Data, int Length);
+
+ int GetPid(SI::PMT::Stream& stream);
+public:
+ cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel);
+ uchar* Get(int &Count) { return siBuffer.Get(Count); }
+ void Del(int Count) { return siBuffer.Del(Count); }
+};
+
+cStreamdevPatFilter::cStreamdevPatFilter(cStreamdevLiveStreamer *Streamer, const cChannel *Channel): siBuffer(10 * TS_SIZE, TS_SIZE)
+{
+ Dprintf("cStreamdevPatFilter(\"%s\")\n", Channel->Name());
+ assert(Streamer);
+ m_Channel = Channel;
+ m_Streamer = Streamer;
+ pmtPid = 0;
+ pmtSid = 0;
+ pmtVersion = -1;
+ Set(0x00, 0x00); // PAT
+ // initialize PAT buffer. Only some values are dynamic (see comments)
+ memset(tspat_buf, 0xff, TS_SIZE);
+ tspat_buf[0] = TS_SYNC_BYTE; // Transport packet header sunchronization byte (1000011 = 0x47h)
+ tspat_buf[1] = 0x40; // Set payload unit start indicator bit
+ tspat_buf[2] = 0x0; // PID
+ tspat_buf[3] = 0x10; // Set payload flag, DYNAMIC: Continuity counter
+ tspat_buf[4] = 0x0; // SI pointer field
+ tspat_buf[5] = 0x0; // PAT table id
+ tspat_buf[6] = 0xb0; // Section syntax indicator bit and reserved bits set
+ tspat_buf[7] = 12 + 1; // Section length (12 bit): PAT_TABLE_LEN + 1
+ tspat_buf[8] = 0; // DYNAMIC: Transport stream ID (bits 8-15)
+ tspat_buf[9] = 0; // DYNAMIC: Transport stream ID (bits 0-7)
+ tspat_buf[10] = 0xc0; // Reserved, DYNAMIC: Version number, DYNAMIC: Current next indicator
+ tspat_buf[11] = 0x0; // Section number
+ tspat_buf[12] = 0x0; // Last section number
+ tspat_buf[13] = 0; // DYNAMIC: Program number (bits 8-15)
+ tspat_buf[14] = 0; // DYNAMIC: Program number (bits 0-7)
+ tspat_buf[15] = 0xe0; // Reserved, DYNAMIC: Network ID (bits 8-12)
+ tspat_buf[16] = 0; // DYNAMIC: Network ID (bits 0-7)
+ tspat_buf[17] = 0; // DYNAMIC: Checksum
+ tspat_buf[18] = 0; // DYNAMIC: Checksum
+ tspat_buf[19] = 0; // DYNAMIC: Checksum
+ tspat_buf[20] = 0; // DYNAMIC: Checksum
+}
+
+static const char * const psStreamTypes[] = {
+ "UNKNOWN",
+ "ISO/IEC 11172 Video",
+ "ISO/IEC 13818-2 Video",
+ "ISO/IEC 11172 Audio",
+ "ISO/IEC 13818-3 Audio",
+ "ISO/IEC 13818-1 Privete sections",
+ "ISO/IEC 13818-1 Private PES data",
+ "ISO/IEC 13512 MHEG",
+ "ISO/IEC 13818-1 Annex A DSM CC",
+ "0x09",
+ "ISO/IEC 13818-6 Multiprotocol encapsulation",
+ "ISO/IEC 13818-6 DSM-CC U-N Messages",
+ "ISO/IEC 13818-6 Stream Descriptors",
+ "ISO/IEC 13818-6 Sections (any type, including private data)",
+ "ISO/IEC 13818-1 auxiliary",
+ "ISO/IEC 13818-7 Audio with ADTS transport sytax",
+ "ISO/IEC 14496-2 Visual (MPEG-4)",
+ "ISO/IEC 14496-3 Audio with LATM transport syntax",
+ "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a",
+ "ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)",
+ "",
+};
+
+int cStreamdevPatFilter::GetPid(SI::PMT::Stream& stream)
+{
+ SI::Descriptor *d;
+
+ if (!stream.getPid())
+ return 0;
+
+ switch (stream.getStreamType()) {
+ case 0x01: // ISO/IEC 11172 Video
+ case 0x02: // ISO/IEC 13818-2 Video
+ case 0x03: // ISO/IEC 11172 Audio
+ case 0x04: // ISO/IEC 13818-3 Audio
+#if 0
+ case 0x07: // ISO/IEC 13512 MHEG
+ case 0x08: // ISO/IEC 13818-1 Annex A DSM CC
+ case 0x0a: // ISO/IEC 13818-6 Multiprotocol encapsulation
+ case 0x0b: // ISO/IEC 13818-6 DSM-CC U-N Messages
+ case 0x0c: // ISO/IEC 13818-6 Stream Descriptors
+ case 0x0d: // ISO/IEC 13818-6 Sections (any type, including private data)
+ case 0x0e: // ISO/IEC 13818-1 auxiliary
+#endif
+ case 0x0f: // ISO/IEC 13818-7 Audio with ADTS transport syntax
+ case 0x10: // ISO/IEC 14496-2 Visual (MPEG-4)
+ case 0x11: // ISO/IEC 14496-3 Audio with LATM transport syntax
+ case 0x1b: // ISO/IEC 14496-10 Video (MPEG-4 part 10/AVC, aka H.264)
+ Dprintf("cStreamdevPatFilter PMT scanner adding PID %d (%s)\n",
+ stream.getPid(), psStreamTypes[stream.getStreamType()]);
+ return stream.getPid();
+ case 0x05: // ISO/IEC 13818-1 private sections
+ case 0x06: // ISO/IEC 13818-1 PES packets containing private data
+ for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+ switch (d->getDescriptorTag()) {
+ case SI::AC3DescriptorTag:
+ Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
+ stream.getPid(), psStreamTypes[stream.getStreamType()], "AC3");
+ delete d;
+ return stream.getPid();
+ case SI::TeletextDescriptorTag:
+ Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
+ stream.getPid(), psStreamTypes[stream.getStreamType()], "Teletext");
+ delete d;
+ return stream.getPid();
+ case SI::SubtitlingDescriptorTag:
+ Dprintf("cStreamdevPatFilter PMT scanner: adding PID %d (%s) %s\n",
+ stream.getPid(), psStreamTypes[stream.getStreamType()], "DVBSUB");
+ delete d;
+ return stream.getPid();
+ default:
+ Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n",
+ stream.getPid(), psStreamTypes[stream.getStreamType()], "UNKNOWN");
+ break;
+ }
+ delete d;
+ }
+ break;
+ default:
+ /* This following section handles all the cases where the audio track
+ * info is stored in PMT user info with stream id >= 0x80
+ * we check the registration format identifier to see if it
+ * holds "AC-3"
+ */
+ if (stream.getStreamType() >= 0x80) {
+ bool found = false;
+ for (SI::Loop::Iterator it; (d = stream.streamDescriptors.getNext(it)); ) {
+ switch (d->getDescriptorTag()) {
+ case SI::RegistrationDescriptorTag:
+ /* unfortunately libsi does not implement RegistrationDescriptor */
+ if (d->getLength() >= 4) {
+ found = true;
+ SI::CharArray rawdata = d->getData();
+ if (/*rawdata[0] == 5 && rawdata[1] >= 4 && */
+ rawdata[2] == 'A' && rawdata[3] == 'C' &&
+ rawdata[4] == '-' && rawdata[5] == '3') {
+ isyslog("cStreamdevPatFilter PMT scanner:"
+ "Adding pid %d (type 0x%x) RegDesc len %d (%c%c%c%c)",
+ stream.getPid(), stream.getStreamType(),
+ d->getLength(), rawdata[2], rawdata[3],
+ rawdata[4], rawdata[5]);
+ delete d;
+ return stream.getPid();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ delete d;
+ }
+ if(!found) {
+ isyslog("Adding pid %d (type 0x%x) RegDesc not found -> assume AC-3",
+ stream.getPid(), stream.getStreamType());
+ return stream.getPid();
+ }
+ }
+ Dprintf("cStreamdevPatFilter PMT scanner: NOT adding PID %d (%s) %s\n",
+ stream.getPid(), psStreamTypes[stream.getStreamType()<0x1c?stream.getStreamType():0], "UNKNOWN");
+ break;
+ }
+ return 0;
+}
+
+void cStreamdevPatFilter::Process(u_short Pid, u_char Tid, const u_char *Data, int Length)
+{
+ if (Pid == 0x00) {
+ if (Tid == 0x00) {
+ SI::PAT pat(Data, false);
+ if (!pat.CheckCRCAndParse())
+ return;
+ SI::PAT::Association assoc;
+ for (SI::Loop::Iterator it; pat.associationLoop.getNext(assoc, it); ) {
+ if (!assoc.isNITPid()) {
+ const cChannel *Channel = Channels.GetByServiceID(Source(), Transponder(), assoc.getServiceId());
+ if (Channel && (Channel == m_Channel)) {
+ int prevPmtPid = pmtPid;
+ if (0 != (pmtPid = assoc.getPid())) {
+ Dprintf("cStreamdevPatFilter: PMT pid for channel %s: %d\n", Channel->Name(), pmtPid);
+ pmtSid = assoc.getServiceId();
+ // repack PAT to TS frame and send to client
+ int ts_id;
+ unsigned int crc, i, len;
+ uint8_t *tmp;
+ static uint8_t ccounter = 0;
+ ccounter = (ccounter + 1) % 16;
+ ts_id = Channel->Tid(); // Get transport stream id of the channel
+ tspat_buf[3] = 0x10 | ccounter; // Set payload flag, Continuity counter
+ tspat_buf[8] = (ts_id >> 8); // Transport stream ID (bits 8-15)
+ tspat_buf[9] = (ts_id & 0xff); // Transport stream ID (bits 0-7)
+ tspat_buf[10] = 0xc0 | ((pat.getVersionNumber() << 1) & 0x3e) |
+ pat.getCurrentNextIndicator();// Version number, Current next indicator
+ tspat_buf[13] = (pmtSid >> 8); // Program number (bits 8-15)
+ tspat_buf[14] = (pmtSid & 0xff); // Program number (bits 0-7)
+ tspat_buf[15] = 0xe0 | (pmtPid >> 8); // Network ID (bits 8-12)
+ tspat_buf[16] = (pmtPid & 0xff); // Network ID (bits 0-7)
+ crc = 0xffffffff;
+ len = 12; // PAT_TABLE_LEN
+ tmp = &tspat_buf[4 + 1]; // TS_HDR_LEN + 1
+ while (len--) {
+ crc ^= *tmp++ << 24;
+ for (i = 0; i < 8; i++)
+ crc = (crc << 1) ^ ((crc & 0x80000000) ? 0x04c11db7 : 0); // CRC32POLY
+ }
+ tspat_buf[17] = crc >> 24 & 0xff; // Checksum
+ tspat_buf[18] = crc >> 16 & 0xff; // Checksum
+ tspat_buf[19] = crc >> 8 & 0xff; // Checksum
+ tspat_buf[20] = crc & 0xff; // Checksum
+ int written = siBuffer.PutTS(tspat_buf, TS_SIZE);
+ if (written != TS_SIZE)
+ siBuffer.ReportOverflow(TS_SIZE - written);
+ if (pmtPid != prevPmtPid) {
+ m_Streamer->SetPids(pmtPid);
+ Add(pmtPid, 0x02);
+ pmtVersion = -1;
+ }
+ return;
+ }
+ }
+ }
+ }
+ }
+ } else if (Pid == pmtPid && Tid == SI::TableIdPMT && Source() && Transponder()) {
+ SI::PMT pmt(Data, false);
+ if (!pmt.CheckCRCAndParse())
+ return;
+ if (pmt.getServiceId() != pmtSid)
+ return; // skip broken PMT records
+ if (pmtVersion != -1) {
+ if (pmtVersion != pmt.getVersionNumber()) {
+ Dprintf("cStreamdevPatFilter: PMT version changed, detaching all pids\n");
+ cFilter::Del(pmtPid, 0x02);
+ pmtPid = 0; // this triggers PAT scan
+ }
+ return;
+ }
+ pmtVersion = pmt.getVersionNumber();
+
+ SI::PMT::Stream stream;
+ int pids[MAXRECEIVEPIDS + 1], npids = 0;
+ pids[npids++] = pmtPid;
+#if 0
+ pids[npids++] = 0x10; // pid 0x10, tid 0x40: NIT
+ pids[npids++] = 0x11; // pid 0x11, tid 0x42: SDT
+ pids[npids++] = 0x14; // pid 0x14, tid 0x70: TDT
+#endif
+ pids[npids++] = 0x12; // pid 0x12, tid 0x4E...0x6F: EIT
+ for (SI::Loop::Iterator it; pmt.streamLoop.getNext(stream, it); )
+ if (0 != (pids[npids] = GetPid(stream)) && npids < MAXRECEIVEPIDS)
+ npids++;
+
+ pids[npids] = 0;
+ m_Streamer->SetPids(pmt.getPCRPid(), pids);
+ }
+}
+
+// --- cStreamdevLiveStreamer -------------------------------------------------
+
+cStreamdevLiveStreamer::cStreamdevLiveStreamer(int Priority, std::string Parameter):
+ cStreamdevStreamer("streamdev-livestreaming"),
+ m_Priority(Priority),
+ m_Parameter(Parameter),
+ m_NumPids(0),
+ m_StreamType(stTSPIDS),
+ m_Channel(NULL),
+ m_Device(NULL),
+ m_Receiver(NULL),
+ m_PatFilter(NULL),
+ m_Remux(NULL)
+{
+}
+
+cStreamdevLiveStreamer::~cStreamdevLiveStreamer()
+{
+ Dprintf("Desctructing Live streamer\n");
+ Stop();
+ if(m_PatFilter) {
+ Detach();
+ DELETENULL(m_PatFilter);
+ }
+ DELETENULL(m_Receiver);
+ delete m_Remux;
+}
+
+bool cStreamdevLiveStreamer::HasPid(int Pid)
+{
+ int idx;
+ for (idx = 0; idx < m_NumPids; ++idx)
+ if (m_Pids[idx] == Pid)
+ return true;
+ return false;
+}
+
+bool cStreamdevLiveStreamer::SetPid(int Pid, bool On)
+{
+ int idx;
+
+ if (Pid == 0)
+ return true;
+
+ if (On) {
+ for (idx = 0; idx < m_NumPids; ++idx) {
+ if (m_Pids[idx] == Pid)
+ return true; // No change needed
+ }
+
+ if (m_NumPids == MAXRECEIVEPIDS) {
+ esyslog("ERROR: Streamdev: No free slot to receive pid %d\n", Pid);
+ return false;
+ }
+
+ m_Pids[m_NumPids++] = Pid;
+ m_Pids[m_NumPids] = 0;
+ } else {
+ for (idx = 0; idx < m_NumPids; ++idx) {
+ if (m_Pids[idx] == Pid) {
+ --m_NumPids;
+ memmove(&m_Pids[idx], &m_Pids[idx + 1], sizeof(int) * (m_NumPids - idx));
+ }
+ }
+ }
+
+ StartReceiver();
+ return true;
+}
+
+bool cStreamdevLiveStreamer::SetPids(int Pid, const int *Pids1, const int *Pids2, const int *Pids3)
+{
+ m_NumPids = 0;
+
+ if (Pid)
+ m_Pids[m_NumPids++] = Pid;
+
+ if (Pids1)
+ for ( ; *Pids1 && m_NumPids < MAXRECEIVEPIDS; Pids1++)
+ if (!HasPid(*Pids1))
+ m_Pids[m_NumPids++] = *Pids1;
+
+ if (Pids2)
+ for ( ; *Pids2 && m_NumPids < MAXRECEIVEPIDS; Pids2++)
+ if (!HasPid(*Pids2))
+ m_Pids[m_NumPids++] = *Pids2;
+
+ if (Pids3)
+ for ( ; *Pids3 && m_NumPids < MAXRECEIVEPIDS; Pids3++)
+ if (!HasPid(*Pids3))
+ m_Pids[m_NumPids++] = *Pids3;
+
+ if (m_NumPids >= MAXRECEIVEPIDS) {
+ esyslog("ERROR: Streamdev: No free slot to receive pid %d\n", Pid);
+ return false;
+ }
+
+ m_Pids[m_NumPids] = 0;
+ StartReceiver();
+ return true;
+}
+
+void cStreamdevLiveStreamer::StartReceiver(void)
+{
+ DELETENULL(m_Receiver);
+ if (m_NumPids > 0) {
+ Dprintf("Creating Receiver to respect changed pids\n");
+ m_Receiver = new cStreamdevLiveReceiver(this, m_Channel->GetChannelID(), m_Priority, m_Pids);
+ if (IsRunning() && m_Device != NULL) {
+ Dprintf("Attaching new receiver\n");
+ Attach();
+ }
+ }
+}
+
+bool cStreamdevLiveStreamer::SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid)
+{
+ Dprintf("Initializing Remuxer for full channel transfer\n");
+ //printf("ca pid: %d\n", Channel->Ca());
+ m_Channel = Channel;
+ m_StreamType = StreamType;
+
+ int apid[2] = { Apid, 0 };
+ const int *Apids = Apid ? apid : m_Channel->Apids();
+ const int *Dpids = Apid ? NULL : m_Channel->Dpids();
+
+ switch (m_StreamType) {
+ case stES:
+ {
+ int pid = ISRADIO(m_Channel) ? m_Channel->Apid(0) : m_Channel->Vpid();
+ if (Apid != 0)
+ pid = Apid;
+ m_Remux = new cTS2ESRemux(pid);
+ return SetPids(pid);
+ }
+
+ case stPES:
+ m_Remux = new cTS2PESRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
+ m_Channel->Spids());
+ return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
+
+ case stPS:
+ m_Remux = new cTS2PSRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
+ m_Channel->Spids());
+ return SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
+
+ case stExtern:
+ m_Remux = new cExternRemux(m_Channel->Vpid(), m_Channel->Apids(), m_Channel->Dpids(),
+ m_Channel->Spids(), m_Parameter);
+ // fall through
+ case stTS:
+ // This should never happen, but ...
+ if (m_PatFilter) {
+ Detach();
+ DELETENULL(m_PatFilter);
+ }
+ // Set pids from cChannel
+ SetPids(m_Channel->Vpid(), Apids, Dpids, m_Channel->Spids());
+ if (m_Channel->Vpid() != m_Channel->Ppid())
+ SetPid(m_Channel->Ppid(), true);
+ // Set pids from PMT
+ m_PatFilter = new cStreamdevPatFilter(this, m_Channel);
+ return true;
+
+ case stTSPIDS:
+ Dprintf("pid streaming mode\n");
+ return true;
+ default:
+ return false;
+ }
+}
+
+int cStreamdevLiveStreamer::Put(const uchar *Data, int Count)
+{
+ // insert si data
+ if (m_PatFilter) {
+ int siCount;
+ uchar *siData = m_PatFilter->Get(siCount);
+ if (siData) {
+ if (m_Remux)
+ siCount = m_Remux->Put(siData, siCount);
+ else
+ siCount = cStreamdevStreamer::Put(siData, siCount);
+ if (siCount)
+ m_PatFilter->Del(siCount);
+ }
+ }
+ if (m_Remux)
+ return m_Remux->Put(Data, Count);
+ else
+ return cStreamdevStreamer::Put(Data, Count);
+}
+
+uchar *cStreamdevLiveStreamer::Get(int &Count)
+{
+ if (m_Remux)
+ return m_Remux->Get(Count);
+ else
+ return cStreamdevStreamer::Get(Count);
+}
+
+void cStreamdevLiveStreamer::Del(int Count)
+{
+ if (m_Remux)
+ m_Remux->Del(Count);
+ else
+ cStreamdevStreamer::Del(Count);
+}
+
+void cStreamdevLiveStreamer::Attach(void)
+{
+ Dprintf("cStreamdevLiveStreamer::Attach()\n");
+ if (m_Device) {
+ if (m_Receiver) {
+ m_Device->Detach(m_Receiver);
+ m_Device->AttachReceiver(m_Receiver);
+ }
+ if (m_PatFilter) {
+ m_Device->Detach(m_PatFilter);
+ m_Device->AttachFilter(m_PatFilter);
+ }
+ }
+}
+
+void cStreamdevLiveStreamer::Detach(void)
+{
+ Dprintf("cStreamdevLiveStreamer::Detach()\n");
+ if (m_Device) {
+ if (m_Receiver)
+ m_Device->Detach(m_Receiver);
+ if (m_PatFilter)
+ m_Device->Detach(m_PatFilter);
+ }
+}
+
+std::string cStreamdevLiveStreamer::Report(void)
+{
+ std::string result;
+
+ if (m_Device != NULL)
+ result += (std::string)"+- Device is " + (const char*)itoa(m_Device->CardIndex()) + "\n";
+ if (m_Receiver != NULL)
+ result += "+- Receiver is allocated\n";
+
+ result += "+- Pids are ";
+ for (int i = 0; i < MAXRECEIVEPIDS; ++i)
+ if (m_Pids[i] != 0)
+ result += (std::string)(const char*)itoa(m_Pids[i]) + ", ";
+ result += "\n";
+ return result;
+}
+
+// --- cStreamdevFilterStreamer -------------------------------------------------
+
+cStreamdevFilterStreamer::cStreamdevFilterStreamer():
+ cStreamdevStreamer("streamdev-filterstreaming"),
+ m_Device(NULL),
+ m_Filter(NULL)/*,
+ m_Channel(NULL)*/
+{
+}
+
+cStreamdevFilterStreamer::~cStreamdevFilterStreamer()
+{
+ Dprintf("Desctructing Filter streamer\n");
+ Detach();
+ m_Device = NULL;
+ DELETENULL(m_Filter);
+ Stop();
+}
+
+void cStreamdevFilterStreamer::Attach(void)
+{
+ Dprintf("cStreamdevFilterStreamer::Attach()\n");
+ LOCK_THREAD;
+ if(m_Device && m_Filter)
+ m_Device->AttachFilter(m_Filter);
+}
+
+void cStreamdevFilterStreamer::Detach(void)
+{
+ Dprintf("cStreamdevFilterStreamer::Detach()\n");
+ LOCK_THREAD;
+ if(m_Device && m_Filter)
+ m_Device->Detach(m_Filter);
+}
+
+#if 0
+void cStreamdevFilterStreamer::SetChannel(const cChannel *Channel)
+{
+ LOCK_THREAD;
+ Dprintf("cStreamdevFilterStreamer::SetChannel(%s : %s)", Channel?Channel->Name():"<null>",
+ Channel ? *Channel->GetChannelID().ToString() : "");
+ m_Channel = Channel;
+}
+#endif
+
+void cStreamdevFilterStreamer::SetDevice(cDevice *Device)
+{
+ Dprintf("cStreamdevFilterStreamer::SetDevice()\n");
+ LOCK_THREAD;
+ if(Device != m_Device) {
+ Detach();
+ m_Device = Device;
+ //m_Channel = NULL;
+ Attach();
+ }
+}
+
+bool cStreamdevFilterStreamer::SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On)
+{
+ Dprintf("cStreamdevFilterStreamer::SetFilter(%u,0x%x,0x%x,%s)\n", Pid, Tid, Mask, On?"On":"Off");
+
+ if(!m_Device)
+ return false;
+
+ if (On) {
+ if (m_Filter == NULL) {
+ m_Filter = new cStreamdevLiveFilter(this);
+ Dprintf("attaching filter to device\n");
+ Attach();
+ }
+ m_Filter->Set(Pid, Tid, Mask);
+ } else if (m_Filter != NULL)
+ m_Filter->Del(Pid, Tid, Mask);
+
+ return true;
+}
+
+#if 0
+void cStreamdevFilterStreamer::ChannelSwitch(const cDevice *Device, int ChannelNumber) {
+ LOCK_THREAD;
+ if(Device == m_Device) {
+ if(ChannelNumber > 0) {
+ cChannel *ch = Channels.GetByNumber(ChannelNumber);
+ if(ch != NULL) {
+ if(m_Filter != NULL &&
+ m_Channel != NULL &&
+ (! TRANSPONDER(ch, m_Channel))) {
+
+ isyslog("***** LiveFilterStreamer: transponder changed ! %s",
+ *ch->GetChannelID().ToString());
+
+ uchar buffer[TS_SIZE] = {TS_SYNC_BYTE, 0xff, 0xff, 0xff, 0x7f, 0};
+ strcpy((char*)(buffer + 5), ch->GetChannelID().ToString());
+ int p = Put(buffer, TS_SIZE);
+ if (p != TS_SIZE)
+ ReportOverflow(TS_SIZE - p);
+ }
+ m_Channel = ch;
+ }
+ }
+ }
+}
+#endif
diff --git a/plugins/streamdev/streamdev-cvs/server/livestreamer.h b/plugins/streamdev/streamdev-cvs/server/livestreamer.h
new file mode 100644
index 0000000..92448bb
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/livestreamer.h
@@ -0,0 +1,82 @@
+#ifndef VDR_STREAMDEV_LIVESTREAMER_H
+#define VDR_STREAMDEV_LIVESTREAMER_H
+
+#include <vdr/config.h>
+#include <vdr/receiver.h>
+
+#include "server/streamer.h"
+#include "common.h"
+
+namespace Streamdev {
+ class cTSRemux;
+}
+class cStreamdevPatFilter;
+class cStreamdevLiveReceiver;
+
+// --- cStreamdevLiveStreamer -------------------------------------------------
+
+class cStreamdevLiveStreamer: public cStreamdevStreamer {
+private:
+ int m_Priority;
+ std::string m_Parameter;
+ int m_Pids[MAXRECEIVEPIDS + 1];
+ int m_NumPids;
+ eStreamType m_StreamType;
+ const cChannel *m_Channel;
+ cDevice *m_Device;
+ cStreamdevLiveReceiver *m_Receiver;
+ cStreamdevPatFilter *m_PatFilter;
+ Streamdev::cTSRemux *m_Remux;
+
+ void StartReceiver(void);
+ bool HasPid(int Pid);
+
+public:
+ cStreamdevLiveStreamer(int Priority, std::string Parameter = "");
+ virtual ~cStreamdevLiveStreamer();
+
+ void SetDevice(cDevice *Device) { m_Device = Device; }
+ bool SetPid(int Pid, bool On);
+ bool SetPids(int Pid, const int *Pids1 = NULL, const int *Pids2 = NULL, const int *Pids3 = NULL);
+ bool SetChannel(const cChannel *Channel, eStreamType StreamType, int Apid = 0);
+
+ virtual int Put(const uchar *Data, int Count);
+ virtual uchar *Get(int &Count);
+ virtual void Del(int Count);
+
+ virtual void Attach(void);
+ virtual void Detach(void);
+
+ // Statistical purposes:
+ virtual std::string Report(void);
+};
+
+
+// --- cStreamdevFilterStreamer -------------------------------------------------
+
+//#include <vdr/status.h>
+
+class cStreamdevLiveFilter;
+
+class cStreamdevFilterStreamer: public cStreamdevStreamer /*, public cStatus*/ {
+private:
+ cDevice *m_Device;
+ cStreamdevLiveFilter *m_Filter;
+ //const cChannel *m_Channel;
+
+public:
+ cStreamdevFilterStreamer();
+ virtual ~cStreamdevFilterStreamer();
+
+ void SetDevice(cDevice *Device);
+ //void SetChannel(const cChannel *Channel);
+ bool SetFilter(u_short Pid, u_char Tid, u_char Mask, bool On);
+
+ virtual void Attach(void);
+ virtual void Detach(void);
+
+ // cStatus message handlers
+ //virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber);
+};
+
+#endif // VDR_STREAMDEV_LIVESTREAMER_H
diff --git a/plugins/streamdev/streamdev-cvs/server/menuHTTP.c b/plugins/streamdev/streamdev-cvs/server/menuHTTP.c
new file mode 100644
index 0000000..84a4fb7
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/menuHTTP.c
@@ -0,0 +1,429 @@
+#include <vdr/channels.h>
+#include "server/menuHTTP.h"
+
+//**************************** cChannelIterator **************
+cChannelIterator::cChannelIterator(cChannel *First): channel(First)
+{}
+
+const cChannel* cChannelIterator::Next()
+{
+ const cChannel *current = channel;
+ channel = NextChannel(channel);
+ return current;
+}
+
+//**************************** cListAll **************
+cListAll::cListAll(): cChannelIterator(Channels.First())
+{}
+
+const cChannel* cListAll::NextChannel(const cChannel *Channel)
+{
+ if (Channel)
+ Channel = Channels.Next(Channel);
+ return Channel;
+}
+
+//**************************** cListChannels **************
+cListChannels::cListChannels(): cChannelIterator(Channels.Get(Channels.GetNextNormal(-1)))
+{}
+
+const cChannel* cListChannels::NextChannel(const cChannel *Channel)
+{
+ if (Channel)
+ Channel = Channels.Get(Channels.GetNextNormal(Channel->Index()));
+ return Channel;
+}
+
+// ********************* cListGroups ****************
+cListGroups::cListGroups(): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1)))
+{}
+
+const cChannel* cListGroups::NextChannel(const cChannel *Channel)
+{
+ if (Channel)
+ Channel = Channels.Get(Channels.GetNextGroup(Channel->Index()));
+ return Channel;
+}
+//
+// ********************* cListGroup ****************
+cListGroup::cListGroup(const cChannel *Group): cChannelIterator((Group && Group->GroupSep() && Channels.Next(Group) && !Channels.Next(Group)->GroupSep()) ? Channels.Next(Group) : NULL)
+{}
+
+const cChannel* cListGroup::NextChannel(const cChannel *Channel)
+{
+ if (Channel)
+ Channel = Channels.Next(Channel);
+ return (Channel && !Channel->GroupSep()) ? Channel : NULL;
+}
+//
+// ********************* cListTree ****************
+cListTree::cListTree(const cChannel *SelectedGroup): cChannelIterator(Channels.Get(Channels.GetNextGroup(-1)))
+{
+ selectedGroup = SelectedGroup;
+ currentGroup = Channels.Get(Channels.GetNextGroup(-1));
+}
+
+const cChannel* cListTree::NextChannel(const cChannel *Channel)
+{
+ if (currentGroup == selectedGroup)
+ {
+ if (Channel)
+ Channel = Channels.Next(Channel);
+ if (Channel && Channel->GroupSep())
+ currentGroup = Channel;
+ }
+ else
+ {
+ if (Channel)
+ Channel = Channels.Get(Channels.GetNextGroup(Channel->Index()));
+ currentGroup = Channel;
+ }
+ return Channel;
+}
+
+// ******************** cChannelList ******************
+cChannelList::cChannelList(cChannelIterator *Iterator) : iterator(Iterator)
+{}
+
+cChannelList::~cChannelList()
+{
+ delete iterator;
+}
+
+int cChannelList::GetGroupIndex(const cChannel *Group)
+{
+ int index = 0;
+ for (int curr = Channels.GetNextGroup(-1); curr >= 0; curr = Channels.GetNextGroup(curr))
+ {
+ if (Channels.Get(curr) == Group)
+ return index;
+ index++;
+ }
+ return -1;
+}
+
+const cChannel* cChannelList::GetGroup(int Index)
+{
+ int group = Channels.GetNextGroup(-1);
+ while (Index-- && group >= 0)
+ group = Channels.GetNextGroup(group);
+ return group >= 0 ? Channels.Get(group) : NULL;
+}
+
+// ******************** cHtmlChannelList ******************
+const char* cHtmlChannelList::menu =
+ "[<a href=\"/\">Home</a> (<a href=\"all.html\" tvid=\"RED\">no script</a>)] "
+ "[<a href=\"tree.html\" tvid=\"GREEN\">Tree View</a>] "
+ "[<a href=\"groups.html\" tvid=\"YELLOW\">Groups</a> (<a href=\"groups.m3u\">Playlist</a>)] "
+ "[<a href=\"channels.html\" tvid=\"BLUE\">Channels</a> (<a href=\"channels.m3u\">Playlist</a>)] ";
+
+const char* cHtmlChannelList::css =
+ "<style type=\"text/css\">\n"
+ "<!--\n"
+ "a:link, a:visited, a:hover, a:active, a:focus { color:#333399; }\n"
+ "body { font:100% Verdana, Arial, Helvetica, sans-serif; background-color:#9999FF; margin:1em; }\n"
+ ".menu { position:fixed; top:0px; left:1em; right:1em; height:3em; text-align:center; background-color:white; border:inset 2px #9999ff; }\n"
+ "h2 { font-size:150%; margin:0em; padding:0em 1.5em; }\n"
+ ".contents { margin-top:5em; background-color:white; }\n"
+ ".group { background:url(data:image/gif;base64,R0lGODdhAQAeAIQeAJub/5yc/6Cf/6Oj/6am/6qq/66u/7Gx/7S0/7i4/7u8/7+//8LD/8bG/8nK/83N/9HQ/9TU/9fX/9va/97e/+Lh/+Xl/+no/+3t//Dw//Pz//b3//v7//7+/////////ywAAAAAAQAeAAAFGCAQCANRGAeSKAvTOA8USRNVWReWaRvXhQA7) repeat-x; border:inset 2px #9999ff; }\n"
+ ".items { border-top:dashed 1px; margin-top:0px; margin-bottom:0px; padding:0.7em 5em; }\n"
+ ".apid { padding-left:28px; margin:0.5em; background:url(data:image/gif;base64,R0lGODlhGwASAKEBAAAAAP///////////yH5BAEKAAEALAAAAAAbABIAAAJAjI+pywj5WgPxVAmpNRcHqnGb94FPhE7m+okts7JvusSmSys2iLv6TstldjMfhhUkcXi+zjFUVFo6TiVVij0UAAA7) no-repeat; }\n"
+ ".dpid { padding-left:28px; margin:0.5em; background:url(data:image/gif;base64,R0lGODlhGwASAKEBAAAAAP///////////yH5BAEKAAEALAAAAAAbABIAAAJFjI+py+0BopwAUoqivRvr83UaZ4RWMnVoBbLZaJbuqcCLGcv0+t5Vvgu2hLrh6pfDzVSpnlGEbAZhnIutZaVmH9yuV1EAADs=) no-repeat; }\n"
+ "button { width:2em; margin:0.2em 0.5em; vertical-align:top; }\n"
+ "-->\n"
+ "</style>";
+
+const char* cHtmlChannelList::js =
+ "<script language=\"JavaScript\">\n"
+ "<!--\n"
+
+ "function eventTarget(evt) {\n"
+ " if (!evt) evt = window.event;\n"
+ " if (evt.target) return evt.target;\n"
+ " else if (evt.srcElement) return evt.srcElement;\n"
+ " else return null;\n"
+ "}\n"
+
+ // toggle visibility of a group
+ "function clickHandler(evt) {\n"
+ " var button = eventTarget(evt);\n"
+ " if (button) {\n"
+ " var group = document.getElementById('c' + button.id);\n"
+ " if (group) {\n"
+ " button.removeChild(button.firstChild);\n"
+ " if (group.style.display == 'block') {\n"
+ " button.appendChild(document.createTextNode(\"+\"));\n"
+ " group.style.display = 'none';\n"
+ " } else {\n"
+ " button.appendChild(document.createTextNode(\"-\"));\n"
+ " group.style.display = 'block';\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n"
+
+ // insert a click button infront of each h2 and an id to the corresponding list
+ "function init() {\n"
+ " var titles = document.getElementsByTagName('h2');\n"
+ " for (var i = 0; i < titles.length; i++) {\n"
+ " var button = document.createElement('button');\n"
+ " button.id = 'g' + i;\n"
+ " button.onclick = clickHandler;\n"
+ " button.appendChild(document.createTextNode('+'));\n"
+ " titles[i].insertBefore(button, titles[i].firstChild);\n"
+ " var group = titles[i].nextSibling;\n"
+ " while (group) {\n"
+ " if (group.className && group.className == 'items') {\n"
+ " group.id = 'cg' + i;\n"
+ " break;\n"
+ " }\n"
+ " group = group.nextSibling;\n"
+ " }\n"
+ " }\n"
+ "}\n"
+
+ "window.onload = init;\n"
+
+ // hide lists before the browser renders it
+ "if (document.styleSheets[0].insertRule)\n"
+ " document.styleSheets[0].insertRule('.items { display:none }', 0);\n"
+ "else if (document.styleSheets[0].addRule)\n"
+ " document.styleSheets[0].addRule('.items', 'display:none');\n"
+
+ "//-->\n"
+ "</script>";
+
+
+std::string cHtmlChannelList::StreamTypeMenu()
+{
+ std::string typeMenu;
+ typeMenu += (streamType == stTS ? (std::string) "[TS] " :
+ (std::string) "[<a href=\"/TS/" + self + "\">TS</a>] ");
+ typeMenu += (streamType == stPS ? (std::string) "[PS] " :
+ (std::string) "[<a href=\"/PS/" + self + "\">PS</a>] ");
+ typeMenu += (streamType == stPES ? (std::string) "[PES] " :
+ (std::string) "[<a href=\"/PES/" + self + "\">PES</a>] ");
+ typeMenu += (streamType == stES ? (std::string) "[ES] " :
+ (std::string) "[<a href=\"/ES/" + self + "\">ES</a>] ");
+ typeMenu += (streamType == stExtern ? (std::string) "[Extern] " :
+ (std::string) "[<a href=\"/Extern/" + self + "\">Extern</a>] ");
+ return typeMenu;
+}
+
+cHtmlChannelList::cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget): cChannelList(Iterator)
+{
+ streamType = StreamType;
+ self = strdup(Self);
+ groupTarget = (GroupTarget && *GroupTarget) ? strdup(GroupTarget) : NULL;
+ htmlState = hsRoot;
+ current = NULL;
+}
+
+cHtmlChannelList::~cHtmlChannelList()
+{
+ free((void *) self);
+ free((void *) groupTarget);
+}
+
+bool cHtmlChannelList::HasNext()
+{
+ return htmlState != hsPageBottom;
+}
+
+std::string cHtmlChannelList::Next()
+{
+ switch (htmlState)
+ {
+ case hsRoot:
+ htmlState = hsHtmlHead;
+ break;
+ case hsHtmlHead:
+ htmlState = hsCss;
+ break;
+ case hsCss:
+ htmlState = *self ? hsPageTop : hsJs;
+ break;
+ case hsJs:
+ htmlState = hsPageTop;
+ break;
+ case hsPageTop:
+ current = NextChannel();
+ htmlState = current ? (current->GroupSep() ? hsGroupTop : hsPlainTop) : hsPageBottom;
+ break;
+ case hsPlainTop:
+ htmlState = hsPlainItem;
+ break;
+ case hsPlainItem:
+ current = NextChannel();
+ htmlState = current && !current->GroupSep() ? hsPlainItem : hsPlainBottom;
+ break;
+ case hsPlainBottom:
+ htmlState = current ? hsGroupTop : hsPageBottom;
+ break;
+ case hsGroupTop:
+ current = NextChannel();
+ htmlState = current && !current->GroupSep() ? hsItemsTop : hsGroupBottom;
+ break;
+ case hsItemsTop:
+ htmlState = hsItem;
+ break;
+ case hsItem:
+ current = NextChannel();
+ htmlState = current && !current->GroupSep() ? hsItem : hsItemsBottom;
+ break;
+ case hsItemsBottom:
+ htmlState = hsGroupBottom;
+ break;
+ case hsGroupBottom:
+ htmlState = current ? hsGroupTop : hsPageBottom;
+ break;
+ case hsPageBottom:
+ default:
+ esyslog("streamdev-server cHtmlChannelList: invalid call to Next()");
+ break;
+ }
+ switch (htmlState)
+ {
+ // NOTE: JavaScript requirements:
+ // Group title is identified by <h2> tag
+ // Channel list must be a sibling of <h2> with class "items"
+ case hsHtmlHead: return "<html><head>" + HtmlHead();
+ case hsCss: return css;
+ case hsJs: return js;
+ case hsPageTop: return "</head><body>" + PageTop() + "<div class=\"contents\">";
+ case hsGroupTop: return "<div class=\"group\"><h2>" + GroupTitle() + "</h2>";
+ case hsItemsTop:
+ case hsPlainTop: return "<ol class=\"items\">";
+ case hsItem:
+ case hsPlainItem: return ItemText();
+ case hsItemsBottom:
+ case hsPlainBottom: return "</ol>";
+ case hsGroupBottom: return "</div>";
+ case hsPageBottom: return "</div>" + PageBottom() + "</body></html>";
+ default: return "";
+ }
+}
+
+std::string cHtmlChannelList::HtmlHead()
+{
+ return (std::string) "";
+}
+
+std::string cHtmlChannelList::PageTop()
+{
+ return (std::string) "<div class=\"menu\"><div>" + menu + "</div><div>" + StreamTypeMenu() + "</div></div>";
+}
+
+std::string cHtmlChannelList::PageBottom()
+{
+ return (std::string) "";
+}
+
+std::string cHtmlChannelList::GroupTitle()
+{
+ if (groupTarget)
+ {
+ return (std::string) "<a href=\"" + groupTarget + "?group=" +
+ (const char*) itoa(cChannelList::GetGroupIndex(current)) +
+ "\">" + current->Name() + "</a>";
+ }
+ else
+ {
+ return (std::string) current->Name();
+ }
+}
+
+std::string cHtmlChannelList::ItemText()
+{
+ std::string line;
+ std::string suffix;
+
+ switch (streamType) {
+ case stTS: suffix = (std::string) ".ts"; break;
+ case stPS: suffix = (std::string) ".vob"; break;
+ // for Network Media Tank
+ case stPES: suffix = (std::string) ".vdr"; break;
+ default: suffix = "";
+ }
+ line += (std::string) "<li value=\"" + (const char*) itoa(current->Number()) + "\">";
+ line += (std::string) "<a href=\"" + (std::string) current->GetChannelID().ToString() + suffix + "\"";
+
+ // for Network Media Tank
+ line += (std::string) " vod ";
+ if (current->Number() < 1000)
+ line += (std::string) " tvid=\"" + (const char*) itoa(current->Number()) + "\"";
+
+ line += (std::string) ">" + current->Name() + "</a>";
+
+ int count = 0;
+ for (int i = 0; current->Apid(i) != 0; ++i, ++count)
+ ;
+ for (int i = 0; current->Dpid(i) != 0; ++i, ++count)
+ ;
+
+ if (count > 1)
+ {
+ int index = 1;
+ for (int i = 0; current->Apid(i) != 0; ++i, ++index) {
+ line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
+ "+" + (const char*)itoa(index) + suffix + "\" class=\"apid\" vod>" + current->Alang(i) + "</a>";
+ }
+ for (int i = 0; current->Dpid(i) != 0; ++i, ++index) {
+ line += (std::string) " <a href=\"" + (std::string) current->GetChannelID().ToString() +
+ "+" + (const char*)itoa(index) + suffix + "\" class=\"dpid\" vod>" + current->Dlang(i) + "</a>";
+ }
+ }
+ line += "</li>";
+ return line;
+}
+
+// ******************** cM3uChannelList ******************
+cM3uChannelList::cM3uChannelList(cChannelIterator *Iterator, const char* Base)
+: cChannelList(Iterator),
+ m_IConv(cCharSetConv::SystemCharacterTable(), "UTF-8")
+{
+ base = strdup(Base);
+ m3uState = msFirst;
+}
+
+cM3uChannelList::~cM3uChannelList()
+{
+ free(base);
+}
+
+bool cM3uChannelList::HasNext()
+{
+ return m3uState != msLast;
+}
+
+std::string cM3uChannelList::Next()
+{
+ if (m3uState == msFirst)
+ {
+ m3uState = msContinue;
+ return "#EXTM3U";
+ }
+
+ const cChannel *channel = NextChannel();
+ if (!channel)
+ {
+ m3uState = msLast;
+ return "";
+ }
+
+ std::string name = (std::string) m_IConv.Convert(channel->Name());
+
+ if (channel->GroupSep())
+ {
+ return (std::string) "#EXTINF:-1," + name + "\r\n" +
+ base + "group.m3u?group=" +
+ (const char*) itoa(cChannelList::GetGroupIndex(channel));
+ }
+ else
+ {
+ return (std::string) "#EXTINF:-1," +
+ (const char*) itoa(channel->Number()) + " " + name + "\r\n" +
+ base + (std::string) channel->GetChannelID().ToString();
+ }
+}
+
diff --git a/plugins/streamdev/streamdev-cvs/server/menuHTTP.h b/plugins/streamdev/streamdev-cvs/server/menuHTTP.h
new file mode 100644
index 0000000..cbd7b59
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/menuHTTP.h
@@ -0,0 +1,143 @@
+#ifndef VDR_STREAMDEV_SERVERS_MENUHTTP_H
+#define VDR_STREAMDEV_SERVERS_MENUHTTP_H
+
+#include <string>
+#include "../common.h"
+
+class cChannel;
+
+// ******************** cChannelIterator ******************
+class cChannelIterator
+{
+ private:
+ const cChannel *channel;
+ protected:
+ virtual const cChannel* NextChannel(const cChannel *Channel) = 0;
+ public:
+ const cChannel* Next();
+ cChannelIterator(cChannel *First);
+ virtual ~cChannelIterator() {};
+};
+
+class cListAll: public cChannelIterator
+{
+ protected:
+ virtual const cChannel* NextChannel(const cChannel *Channel);
+ public:
+ cListAll();
+ virtual ~cListAll() {};
+};
+
+class cListChannels: public cChannelIterator
+{
+ protected:
+ virtual const cChannel* NextChannel(const cChannel *Channel);
+ public:
+ cListChannels();
+ virtual ~cListChannels() {};
+};
+
+class cListGroups: public cChannelIterator
+{
+ protected:
+ virtual const cChannel* NextChannel(const cChannel *Channel);
+ public:
+ cListGroups();
+ virtual ~cListGroups() {};
+};
+
+class cListGroup: public cChannelIterator
+{
+ protected:
+ virtual const cChannel* NextChannel(const cChannel *Channel);
+ public:
+ cListGroup(const cChannel *Group);
+ virtual ~cListGroup() {};
+};
+
+class cListTree: public cChannelIterator
+{
+ private:
+ const cChannel* selectedGroup;
+ const cChannel* currentGroup;
+ protected:
+ virtual const cChannel* NextChannel(const cChannel *Channel);
+ public:
+ cListTree(const cChannel *SelectedGroup);
+ virtual ~cListTree() {};
+};
+
+// ******************** cChannelList ******************
+class cChannelList
+{
+ private:
+ cChannelIterator *iterator;
+ protected:
+ const cChannel* NextChannel() { return iterator->Next(); }
+ public:
+ // Helper which returns the group index
+ static int GetGroupIndex(const cChannel* Group);
+ // Helper which returns the group by its index
+ static const cChannel* GetGroup(int Index);
+
+ virtual std::string HttpHeader() { return "HTTP/1.0 200 OK\r\n"; };
+ virtual bool HasNext() = 0;
+ virtual std::string Next() = 0;
+ cChannelList(cChannelIterator *Iterator);
+ virtual ~cChannelList();
+};
+
+class cHtmlChannelList: public cChannelList
+{
+ private:
+ static const char* menu;
+ static const char* css;
+ static const char* js;
+
+ enum eHtmlState {
+ hsRoot, hsHtmlHead, hsCss, hsJs, hsPageTop, hsPageBottom,
+ hsGroupTop, hsGroupBottom,
+ hsPlainTop, hsPlainItem, hsPlainBottom,
+ hsItemsTop, hsItem, hsItemsBottom
+ };
+ eHtmlState htmlState;
+ const cChannel *current;
+ eStreamType streamType;
+ const char* self;
+ const char* groupTarget;
+
+ std::string StreamTypeMenu();
+ std::string HtmlHead();
+ std::string PageTop();
+ std::string GroupTitle();
+ std::string ItemText();
+ std::string PageBottom();
+ public:
+ virtual std::string HttpHeader() {
+ return cChannelList::HttpHeader()
+ + "Content-type: text/html; charset="
+ + (cCharSetConv::SystemCharacterTable() ? cCharSetConv::SystemCharacterTable() : "UTF-8")
+ + "\r\n";
+ }
+ virtual bool HasNext();
+ virtual std::string Next();
+ cHtmlChannelList(cChannelIterator *Iterator, eStreamType StreamType, const char *Self, const char *GroupTarget);
+ virtual ~cHtmlChannelList();
+};
+
+class cM3uChannelList: public cChannelList
+{
+ private:
+ char *base;
+ enum eM3uState { msFirst, msContinue, msLast };
+ eM3uState m3uState;
+ cCharSetConv m_IConv;
+ public:
+ virtual std::string HttpHeader() { return cChannelList::HttpHeader() + "Content-type: audio/x-mpegurl; charset=UTF-8\r\n"; };
+ virtual bool HasNext();
+ virtual std::string Next();
+ cM3uChannelList(cChannelIterator *Iterator, const char* Base);
+ virtual ~cM3uChannelList();
+};
+
+#endif
diff --git a/plugins/streamdev/streamdev-cvs/server/recplayer.c b/plugins/streamdev/streamdev-cvs/server/recplayer.c
new file mode 100644
index 0000000..f45d8c3
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/recplayer.c
@@ -0,0 +1,288 @@
+/*
+ Copyright 2004-2005 Chris Tallon
+
+ This file is part of VOMP.
+ and adopted for streamdev to play recordings
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "recplayer.h"
+
+#define _XOPEN_SOURCE 600
+#include <fcntl.h>
+
+RecPlayer::RecPlayer(cRecording* rec)
+{
+ file = NULL;
+ fileOpen = 0;
+ lastPosition = 0;
+ recording = rec;
+ for(int i = 1; i < 1000; i++) segments[i] = NULL;
+
+ // FIXME find out max file path / name lengths
+
+#if VDRVERSNUM >= 10703
+ indexFile = new cIndexFile(recording->FileName(), false, rec->IsPesRecording());
+#else
+ indexFile = new cIndexFile(recording->FileName(), false);
+#endif
+ if (!indexFile) esyslog("ERROR: Streamdev: Failed to create indexfile!");
+
+ scan();
+}
+
+void RecPlayer::scan()
+{
+ if (file) fclose(file);
+ totalLength = 0;
+ fileOpen = 0;
+ totalFrames = 0;
+
+ int i = 1;
+ while(segments[i++]) delete segments[i];
+
+ char fileName[2048];
+ for(i = 1; i < 1000; i++)
+ {
+
+#if APIVERSNUM < 10703
+ snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
+ //log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
+ file = fopen(fileName, "r");
+#else
+ snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), i);
+ file = fopen(fileName, "r");
+ if (!file) {
+ snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
+ file = fopen(fileName, "r");
+ }
+#endif
+ if (!file) break;
+
+ segments[i] = new Segment();
+ segments[i]->start = totalLength;
+ fseek(file, 0, SEEK_END);
+ totalLength += ftell(file);
+ totalFrames = indexFile->Last();
+ //log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames);
+ segments[i]->end = totalLength;
+ fclose(file);
+ }
+
+ file = NULL;
+}
+
+RecPlayer::~RecPlayer()
+{
+ //log->log("RecPlayer", Log::DEBUG, "destructor");
+ int i = 1;
+ while(segments[i++]) delete segments[i];
+ if (file) fclose(file);
+}
+
+int RecPlayer::openFile(int index)
+{
+ if (file) fclose(file);
+
+ char fileName[2048];
+
+#if APIVERSNUM >= 10703
+ snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index);
+ isyslog("openFile called for index %i string:%s", index, fileName);
+
+ file = fopen(fileName, "r");
+ if (file)
+ {
+ fileOpen = index;
+ return 1;
+ }
+#endif
+
+ snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
+ isyslog("openFile called for index %i string:%s", index, fileName);
+ //log->log("RecPlayer", Log::DEBUG, "openFile called for index %i string:%s", index, fileName);
+
+ file = fopen(fileName, "r");
+ if (file)
+ {
+ fileOpen = index;
+ return 1;
+ }
+
+ //log->log("RecPlayer", Log::DEBUG, "file failed to open");
+ fileOpen = 0;
+ return 0;
+}
+
+uint64_t RecPlayer::getLengthBytes()
+{
+ return totalLength;
+}
+
+uint32_t RecPlayer::getLengthFrames()
+{
+ return totalFrames;
+}
+
+unsigned long RecPlayer::getBlock(unsigned char* buffer, uint64_t position, unsigned long amount)
+{
+ if ((amount > totalLength) || (amount > 500000))
+ {
+ //log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount);
+ return 0;
+ }
+
+ if (position >= totalLength)
+ {
+ //log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
+ return 0;
+ }
+
+ if ((position + amount) > totalLength)
+ {
+ //log->log("RecPlayer", Log::DEBUG, "Client asked for some data past the end of recording, adjusting amount");
+ amount = totalLength - position;
+ }
+
+ // work out what block position is in
+ int segmentNumber;
+ for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++)
+ {
+ if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
+ // position is in this block
+ }
+
+ // we could be seeking around
+ if (segmentNumber != fileOpen)
+ {
+ if (!openFile(segmentNumber)) return 0;
+ }
+
+ uint64_t currentPosition = position;
+ uint32_t yetToGet = amount;
+ uint32_t got = 0;
+ uint32_t getFromThisSegment = 0;
+ uint32_t filePosition;
+
+ while(got < amount)
+ {
+ if (got)
+ {
+ // if(got) then we have already got some and we are back around
+ // advance the file pointer to the next file
+ if (!openFile(++segmentNumber)) return 0;
+ }
+
+ // is the request completely in this block?
+ if ((currentPosition + yetToGet) <= segments[segmentNumber]->end)
+ getFromThisSegment = yetToGet;
+ else
+ getFromThisSegment = segments[segmentNumber]->end - currentPosition;
+
+ filePosition = currentPosition - segments[segmentNumber]->start;
+ fseek(file, filePosition, SEEK_SET);
+ if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem.
+
+ // Tell linux not to bother keeping the data in the FS cache
+ posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
+
+ got += getFromThisSegment;
+ currentPosition += getFromThisSegment;
+ yetToGet -= getFromThisSegment;
+ }
+
+ lastPosition = position;
+ return got;
+}
+
+uint64_t RecPlayer::getLastPosition()
+{
+ return lastPosition;
+}
+
+cRecording* RecPlayer::getCurrentRecording()
+{
+ return recording;
+}
+
+uint64_t RecPlayer::positionFromFrameNumber(uint32_t frameNumber)
+{
+ if (!indexFile) return 0;
+
+#if VDRVERSNUM >= 10703
+ uint16_t retFileNumber;
+ off_t retFileOffset;
+#else
+ uchar retFileNumber;
+ int retFileOffset;
+#endif
+
+ if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset))
+ {
+ return 0;
+ }
+
+// log->log("RecPlayer", Log::DEBUG, "FN: %u FO: %i", retFileNumber, retFileOffset);
+ if (!segments[retFileNumber]) return 0;
+ uint64_t position = segments[retFileNumber]->start + retFileOffset;
+// log->log("RecPlayer", Log::DEBUG, "Pos: %llu", position);
+
+ return position;
+}
+
+uint32_t RecPlayer::frameNumberFromPosition(uint64_t position)
+{
+ if (!indexFile) return 0;
+
+ if (position >= totalLength)
+ {
+ //log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
+ return 0;
+ }
+
+ uint8_t segmentNumber;
+ for(segmentNumber = 1; segmentNumber < 255; segmentNumber++)
+ {
+ if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
+ // position is in this block
+ }
+ uint32_t askposition = position - segments[segmentNumber]->start;
+ return indexFile->Get((int)segmentNumber, askposition);
+
+}
+
+
+bool RecPlayer::getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength)
+{
+ // 0 = backwards
+ // 1 = forwards
+
+ if (!indexFile) return false;
+
+ int iframeLength;
+ int indexReturnFrameNumber;
+
+ indexReturnFrameNumber = (uint32_t)indexFile->GetNextIFrame(frameNumber, (direction==1 ? true : false), NULL, NULL, &iframeLength);
+ //log->log("RecPlayer", Log::DEBUG, "GNIF input framenumber:%lu, direction=%lu, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
+
+ if (indexReturnFrameNumber == -1) return false;
+
+ *rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
+ *rframeNumber = (uint32_t)indexReturnFrameNumber;
+ *rframeLength = (uint32_t)iframeLength;
+
+ return true;
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/recplayer.h b/plugins/streamdev/streamdev-cvs/server/recplayer.h
new file mode 100644
index 0000000..3da6c89
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/recplayer.h
@@ -0,0 +1,63 @@
+/*
+ Copyright 2004-2005 Chris Tallon
+
+ This file is part of VOMP.
+
+ VOMP is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ VOMP is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with VOMP; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifndef RECPLAYER_H
+#define RECPLAYER_H
+
+#include <stdio.h>
+#include <vdr/recording.h>
+
+#include "server/streamer.h"
+
+class Segment
+{
+ public:
+ uint64_t start;
+ uint64_t end;
+};
+
+class RecPlayer
+{
+ public:
+ RecPlayer(cRecording* rec);
+ ~RecPlayer();
+ uint64_t getLengthBytes();
+ uint32_t getLengthFrames();
+ unsigned long getBlock(unsigned char* buffer, uint64_t position, unsigned long amount);
+ int openFile(int index);
+ uint64_t getLastPosition();
+ cRecording* getCurrentRecording();
+ void scan();
+ uint64_t positionFromFrameNumber(uint32_t frameNumber);
+ uint32_t frameNumberFromPosition(uint64_t position);
+ bool getNextIFrame(uint32_t frameNumber, uint32_t direction, uint64_t* rfilePosition, uint32_t* rframeNumber, uint32_t* rframeLength);
+
+ private:
+ cRecording* recording;
+ cIndexFile* indexFile;
+ FILE* file;
+ int fileOpen;
+ Segment* segments[1000];
+ uint64_t totalLength;
+ uint64_t lastPosition;
+ uint32_t totalFrames;
+};
+
+#endif
diff --git a/plugins/streamdev/streamdev-cvs/server/server.c b/plugins/streamdev/streamdev-cvs/server/server.c
new file mode 100644
index 0000000..1bdb20a
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/server.c
@@ -0,0 +1,173 @@
+/*
+ * $Id: server.c,v 1.10 2009/02/13 10:39:22 schmirl Exp $
+ */
+
+#include "server/server.h"
+#include "server/componentVTP.h"
+#include "server/componentHTTP.h"
+#include "server/componentIGMP.h"
+#include "server/setup.h"
+
+#include <vdr/tools.h>
+#include <tools/select.h>
+#include <string.h>
+#include <errno.h>
+
+cSVDRPhosts StreamdevHosts;
+char *opt_auth = NULL;
+char *opt_remux = NULL;
+
+cStreamdevServer *cStreamdevServer::m_Instance = NULL;
+cList<cServerComponent> cStreamdevServer::m_Servers;
+cList<cServerConnection> cStreamdevServer::m_Clients;
+
+cStreamdevServer::cStreamdevServer(void):
+ cThread("streamdev server")
+{
+ Start();
+}
+
+cStreamdevServer::~cStreamdevServer()
+{
+ Stop();
+}
+
+void cStreamdevServer::Initialize(void)
+{
+ if (m_Instance == NULL) {
+ if (StreamdevServerSetup.StartVTPServer) Register(new cComponentVTP);
+ if (StreamdevServerSetup.StartHTTPServer) Register(new cComponentHTTP);
+ if (StreamdevServerSetup.StartIGMPServer) {
+ if (strcmp(StreamdevServerSetup.IGMPBindIP, "0.0.0.0") == 0)
+ esyslog("streamdev-server: Not starting IGMP. IGMP must be bound to a local IP");
+ else
+ Register(new cComponentIGMP);
+ }
+
+ m_Instance = new cStreamdevServer;
+ }
+}
+
+void cStreamdevServer::Destruct(void)
+{
+ DELETENULL(m_Instance);
+}
+
+void cStreamdevServer::Stop(void)
+{
+ if (Running())
+ Cancel(3);
+}
+
+void cStreamdevServer::Register(cServerComponent *Server)
+{
+ m_Servers.Add(Server);
+}
+
+void cStreamdevServer::Action(void)
+{
+ /* Initialize Server components, deleting those that failed */
+ for (cServerComponent *c = m_Servers.First(); c;) {
+ cServerComponent *next = m_Servers.Next(c);
+ if (!c->Initialize())
+ m_Servers.Del(c);
+ c = next;
+ }
+
+ if (m_Servers.Count() == 0) {
+ esyslog("ERROR: no streamdev server activated, exiting");
+ Cancel(-1);
+ }
+
+ cTBSelect select;
+ while (Running()) {
+ select.Clear();
+
+ /* Ask all Server components to register to the selector */
+ for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c))
+ select.Add(c->Socket(), false);
+
+ /* Ask all Client connections to register to the selector */
+ for (cServerConnection *s = m_Clients.First(); s; s = m_Clients.Next(s))
+ {
+ select.Add(s->Socket(), false);
+ if (s->HasData())
+ select.Add(s->Socket(), true);
+ }
+
+ int sel;
+ do
+ {
+ sel = select.Select(400);
+ if (sel < 0 && errno == ETIMEDOUT) {
+ // check for aborted clients
+ for (cServerConnection *s = m_Clients.First(); s; s = m_Clients.Next(s)) {
+ if (s->Abort())
+ sel = 0;
+ }
+ }
+ } while (sel < 0 && errno == ETIMEDOUT && Running());
+
+ if (!Running())
+ break;
+ if (sel < 0) {
+ esyslog("fatal error, server exiting: %m");
+ break;
+ }
+
+ /* Ask all Server components to act on signalled sockets */
+ for (cServerComponent *c = m_Servers.First(); c; c = m_Servers.Next(c)){
+ if (sel && select.CanRead(c->Socket())) {
+ cServerConnection *client = c->Accept();
+ if (!client)
+ continue;
+ m_Clients.Add(client);
+
+ if (m_Clients.Count() > StreamdevServerSetup.MaxClients) {
+ esyslog("streamdev: too many clients, rejecting %s:%d",
+ client->RemoteIp().c_str(), client->RemotePort());
+ client->Reject();
+ } else if (!client->CanAuthenticate() && !StreamdevHosts.Acceptable(client->RemoteIpAddr())) {
+ esyslog("streamdev: client %s:%d not allowed to connect",
+ client->RemoteIp().c_str(), client->RemotePort());
+ client->Reject();
+ } else
+ client->Welcome();
+ }
+ }
+
+ /* Ask all Client connections to act on signalled sockets */
+ for (cServerConnection *s = m_Clients.First(); s;) {
+ bool result = true;
+
+ if (sel && select.CanWrite(s->Socket()))
+ result = s->Write();
+
+ if (sel && result && select.CanRead(s->Socket()))
+ result = s->Read();
+
+ result &= !s->Abort();
+
+ cServerConnection *next = m_Clients.Next(s);
+ if (!result) {
+ isyslog("streamdev: closing streamdev connection to %s:%d",
+ s->RemoteIp().c_str(), s->RemotePort());
+ s->Close();
+ m_Clients.Del(s);
+ }
+ s = next;
+ }
+ }
+
+ while (m_Clients.Count() > 0) {
+ cServerConnection *s = m_Clients.First();
+ s->Close();
+ m_Clients.Del(s);
+ }
+
+ while (m_Servers.Count() > 0) {
+ cServerComponent *c = m_Servers.First();
+ c->Destruct();
+ m_Servers.Del(c);
+ }
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/server.h b/plugins/streamdev/streamdev-cvs/server/server.h
new file mode 100644
index 0000000..a44df1c
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/server.h
@@ -0,0 +1,49 @@
+/*
+ * $Id: server.h,v 1.6 2008/10/22 11:59:32 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SERVER_H
+#define VDR_STREAMDEV_SERVER_H
+
+#include <vdr/thread.h>
+
+#include "server/component.h"
+#include "server/connection.h"
+
+#define DEFAULT_EXTERNREMUX (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "externremux.sh"))
+#define STREAMDEVHOSTSPATH (*AddDirectory(cPlugin::ConfigDirectory(PLUGIN_NAME_I18N), "streamdevhosts.conf"))
+
+extern char *opt_auth;
+extern char *opt_remux;
+
+class cStreamdevServer: public cThread {
+private:
+ static cStreamdevServer *m_Instance;
+ static cList<cServerComponent> m_Servers;
+ static cList<cServerConnection> m_Clients;
+
+protected:
+ void Stop(void);
+
+ virtual void Action(void);
+
+ static void Register(cServerComponent *Server);
+
+public:
+ cStreamdevServer(void);
+ virtual ~cStreamdevServer();
+
+ static void Initialize(void);
+ static void Destruct(void);
+ static bool Active(void);
+};
+
+inline bool cStreamdevServer::Active(void)
+{
+ return m_Instance != NULL
+ && m_Instance->m_Clients.Count() > 0;
+}
+
+extern cSVDRPhosts StreamdevHosts;
+
+#endif // VDR_STREAMDEV_SERVER_H
diff --git a/plugins/streamdev/streamdev-cvs/server/setup.c b/plugins/streamdev/streamdev-cvs/server/setup.c
new file mode 100644
index 0000000..db709db
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/setup.c
@@ -0,0 +1,141 @@
+/*
+ * $Id: setup.c,v 1.9 2009/10/13 06:38:47 schmirl Exp $
+ */
+
+#include <vdr/menuitems.h>
+
+#include "server/setup.h"
+#include "server/server.h"
+
+cStreamdevServerSetup StreamdevServerSetup;
+
+cStreamdevServerSetup::cStreamdevServerSetup(void) {
+ MaxClients = 5;
+ StartVTPServer = true;
+ VTPServerPort = 2004;
+ StartHTTPServer = true;
+ HTTPServerPort = 3000;
+ HTTPStreamType = stTS;
+ StartIGMPServer = false;
+ IGMPClientPort = 1234;
+ IGMPStreamType = stTS;
+ SuspendMode = smAlways;
+ AllowSuspend = false;
+ strcpy(VTPBindIP, "0.0.0.0");
+ strcpy(HTTPBindIP, "0.0.0.0");
+ strcpy(IGMPBindIP, "0.0.0.0");
+}
+
+bool cStreamdevServerSetup::SetupParse(const char *Name, const char *Value) {
+ if (strcmp(Name, "MaxClients") == 0) MaxClients = atoi(Value);
+ else if (strcmp(Name, "StartServer") == 0) StartVTPServer = atoi(Value);
+ else if (strcmp(Name, "ServerPort") == 0) VTPServerPort = atoi(Value);
+ else if (strcmp(Name, "VTPBindIP") == 0) strcpy(VTPBindIP, Value);
+ else if (strcmp(Name, "StartHTTPServer") == 0) StartHTTPServer = atoi(Value);
+ else if (strcmp(Name, "HTTPServerPort") == 0) HTTPServerPort = atoi(Value);
+ else if (strcmp(Name, "HTTPStreamType") == 0) HTTPStreamType = atoi(Value);
+ else if (strcmp(Name, "HTTPBindIP") == 0) strcpy(HTTPBindIP, Value);
+ else if (strcmp(Name, "StartIGMPServer") == 0) StartIGMPServer = atoi(Value);
+ else if (strcmp(Name, "IGMPClientPort") == 0) IGMPClientPort = atoi(Value);
+ else if (strcmp(Name, "IGMPStreamType") == 0) IGMPStreamType = atoi(Value);
+ else if (strcmp(Name, "IGMPBindIP") == 0) strcpy(IGMPBindIP, Value);
+ else if (strcmp(Name, "SuspendMode") == 0) SuspendMode = atoi(Value);
+ else if (strcmp(Name, "AllowSuspend") == 0) AllowSuspend = atoi(Value);
+ else return false;
+ return true;
+}
+
+const char* cStreamdevServerMenuSetupPage::StreamTypes[st_Count - 1] = {
+ "TS",
+ "PES",
+ "PS",
+ "ES",
+ "Extern"
+};
+
+const char* cStreamdevServerMenuSetupPage::SuspendModes[sm_Count] = {
+ trNOOP("Offer suspend mode"),
+ trNOOP("Always suspended"),
+ trNOOP("Never suspended")
+};
+
+cStreamdevServerMenuSetupPage::cStreamdevServerMenuSetupPage(void) {
+ m_NewSetup = StreamdevServerSetup;
+
+ static const char* modes[sm_Count];
+ for (int i = 0; i < sm_Count; i++)
+ modes[i] = tr(SuspendModes[i]);
+
+ AddCategory (tr("Common Settings"));
+ Add(new cMenuEditIntItem (tr("Maximum Number of Clients"), &m_NewSetup.MaxClients, 0, 100));
+
+ Add(new cMenuEditStraItem(tr("Suspend behaviour"), &m_NewSetup.SuspendMode, sm_Count, modes));
+ Add(new cMenuEditBoolItem(tr("Client may suspend"), &m_NewSetup.AllowSuspend));
+
+ AddCategory (tr("VDR-to-VDR Server"));
+ Add(new cMenuEditBoolItem(tr("Start VDR-to-VDR Server"), &m_NewSetup.StartVTPServer));
+ Add(new cMenuEditIntItem (tr("VDR-to-VDR Server Port"), &m_NewSetup.VTPServerPort, 0, 65535));
+ Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.VTPBindIP));
+
+ AddCategory (tr("HTTP Server"));
+ Add(new cMenuEditBoolItem(tr("Start HTTP Server"), &m_NewSetup.StartHTTPServer));
+ Add(new cMenuEditIntItem (tr("HTTP Server Port"), &m_NewSetup.HTTPServerPort, 0, 65535));
+ Add(new cMenuEditStraItem(tr("HTTP Streamtype"), &m_NewSetup.HTTPStreamType, st_Count - 1, StreamTypes));
+ Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.HTTPBindIP));
+ AddCategory (tr("Multicast Streaming Server"));
+ Add(new cMenuEditBoolItem(tr("Start IGMP Server"), &m_NewSetup.StartIGMPServer));
+ Add(new cMenuEditIntItem (tr("Multicast Client Port"), &m_NewSetup.IGMPClientPort, 0, 65535));
+ Add(new cMenuEditStraItem(tr("Multicast Streamtype"), &m_NewSetup.IGMPStreamType, st_Count - 1, StreamTypes));
+ Add(new cMenuEditIpItem (tr("Bind to IP"), m_NewSetup.IGMPBindIP));
+ SetCurrent(Get(1));
+}
+
+cStreamdevServerMenuSetupPage::~cStreamdevServerMenuSetupPage() {
+}
+
+void cStreamdevServerMenuSetupPage::AddCategory(const char *Title) {
+
+ cString str = cString::sprintf("--- %s -------------------------------------------------"
+ "---------------", Title );
+
+ cOsdItem *item = new cOsdItem(*str);
+ item->SetSelectable(false);
+ Add(item);
+}
+
+void cStreamdevServerMenuSetupPage::Store(void) {
+ bool restart = false;
+ if (m_NewSetup.StartVTPServer != StreamdevServerSetup.StartVTPServer
+ || m_NewSetup.VTPServerPort != StreamdevServerSetup.VTPServerPort
+ || strcmp(m_NewSetup.VTPBindIP, StreamdevServerSetup.VTPBindIP) != 0
+ || m_NewSetup.StartHTTPServer != StreamdevServerSetup.StartHTTPServer
+ || m_NewSetup.HTTPServerPort != StreamdevServerSetup.HTTPServerPort
+ || strcmp(m_NewSetup.HTTPBindIP, StreamdevServerSetup.HTTPBindIP) != 0
+ || m_NewSetup.StartIGMPServer != StreamdevServerSetup.StartIGMPServer
+ || m_NewSetup.IGMPClientPort != StreamdevServerSetup.IGMPClientPort
+ || strcmp(m_NewSetup.IGMPBindIP, StreamdevServerSetup.IGMPBindIP) != 0) {
+ restart = true;
+ cStreamdevServer::Destruct();
+ }
+
+ SetupStore("MaxClients", m_NewSetup.MaxClients);
+ SetupStore("StartServer", m_NewSetup.StartVTPServer);
+ SetupStore("ServerPort", m_NewSetup.VTPServerPort);
+ SetupStore("VTPBindIP", m_NewSetup.VTPBindIP);
+ SetupStore("StartHTTPServer", m_NewSetup.StartHTTPServer);
+ SetupStore("HTTPServerPort", m_NewSetup.HTTPServerPort);
+ SetupStore("HTTPStreamType", m_NewSetup.HTTPStreamType);
+ SetupStore("HTTPBindIP", m_NewSetup.HTTPBindIP);
+ SetupStore("StartIGMPServer", m_NewSetup.StartIGMPServer);
+ SetupStore("IGMPClientPort", m_NewSetup.IGMPClientPort);
+ SetupStore("IGMPStreamType", m_NewSetup.IGMPStreamType);
+ SetupStore("IGMPBindIP", m_NewSetup.IGMPBindIP);
+ SetupStore("SuspendMode", m_NewSetup.SuspendMode);
+ SetupStore("AllowSuspend", m_NewSetup.AllowSuspend);
+
+ StreamdevServerSetup = m_NewSetup;
+
+ if (restart)
+ cStreamdevServer::Initialize();
+}
+
diff --git a/plugins/streamdev/streamdev-cvs/server/setup.h b/plugins/streamdev/streamdev-cvs/server/setup.h
new file mode 100644
index 0000000..d22ab34
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/setup.h
@@ -0,0 +1,48 @@
+/*
+ * $Id: setup.h,v 1.3 2009/09/18 10:43:26 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SETUPSERVER_H
+#define VDR_STREAMDEV_SETUPSERVER_H
+
+#include "common.h"
+
+struct cStreamdevServerSetup {
+ cStreamdevServerSetup(void);
+
+ bool SetupParse(const char *Name, const char *Value);
+
+ int MaxClients;
+ int StartVTPServer;
+ int VTPServerPort;
+ char VTPBindIP[20];
+ int StartHTTPServer;
+ int HTTPServerPort;
+ int HTTPStreamType;
+ char HTTPBindIP[20];
+ int StartIGMPServer;
+ int IGMPClientPort;
+ int IGMPStreamType;
+ char IGMPBindIP[20];
+ int SuspendMode;
+ int AllowSuspend;
+};
+
+extern cStreamdevServerSetup StreamdevServerSetup;
+
+class cStreamdevServerMenuSetupPage: public cMenuSetupPage {
+private:
+ static const char* StreamTypes[];
+ static const char* SuspendModes[];
+ cStreamdevServerSetup m_NewSetup;
+
+ void AddCategory(const char *Title);
+protected:
+ virtual void Store(void);
+
+public:
+ cStreamdevServerMenuSetupPage(void);
+ virtual ~cStreamdevServerMenuSetupPage();
+};
+
+#endif // VDR_STREAMDEV_SETUPSERVER_H
diff --git a/plugins/streamdev/streamdev-cvs/server/streamer.c b/plugins/streamdev/streamdev-cvs/server/streamer.c
new file mode 100644
index 0000000..42e7efa
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/streamer.c
@@ -0,0 +1,162 @@
+/*
+ * $Id: streamer.c,v 1.19 2009/06/19 06:32:45 schmirl Exp $
+ */
+
+#include <vdr/ringbuffer.h>
+#include <vdr/device.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "server/streamer.h"
+#include "server/suspend.h"
+#include "server/setup.h"
+#include "tools/socket.h"
+#include "tools/select.h"
+#include "common.h"
+
+// --- cStreamdevBuffer -------------------------------------------------------
+
+cStreamdevBuffer::cStreamdevBuffer(int Size, int Margin, bool Statistics, const char *Description):
+ cRingBufferLinear(Size, Margin, Statistics, Description)
+{
+}
+
+// --- cStreamdevWriter -------------------------------------------------------
+
+cStreamdevWriter::cStreamdevWriter(cTBSocket *Socket,
+ cStreamdevStreamer *Streamer):
+ cThread("streamdev-writer"),
+ m_Streamer(Streamer),
+ m_Socket(Socket)
+{
+}
+
+cStreamdevWriter::~cStreamdevWriter()
+{
+ Dprintf("destructing writer\n");
+ if (Running())
+ Cancel(3);
+}
+
+void cStreamdevWriter::Action(void)
+{
+ cTBSelect sel;
+ Dprintf("Writer start\n");
+ int max = 0;
+ uchar *block = NULL;
+ int count, offset = 0;
+
+ sel.Clear();
+ sel.Add(*m_Socket, true);
+ while (Running()) {
+ if (block == NULL) {
+ block = m_Streamer->Get(count);
+ offset = 0;
+ }
+
+ if (block != NULL) {
+ if (sel.Select(15000) == -1) {
+ esyslog("ERROR: streamdev-server: couldn't send data: %m");
+ break;
+ }
+
+ if (sel.CanWrite(*m_Socket)) {
+ int written;
+ int pkgsize = count;
+ // SOCK_DGRAM indicates multicast
+ if (m_Socket->Type() == SOCK_DGRAM) {
+ // don't fragment multicast packets
+ // max. payload on standard local ethernet is 1416 to 1456 bytes
+ // and some STBs expect complete TS packets
+ // so let's always limit to 7 * TS_SIZE = 1316
+ if (pkgsize > 7 * TS_SIZE)
+ pkgsize = 7 * TS_SIZE;
+ else
+ pkgsize -= pkgsize % TS_SIZE;
+ }
+ if ((written = m_Socket->Write(block + offset, pkgsize)) == -1) {
+ esyslog("ERROR: streamdev-server: couldn't send %d bytes: %m", pkgsize);
+ break;
+ }
+
+ // statistics
+ if (count > max)
+ max = count;
+
+ offset += written;
+ count -= written;
+
+ // less than one TS packet left:
+ // delete what we've written so far and get next chunk
+ if (count < TS_SIZE) {
+ m_Streamer->Del(offset);
+ block = NULL;
+ }
+ }
+ }
+ }
+ Dprintf("Max. Transmit Blocksize was: %d\n", max);
+}
+
+// --- cStreamdevStreamer -----------------------------------------------------
+
+cStreamdevStreamer::cStreamdevStreamer(const char *Name):
+ cThread(Name),
+ m_Writer(NULL),
+ m_RingBuffer(new cStreamdevBuffer(STREAMERBUFSIZE, TS_SIZE * 2,
+ true, "streamdev-streamer")),
+ m_SendBuffer(new cStreamdevBuffer(WRITERBUFSIZE, TS_SIZE * 2))
+{
+ m_RingBuffer->SetTimeouts(0, 100);
+ m_SendBuffer->SetTimeouts(100, 100);
+}
+
+cStreamdevStreamer::~cStreamdevStreamer()
+{
+ Dprintf("Desctructing streamer\n");
+ delete m_RingBuffer;
+ delete m_SendBuffer;
+}
+
+void cStreamdevStreamer::Start(cTBSocket *Socket)
+{
+ Dprintf("start streamer\n");
+ m_Writer = new cStreamdevWriter(Socket, this);
+ Attach();
+}
+
+void cStreamdevStreamer::Activate(bool On)
+{
+ if (On && !Active()) {
+ Dprintf("activate streamer\n");
+ m_Writer->Start();
+ cThread::Start();
+ }
+}
+
+void cStreamdevStreamer::Stop(void)
+{
+ if (Running()) {
+ Dprintf("stopping streamer\n");
+ Cancel(3);
+ }
+ if (m_Writer) {
+ Detach();
+ DELETENULL(m_Writer);
+ }
+}
+
+void cStreamdevStreamer::Action(void)
+{
+ while (Running()) {
+ int got;
+ uchar *block = m_RingBuffer->Get(got);
+
+ if (block) {
+ int count = Put(block, got);
+ if (count)
+ m_RingBuffer->Del(count);
+ }
+ }
+}
+
diff --git a/plugins/streamdev/streamdev-cvs/server/streamer.h b/plugins/streamdev/streamdev-cvs/server/streamer.h
new file mode 100644
index 0000000..6561bc2
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/streamer.h
@@ -0,0 +1,102 @@
+/*
+ * $Id: streamer.h,v 1.11 2009/06/19 06:32:45 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_STREAMER_H
+#define VDR_STREAMDEV_STREAMER_H
+
+#include <vdr/thread.h>
+#include <vdr/ringbuffer.h>
+#include <vdr/tools.h>
+
+class cTBSocket;
+class cStreamdevStreamer;
+
+#ifndef TS_SIZE
+#define TS_SIZE 188
+#endif
+
+#define STREAMERBUFSIZE (20000 * TS_SIZE)
+#define WRITERBUFSIZE (5000 * TS_SIZE)
+
+// --- cStreamdevBuffer -------------------------------------------------------
+
+class cStreamdevBuffer: public cRingBufferLinear {
+public:
+ // make public
+ void WaitForPut(void) { cRingBuffer::WaitForPut(); }
+ // Always write complete TS packets
+ // (assumes Count is a multiple of TS_SIZE)
+ int PutTS(const uchar *Data, int Count);
+ cStreamdevBuffer(int Size, int Margin = 0, bool Statistics = false, const char *Description = NULL);
+};
+
+inline int cStreamdevBuffer::PutTS(const uchar *Data, int Count)
+{
+ int free = Free();
+ if (free < Count)
+ Count = free;
+
+ Count -= Count % TS_SIZE;
+ if (Count)
+ Count = Put(Data, Count);
+ else
+ WaitForPut();
+ return Count;
+}
+
+// --- cStreamdevWriter -------------------------------------------------------
+
+class cStreamdevWriter: public cThread {
+private:
+ cStreamdevStreamer *m_Streamer;
+ cTBSocket *m_Socket;
+
+protected:
+ virtual void Action(void);
+
+public:
+ cStreamdevWriter(cTBSocket *Socket, cStreamdevStreamer *Streamer);
+ virtual ~cStreamdevWriter();
+};
+
+// --- cStreamdevStreamer -----------------------------------------------------
+
+class cStreamdevStreamer: public cThread {
+private:
+ cStreamdevWriter *m_Writer;
+ cStreamdevBuffer *m_RingBuffer;
+ cStreamdevBuffer *m_SendBuffer;
+
+protected:
+ virtual void Action(void);
+
+ bool IsRunning(void) const { return m_Writer; }
+
+public:
+ cStreamdevStreamer(const char *Name);
+ virtual ~cStreamdevStreamer();
+
+ virtual void Start(cTBSocket *Socket);
+ virtual void Stop(void);
+ bool Abort(void);
+
+ void Activate(bool On);
+ int Receive(uchar *Data, int Length) { return m_RingBuffer->PutTS(Data, Length); }
+ void ReportOverflow(int Bytes) { m_RingBuffer->ReportOverflow(Bytes); }
+
+ virtual int Put(const uchar *Data, int Count) { return m_SendBuffer->PutTS(Data, Count); }
+ virtual uchar *Get(int &Count) { return m_SendBuffer->Get(Count); }
+ virtual void Del(int Count) { m_SendBuffer->Del(Count); }
+
+ virtual void Detach(void) {}
+ virtual void Attach(void) {}
+};
+
+inline bool cStreamdevStreamer::Abort(void)
+{
+ return Active() && !m_Writer->Active();
+}
+
+#endif // VDR_STREAMDEV_STREAMER_H
+
diff --git a/plugins/streamdev/streamdev-cvs/server/suspend.c b/plugins/streamdev/streamdev-cvs/server/suspend.c
new file mode 100644
index 0000000..b6e1382
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/suspend.c
@@ -0,0 +1,57 @@
+/*
+ * $Id: suspend.c,v 1.3 2008/10/22 11:59:32 schmirl Exp $
+ */
+
+#include "server/suspend.h"
+#include "server/suspend.dat"
+#include "common.h"
+
+cSuspendLive::cSuspendLive(void)
+ : cThread("Streamdev: server suspend")
+{
+}
+
+cSuspendLive::~cSuspendLive() {
+ Stop();
+ Detach();
+}
+
+void cSuspendLive::Activate(bool On) {
+ Dprintf("Activate cSuspendLive %d\n", On);
+ if (On)
+ Start();
+ else
+ Stop();
+}
+
+void cSuspendLive::Stop(void) {
+ if (Running())
+ Cancel(3);
+}
+
+void cSuspendLive::Action(void) {
+ while (Running()) {
+ DeviceStillPicture(suspend_mpg, sizeof(suspend_mpg));
+ cCondWait::SleepMs(100);
+ }
+}
+
+bool cSuspendCtl::m_Active = false;
+
+cSuspendCtl::cSuspendCtl(void):
+ cControl(m_Suspend = new cSuspendLive) {
+ m_Active = true;
+}
+
+cSuspendCtl::~cSuspendCtl() {
+ m_Active = false;
+ DELETENULL(m_Suspend);
+}
+
+eOSState cSuspendCtl::ProcessKey(eKeys Key) {
+ if (!m_Suspend->Active() || Key == kBack) {
+ DELETENULL(m_Suspend);
+ return osEnd;
+ }
+ return osContinue;
+}
diff --git a/plugins/streamdev/streamdev-cvs/server/suspend.dat b/plugins/streamdev/streamdev-cvs/server/suspend.dat
new file mode 100644
index 0000000..7b1b890
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/suspend.dat
@@ -0,0 +1,1206 @@
+const unsigned char suspend_mpg[] = {
+ 0x00, 0x00, 0x01, 0xb3, 0x2d, 0x02, 0x40, 0x83, 0x02, 0xd0, 0x20, 0xa0,
+ 0x00, 0x00, 0x01, 0xb2, 0x4d, 0x50, 0x45, 0x47, 0x0a, 0x00, 0x00, 0x01,
+ 0xb8, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0a, 0xbb,
+ 0x58, 0x00, 0x00, 0x01, 0x01, 0x52, 0x97, 0xe6, 0x54, 0xa5, 0x2f, 0xdc,
+ 0xaf, 0x9a, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x45, 0xe2,
+ 0x2c, 0x52, 0x67, 0x98, 0x6c, 0x9a, 0x2e, 0xb9, 0x9e, 0xb4, 0x6c, 0xdd,
+ 0x34, 0x8c, 0x8b, 0xab, 0xa6, 0x61, 0xb5, 0xbd, 0x33, 0x8d, 0xa7, 0x22,
+ 0x6f, 0x75, 0x74, 0xcc, 0x36, 0xb4, 0x6c, 0xfd, 0x34, 0x64, 0x4d, 0xee,
+ 0x91, 0xb3, 0xf4, 0xd6, 0xf4, 0xcd, 0xd3, 0x46, 0x44, 0xde, 0xea, 0x1b,
+ 0x37, 0x4d, 0x77, 0x4c, 0xdd, 0x34, 0xe4, 0x43, 0xdd, 0x43, 0x66, 0xe9,
+ 0xad, 0x1b, 0x38, 0xda, 0x32, 0x26, 0xf7, 0x4f, 0x4c, 0xe3, 0x6b, 0x46,
+ 0xce, 0x36, 0x8c, 0x89, 0xbd, 0xd3, 0xd3, 0x3f, 0x4d, 0x68, 0xd9, 0x86,
+ 0xd3, 0x91, 0x37, 0xba, 0x86, 0xcc, 0x36, 0xbb, 0xa6, 0x6e, 0x9a, 0x32,
+ 0x26, 0xf7, 0x4f, 0x4c, 0xfd, 0x35, 0xbd, 0x33, 0xf4, 0xd1, 0x91, 0x37,
+ 0xba, 0x46, 0xcf, 0xd3, 0x5a, 0x36, 0x7e, 0x9a, 0x72, 0x26, 0xf7, 0x4f,
+ 0x4c, 0xfd, 0x35, 0xa3, 0x66, 0x1b, 0x46, 0x44, 0xde, 0xea, 0xe9, 0x9c,
+ 0x6d, 0x67, 0x4c, 0xfd, 0x34, 0x64, 0x43, 0xdd, 0x43, 0x66, 0xe9, 0xad,
+ 0xe9, 0x9c, 0x6d, 0x39, 0x13, 0x7b, 0xa7, 0xa6, 0x7e, 0x9a, 0xd1, 0xb3,
+ 0x0d, 0xa3, 0x22, 0x6f, 0x75, 0x74, 0xcd, 0xd3, 0x5c, 0x36, 0x61, 0xb4,
+ 0x0c, 0x9b, 0xdd, 0x43, 0x66, 0x1b, 0x5c, 0x36, 0x6e, 0x9a, 0x72, 0x26,
+ 0xf7, 0x50, 0xd9, 0xba, 0x6b, 0x86, 0xcd, 0xd3, 0x46, 0x44, 0xde, 0xea,
+ 0x1b, 0x30, 0xda, 0xd1, 0xb3, 0x8d, 0xa3, 0x22, 0x6f, 0x74, 0x8d, 0x9c,
+ 0x6d, 0x68, 0xd9, 0xba, 0x69, 0xc8, 0x87, 0xba, 0xba, 0x66, 0x1b, 0x5c,
+ 0x36, 0x6e, 0x9a, 0x32, 0x26, 0xf7, 0x57, 0x4c, 0xdd, 0x35, 0xdd, 0x33,
+ 0x74, 0xd1, 0x91, 0x37, 0xba, 0x9e, 0x6e, 0x9a, 0xde, 0x99, 0xfa, 0x68,
+ 0xc8, 0x9b, 0xdd, 0x23, 0x67, 0xe9, 0xad, 0x79, 0xc6, 0xd3, 0x91, 0x37,
+ 0xba, 0x7a, 0x67, 0xe9, 0xad, 0x1b, 0x30, 0xda, 0x32, 0x26, 0xf7, 0x50,
+ 0xd9, 0xba, 0x6b, 0x7a, 0x67, 0x1b, 0x46, 0x44, 0x3d, 0xd4, 0x36, 0x61,
+ 0xb5, 0xbd, 0x33, 0xbd, 0x39, 0x13, 0x7b, 0xa7, 0xa6, 0x71, 0xb5, 0xbf,
+ 0xcc, 0x36, 0x8c, 0x89, 0xbd, 0xd4, 0xf3, 0x0d, 0xae, 0xe9, 0x9b, 0xa6,
+ 0x9c, 0x89, 0xbd, 0xd4, 0xf3, 0x74, 0xd7, 0x74, 0xcc, 0x36, 0x8c, 0x89,
+ 0xbd, 0xd2, 0x36, 0x7e, 0x9a, 0xd1, 0xb3, 0x0d, 0xa3, 0x22, 0x6f, 0x75,
+ 0x74, 0xcf, 0xd3, 0x5b, 0xd3, 0x37, 0x4d, 0x19, 0x10, 0xf7, 0x53, 0xcc,
+ 0x36, 0xb7, 0xa6, 0x71, 0xb4, 0xe4, 0x4d, 0xee, 0x91, 0xb3, 0xf4, 0xd6,
+ 0x8d, 0x98, 0x6d, 0x03, 0x26, 0xf0, 0x00, 0x00, 0x01, 0x02, 0x2b, 0xf9,
+ 0x95, 0x29, 0x4b, 0xf7, 0x2b, 0xe6, 0xae, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x45, 0xe2, 0x2c, 0x52, 0x71, 0xb3, 0x74, 0xc9, 0xa2,
+ 0xeb, 0x79, 0x86, 0xd6, 0xf4, 0xcc, 0x36, 0x9c, 0x88, 0xba, 0xba, 0x66,
+ 0xe9, 0xad, 0x1b, 0x38, 0xda, 0x32, 0x26, 0xf7, 0x50, 0xd9, 0xba, 0x6b,
+ 0x7a, 0x67, 0xe9, 0xa7, 0x22, 0x6f, 0x74, 0x8d, 0x9f, 0xa6, 0xb4, 0x6c,
+ 0xc3, 0x68, 0xc8, 0x9b, 0xdd, 0x5d, 0x33, 0x0d, 0xae, 0x1b, 0x37, 0x4d,
+ 0x19, 0x13, 0x7b, 0xab, 0xa6, 0x61, 0xb5, 0xc3, 0x66, 0xe9, 0xa3, 0x22,
+ 0x1e, 0xea, 0x1b, 0x30, 0xda, 0xde, 0x99, 0xfa, 0x69, 0xc8, 0x9b, 0xdd,
+ 0x23, 0x67, 0x1b, 0x5b, 0xd3, 0x37, 0x4d, 0x19, 0x13, 0x7b, 0xa8, 0x6c,
+ 0xc3, 0x6b, 0x86, 0xcd, 0xd3, 0x46, 0x44, 0xde, 0xea, 0xe9, 0x9b, 0xa6,
+ 0xb7, 0xa6, 0x7e, 0x9a, 0x72, 0x26, 0xf7, 0x4f, 0x4c, 0xfd, 0x35, 0xa3,
+ 0x67, 0xe9, 0xa3, 0x22, 0x6f, 0x74, 0xf4, 0xce, 0x36, 0xb7, 0xa6, 0x67,
+ 0xa3, 0x22, 0x6f, 0x75, 0x74, 0xcc, 0xf5, 0xc3, 0x66, 0x1b, 0x4e, 0x44,
+ 0xde, 0xea, 0xe9, 0x9b, 0xa6, 0xb4, 0x6c, 0xfd, 0x34, 0x0c, 0x87, 0xba,
+ 0x46, 0xcf, 0xd3, 0x5a, 0x36, 0x61, 0xb4, 0x64, 0x4d, 0xee, 0xa1, 0xb3,
+ 0xf4, 0xd6, 0x8d, 0x9b, 0xa6, 0x9c, 0x89, 0xbd, 0xd5, 0xd3, 0x30, 0xda,
+ 0xee, 0x99, 0x86, 0xd1, 0x91, 0x37, 0xba, 0x86, 0xcc, 0x36, 0xb8, 0x6c,
+ 0xc3, 0x68, 0xc8, 0x9b, 0xdd, 0x5d, 0x33, 0x74, 0xd6, 0x8d, 0x9c, 0x6d,
+ 0x39, 0x13, 0x7b, 0xa4, 0x6c, 0xe3, 0x6b, 0x7a, 0x66, 0xe9, 0xa3, 0x22,
+ 0x6f, 0x75, 0x3c, 0xdd, 0x35, 0xdd, 0x33, 0x0d, 0xa3, 0x22, 0x1e, 0xea,
+ 0xe9, 0x9b, 0xa6, 0xb8, 0x6c, 0xdd, 0x34, 0xe4, 0x4d, 0xee, 0xa1, 0xb3,
+ 0x0d, 0xad, 0x1b, 0x3f, 0x4d, 0x19, 0x13, 0x7b, 0xa4, 0x6c, 0xe3, 0x6b,
+ 0x7a, 0x67, 0x1b, 0x46, 0x44, 0xde, 0xe9, 0x1b, 0x38, 0xda, 0xd1, 0xb3,
+ 0x3d, 0x39, 0x13, 0x7b, 0xab, 0xa6, 0x61, 0xb5, 0xdd, 0x33, 0x74, 0xd1,
+ 0x91, 0x37, 0xba, 0x5e, 0x7e, 0x9a, 0xee, 0x99, 0x9e, 0x8c, 0x88, 0x7b,
+ 0xa4, 0x6c, 0xfd, 0x35, 0xbf, 0xcc, 0x36, 0x9c, 0x89, 0xbd, 0xd5, 0xd3,
+ 0x33, 0xd7, 0x0d, 0x9b, 0xa6, 0x8c, 0x89, 0xbd, 0xd5, 0xd3, 0x37, 0x4d,
+ 0x68, 0xd9, 0xc6, 0xd1, 0x91, 0x37, 0xba, 0xba, 0x66, 0x1b, 0x5b, 0xd3,
+ 0x33, 0xd3, 0x91, 0x37, 0xba, 0x86, 0xce, 0x36, 0xb7, 0xa6, 0x61, 0xb4,
+ 0x64, 0x4d, 0xee, 0xa1, 0xb3, 0x74, 0xd7, 0x0d, 0x98, 0x6d, 0x19, 0x13,
+ 0x7b, 0xab, 0xa6, 0x6e, 0x9a, 0xd1, 0xb3, 0xf4, 0xd3, 0x91, 0x0f, 0x74,
+ 0x8d, 0x9f, 0xa6, 0xb4, 0x6c, 0xe3, 0x68, 0xc8, 0x9b, 0xdd, 0x23, 0x66,
+ 0x1b, 0x5c, 0x36, 0x6e, 0x9a, 0x32, 0x26, 0xf7, 0x57, 0x4c, 0xc3, 0x6b,
+ 0xba, 0x66, 0x1b, 0x4e, 0x44, 0xde, 0x00, 0x00, 0x01, 0x03, 0x2b, 0xf9,
+ 0x95, 0x29, 0x4b, 0xf7, 0x2b, 0xe6, 0xae, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x28, 0xf3, 0x3c, 0x9b, 0xf8, 0xb5, 0xa5, 0x67, 0x4c,
+ 0xe3, 0x64, 0xd1, 0x75, 0x3c, 0xc3, 0x6b, 0x7a, 0x66, 0x1b, 0x4e, 0x44,
+ 0x3d, 0xd5, 0xd3, 0x30, 0xda, 0xe1, 0xb3, 0x74, 0xd1, 0x91, 0x37, 0xba,
+ 0x86, 0xcc, 0x36, 0xb4, 0x6c, 0xfd, 0x34, 0x64, 0x4d, 0xee, 0x9e, 0x99,
+ 0xc6, 0xd6, 0x8d, 0x9c, 0x6d, 0x38, 0xa9, 0xbd, 0xd2, 0x36, 0x71, 0xb5,
+ 0xbd, 0x33, 0x0d, 0xa3, 0x22, 0x6f, 0x75, 0x74, 0xcc, 0x36, 0xbb, 0xa6,
+ 0x6e, 0x9a, 0x31, 0x53, 0x7b, 0xab, 0xa6, 0x6e, 0x9a, 0xd1, 0xb3, 0x8d,
+ 0xa7, 0x15, 0x37, 0xba, 0xba, 0x66, 0x1b, 0x5a, 0x36, 0x6e, 0x9a, 0x06,
+ 0x43, 0xdd, 0x5d, 0x33, 0x0d, 0xae, 0x1b, 0x30, 0xda, 0x72, 0x26, 0xf7,
+ 0x57, 0x4c, 0xc3, 0x6b, 0x86, 0xcd, 0xd3, 0x46, 0x44, 0xde, 0xea, 0x1b,
+ 0x37, 0x4d, 0x6f, 0x4c, 0xe3, 0x68, 0x19, 0x37, 0xba, 0x86, 0xcd, 0xd3,
+ 0x5a, 0x36, 0x61, 0xb4, 0xe4, 0x4d, 0xee, 0xae, 0x99, 0x86, 0xd7, 0x74,
+ 0xcd, 0xd3, 0x46, 0x44, 0xde, 0xea, 0x1b, 0x30, 0xda, 0xde, 0x99, 0xfa,
+ 0x68, 0xc8, 0x9b, 0xdd, 0x5d, 0x33, 0x0d, 0xad, 0x1b, 0x3f, 0x4d, 0x23,
+ 0x26, 0xf7, 0x4f, 0x4c, 0xfd, 0x35, 0xbd, 0x33, 0x74, 0xd1, 0x91, 0x0f,
+ 0x75, 0x0d, 0x9f, 0xa6, 0xb7, 0xa6, 0x71, 0xb4, 0x64, 0x4d, 0xee, 0x9e,
+ 0x99, 0xba, 0x6b, 0x86, 0xcd, 0xd3, 0x4e, 0x44, 0xde, 0xea, 0x1b, 0x37,
+ 0x4d, 0x6f, 0x4c, 0xfd, 0x34, 0x64, 0x4d, 0xee, 0xa1, 0xb3, 0x0d, 0xad,
+ 0x1b, 0x38, 0xda, 0x32, 0x26, 0xf7, 0x4f, 0x4c, 0xe3, 0x6b, 0x46, 0xcd,
+ 0xd3, 0x4e, 0x44, 0xde, 0xea, 0xe9, 0x98, 0x6d, 0x70, 0xd9, 0xba, 0x68,
+ 0xc8, 0x87, 0xba, 0x86, 0xcd, 0xd3, 0x5d, 0xd3, 0x30, 0xda, 0x32, 0x26,
+ 0xf7, 0x57, 0x4c, 0xdd, 0x35, 0xa3, 0x67, 0x1b, 0x4e, 0x44, 0xde, 0xe9,
+ 0x1b, 0x38, 0xda, 0xde, 0x99, 0x86, 0xd1, 0x91, 0x37, 0xba, 0xba, 0x66,
+ 0x1b, 0x5c, 0x36, 0x6e, 0x9a, 0x32, 0x26, 0xf7, 0x57, 0x4c, 0xdd, 0x35,
+ 0xc3, 0x66, 0xe9, 0xa7, 0x22, 0x6f, 0x75, 0x74, 0xcc, 0x36, 0xb5, 0xe6,
+ 0xe9, 0xa3, 0x22, 0x1e, 0xea, 0xe9, 0x99, 0xeb, 0xba, 0x66, 0xe9, 0xa3,
+ 0x22, 0x6f, 0x75, 0x0d, 0x98, 0x6d, 0x70, 0xd9, 0x86, 0xd3, 0x91, 0x37,
+ 0xba, 0x86, 0xcd, 0xd3, 0x5a, 0x36, 0x61, 0xb4, 0x64, 0x4e, 0xea, 0xe9,
+ 0x9b, 0xa6, 0xbb, 0xa6, 0x6e, 0x9a, 0x32, 0x26, 0xf7, 0x53, 0xcc, 0x36,
+ 0xbb, 0xa6, 0x6e, 0x9a, 0x72, 0x26, 0xf7, 0x57, 0x4c, 0xc3, 0x6b, 0x46,
+ 0xcf, 0xd3, 0x46, 0x44, 0xde, 0xea, 0x1b, 0x37, 0x4d, 0x6f, 0x4c, 0xfd,
+ 0x34, 0x64, 0x43, 0xdd, 0x23, 0x67, 0xe9, 0xad, 0xe9, 0x98, 0x6d, 0x39,
+ 0x13, 0x7b, 0xab, 0xa6, 0x6e, 0x9a, 0xe1, 0xb3, 0x74, 0xd1, 0x91, 0x37,
+ 0xba, 0xba, 0x66, 0xe9, 0xad, 0x1b, 0x3f, 0x4d, 0x19, 0x13, 0x7b, 0xa4,
+ 0x6c, 0xfd, 0x35, 0xa3, 0x67, 0x1b, 0x4e, 0x44, 0xde, 0xe9, 0xe9, 0x9c,
+ 0x6d, 0x6f, 0x4c, 0xdd, 0x34, 0x64, 0x4d, 0xe0, 0x00, 0x00, 0x01, 0x04,
+ 0x2b, 0xf9, 0x95, 0x22, 0xf3, 0x74, 0xdf, 0xb8, 0xb5, 0xf3, 0x56, 0x91,
+ 0x7a, 0xce, 0x99, 0xc6, 0xc8, 0x64, 0x5d, 0x23, 0x67, 0xe9, 0xad, 0xe9,
+ 0x9b, 0xa6, 0x9c, 0x89, 0xdd, 0xe0, 0x19, 0xf4, 0x80, 0x54, 0x5f, 0x41,
+ 0x2c, 0x20, 0x61, 0x7f, 0x14, 0x4b, 0x25, 0xa5, 0x05, 0x27, 0x25, 0x25,
+ 0x20, 0x95, 0xd0, 0x58, 0xd2, 0xd1, 0xba, 0x33, 0x73, 0x4d, 0xb1, 0xe0,
+ 0x0c, 0x00, 0x60, 0x1a, 0x8d, 0xf2, 0x40, 0xaf, 0xc9, 0xcf, 0xbe, 0x01,
+ 0x88, 0x0e, 0xce, 0xe6, 0xe0, 0x0a, 0x6d, 0x1d, 0x32, 0x00, 0x36, 0xf8,
+ 0xa2, 0x62, 0x40, 0x74, 0xb0, 0x42, 0x08, 0x49, 0x29, 0x0f, 0xbe, 0x00,
+ 0xa3, 0xe1, 0xa1, 0x8c, 0xff, 0xff, 0x90, 0x8e, 0x06, 0x06, 0xba, 0xd2,
+ 0x57, 0xbe, 0x6c, 0x01, 0xa2, 0x51, 0xd0, 0x58, 0x67, 0xdb, 0xfd, 0xc9,
+ 0x79, 0xf6, 0xea, 0x3b, 0x91, 0x2f, 0x54, 0x03, 0x1c, 0x9d, 0x90, 0x5a,
+ 0x3f, 0xc6, 0x75, 0xde, 0xc0, 0x13, 0x10, 0xd2, 0x94, 0x16, 0x50, 0x6f,
+ 0x1a, 0x1a, 0x05, 0x0b, 0x49, 0x30, 0x37, 0xb3, 0x3f, 0x43, 0x74, 0x24,
+ 0x90, 0x84, 0x01, 0x72, 0xba, 0x0b, 0xe3, 0x30, 0xcd, 0xd2, 0xc6, 0x59,
+ 0x7a, 0x6d, 0x20, 0x21, 0xc0, 0x07, 0xc0, 0x19, 0xe4, 0xac, 0x60, 0x09,
+ 0xca, 0x18, 0x49, 0xed, 0x89, 0xa4, 0x27, 0xea, 0x43, 0x30, 0xd2, 0xc3,
+ 0x3f, 0x7e, 0xa5, 0x13, 0x31, 0xf0, 0x7b, 0xbc, 0x03, 0x10, 0x29, 0x88,
+ 0x40, 0x55, 0x39, 0x19, 0x90, 0x90, 0x94, 0x08, 0xe4, 0x0f, 0x72, 0x00,
+ 0xe8, 0x34, 0x0c, 0x86, 0x23, 0x9a, 0x77, 0xba, 0xba, 0x66, 0xe9, 0xad,
+ 0xe9, 0x9f, 0xa6, 0xec, 0xc8, 0xb9, 0xde, 0xe9, 0xe9, 0xb4, 0x13, 0x12,
+ 0x1a, 0x02, 0x14, 0x96, 0x80, 0x28, 0xdb, 0x06, 0x27, 0x20, 0xb2, 0x19,
+ 0x78, 0x68, 0x66, 0xfb, 0xf2, 0x59, 0x45, 0x6c, 0x94, 0x24, 0xb2, 0xd0,
+ 0xcc, 0x96, 0xf9, 0x08, 0xfd, 0x69, 0xe9, 0x47, 0x45, 0x79, 0x0d, 0x25,
+ 0xfc, 0x82, 0x83, 0x3e, 0xc1, 0xa4, 0xd2, 0xd0, 0x18, 0x57, 0x7d, 0xbe,
+ 0xe9, 0xeb, 0x2d, 0x19, 0x3b, 0xe4, 0xf0, 0xc2, 0x86, 0x86, 0x8c, 0x6e,
+ 0xf9, 0x1e, 0xf2, 0xc8, 0x41, 0x40, 0x3a, 0x0c, 0xdb, 0x29, 0x05, 0x63,
+ 0x7b, 0x87, 0xff, 0xd7, 0xff, 0x37, 0xf5, 0xfe, 0xbf, 0x78, 0x80, 0x0f,
+ 0x80, 0x34, 0x40, 0x6e, 0x03, 0x25, 0xa0, 0x6e, 0x76, 0x46, 0x1f, 0xf1,
+ 0xbc, 0x7e, 0xbd, 0x10, 0x10, 0x80, 0xef, 0x86, 0x32, 0x10, 0x7f, 0x27,
+ 0x55, 0x3d, 0x0c, 0x02, 0x02, 0x94, 0x35, 0x21, 0xa5, 0xf6, 0x67, 0xe5,
+ 0xa5, 0x0e, 0x02, 0x20, 0xce, 0x52, 0x1c, 0x5b, 0x55, 0x80, 0x1d, 0x13,
+ 0x07, 0x16, 0x09, 0x3f, 0x81, 0xa0, 0x9b, 0xfb, 0x64, 0x09, 0x4a, 0xdc,
+ 0x65, 0xeb, 0x50, 0x03, 0xb0, 0x1d, 0x97, 0x9c, 0x96, 0x56, 0x5a, 0x73,
+ 0x12, 0xbf, 0x5a, 0x3f, 0xdd, 0x60, 0x65, 0x6b, 0xc7, 0xaa, 0xf0, 0x53,
+ 0x8a, 0x2b, 0x3a, 0x7a, 0x36, 0x38, 0xe2, 0x05, 0xe9, 0xa0, 0x96, 0x5f,
+ 0x57, 0xe1, 0x75, 0x9f, 0x9d, 0x01, 0xb2, 0x05, 0x80, 0x46, 0x92, 0x0d,
+ 0x6f, 0x21, 0x15, 0xc0, 0x98, 0x24, 0xfe, 0x96, 0x00, 0x31, 0xbb, 0x24,
+ 0xb0, 0xd0, 0x26, 0x80, 0x08, 0xb8, 0x00, 0xc6, 0x80, 0x64, 0x37, 0x1a,
+ 0x8e, 0x1d, 0xf1, 0x17, 0xdb, 0x0d, 0x28, 0x7e, 0x0a, 0xb1, 0x18, 0x9b,
+ 0xce, 0x1a, 0x05, 0x06, 0xaf, 0x06, 0x96, 0x80, 0xa6, 0xaf, 0x46, 0x42,
+ 0x3e, 0x41, 0x7b, 0xef, 0xce, 0xe3, 0x52, 0xdc, 0x9e, 0x78, 0xab, 0x22,
+ 0x08, 0x60, 0x12, 0xe6, 0x17, 0xbb, 0xe2, 0x25, 0xc5, 0x2c, 0xac, 0x5a,
+ 0x3e, 0xeb, 0xde, 0xe6, 0xcc, 0x29, 0xae, 0x8e, 0xf8, 0xfb, 0xd2, 0x03,
+ 0x62, 0x85, 0x80, 0x46, 0x92, 0x0d, 0x00, 0x6c, 0x50, 0xee, 0x01, 0x1a,
+ 0x48, 0x37, 0xad, 0x1a, 0x43, 0x43, 0xa0, 0x97, 0x94, 0x3d, 0x0b, 0xf8,
+ 0xce, 0x49, 0x02, 0x34, 0x25, 0x93, 0x40, 0x25, 0x40, 0x04, 0x5c, 0x00,
+ 0x63, 0x69, 0xc6, 0x63, 0x70, 0x55, 0x8b, 0x26, 0xfc, 0x98, 0x0d, 0x8a,
+ 0x1d, 0xc0, 0x23, 0x49, 0x06, 0x80, 0x36, 0x28, 0x77, 0x00, 0x8d, 0x24,
+ 0x1b, 0xd7, 0x92, 0xc8, 0x60, 0x12, 0xa0, 0x02, 0x2e, 0x00, 0x31, 0x89,
+ 0x2c, 0x86, 0x01, 0x2a, 0x00, 0x22, 0x00, 0x17, 0xd4, 0xe5, 0x0f, 0xc1,
+ 0x54, 0x8c, 0x4d, 0xf9, 0x40, 0x0b, 0x0a, 0x30, 0x6e, 0x01, 0x1f, 0xe4,
+ 0x7f, 0xf5, 0xd9, 0x2c, 0x31, 0x25, 0x2f, 0x04, 0xe0, 0x08, 0x44, 0xa9,
+ 0x5c, 0x39, 0xab, 0xb1, 0x0c, 0x35, 0x07, 0xb2, 0x44, 0x2b, 0x91, 0xfd,
+ 0xe3, 0xd0, 0x9c, 0x5e, 0xdf, 0x1b, 0x0c, 0x8e, 0x3b, 0xd6, 0x12, 0x8a,
+ 0x9f, 0xdd, 0xe2, 0xf2, 0x76, 0xfb, 0xef, 0xbe, 0x7d, 0xf2, 0xf7, 0xdc,
+ 0xdd, 0xe2, 0xf5, 0x00, 0x1a, 0x86, 0x00, 0x1f, 0x00, 0xef, 0xa3, 0x12,
+ 0x03, 0x77, 0x0d, 0x28, 0x53, 0x7d, 0x8b, 0x46, 0x51, 0xdb, 0xfd, 0xf3,
+ 0xf0, 0x3e, 0xd9, 0x5a, 0xdc, 0xf7, 0xb6, 0x1a, 0x18, 0x06, 0x13, 0xf0,
+ 0x50, 0x8b, 0xc9, 0x28, 0xb2, 0x5a, 0x37, 0xba, 0x9e, 0x77, 0xad, 0x79,
+ 0x9e, 0xd1, 0xa8, 0xba, 0x9e, 0x67, 0xae, 0x79, 0x9e, 0x86, 0x9d, 0xd4,
+ 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0x34, 0xee, 0x97, 0x9d, 0xeb, 0x5e, 0x77,
+ 0xa1, 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0xbd, 0x2d, 0x17, 0x4b, 0xce,
+ 0xf5, 0xaf, 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x67, 0xad, 0x79, 0xde, 0x86,
+ 0x9d, 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0xb4, 0xee, 0x97, 0x9d, 0xeb,
+ 0x5e, 0x67, 0xa1, 0xa7, 0x75, 0x3c, 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b,
+ 0xa9, 0xe6, 0x7a, 0xe7, 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd6, 0xbc,
+ 0xef, 0x43, 0x45, 0xd4, 0xf3, 0x3d, 0x6b, 0xcc, 0xf4, 0x34, 0xee, 0xa7,
+ 0x99, 0xeb, 0x9e, 0x67, 0xa5, 0xa7, 0x75, 0x3c, 0xcf, 0x5c, 0xf3, 0x3d,
+ 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xd7, 0x9d, 0xe8, 0x69, 0xdd, 0x2f, 0x33,
+ 0xd7, 0x3c, 0xcf, 0x4b, 0x4e, 0xea, 0x79, 0x9e, 0xb9, 0xe6, 0x7a, 0x1a,
+ 0x2e, 0xa7, 0x99, 0xeb, 0x5e, 0x67, 0xa1, 0xa7, 0x75, 0x3c, 0xef, 0x5a,
+ 0xf3, 0x3d, 0x2d, 0x3b, 0xa9, 0xe6, 0x7a, 0xe7, 0x99, 0xe8, 0x69, 0xdd,
+ 0x4f, 0x33, 0xd7, 0x3c, 0xcf, 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb5, 0xe7,
+ 0x7a, 0x5a, 0x77, 0x4b, 0xce, 0xf5, 0xaf, 0x33, 0xd0, 0xd1, 0x75, 0x3c,
+ 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xe7, 0x99, 0xe9,
+ 0x69, 0xdd, 0x2f, 0x3b, 0xd6, 0xbc, 0xef, 0x43, 0x4e, 0xe9, 0x79, 0xde,
+ 0xb5, 0xe6, 0x7a, 0x1a, 0x77, 0x53, 0xce, 0xf5, 0xaf, 0x33, 0xd2, 0xd3,
+ 0xba, 0x9e, 0x67, 0xac, 0x8d, 0x2d, 0x16, 0xaf, 0x17, 0x8d, 0x29, 0x9c,
+ 0x00, 0x00, 0x01, 0x05, 0x3b, 0xf9, 0xd3, 0xce, 0xf5, 0xaf, 0x33, 0xdf,
+ 0xb5, 0x35, 0xf3, 0x97, 0x53, 0xcc, 0xf5, 0xcf, 0x33, 0xd2, 0xd1, 0x75,
+ 0x3c, 0xcf, 0x5a, 0xf3, 0xbd, 0x0d, 0x3b, 0xa9, 0xe7, 0x28, 0xb0, 0x1b,
+ 0x00, 0xec, 0x31, 0x26, 0x06, 0xb9, 0x31, 0x21, 0x06, 0x9e, 0x57, 0xe9,
+ 0x1d, 0xbb, 0xa3, 0x61, 0xe1, 0xb5, 0x8f, 0x68, 0x26, 0xee, 0x59, 0x49,
+ 0xdb, 0xed, 0xc0, 0xf7, 0xf9, 0xc6, 0x27, 0x2d, 0x09, 0x61, 0xe8, 0xed,
+ 0xf0, 0xbd, 0x71, 0x01, 0x44, 0x81, 0x80, 0xd4, 0x24, 0xc3, 0xb8, 0x8f,
+ 0x6e, 0x1a, 0x82, 0x5a, 0x3e, 0xab, 0x78, 0x80, 0x3b, 0x47, 0x48, 0x67,
+ 0xf9, 0x7d, 0x01, 0x38, 0xc7, 0x63, 0x03, 0xf3, 0xe0, 0xfb, 0xab, 0xbe,
+ 0xfb, 0x7d, 0xdf, 0x73, 0x6f, 0x3a, 0x52, 0x49, 0x68, 0xdc, 0x7e, 0x5e,
+ 0x1d, 0xcd, 0xc1, 0xdd, 0x57, 0xae, 0xc0, 0x5b, 0xa4, 0xa0, 0x25, 0xc5,
+ 0x12, 0x3a, 0xd0, 0x1c, 0xca, 0x0e, 0xf7, 0x8a, 0x43, 0x43, 0xa3, 0x71,
+ 0xc4, 0x6b, 0xd2, 0x26, 0x76, 0x7d, 0x53, 0xe3, 0x79, 0x9e, 0xb9, 0xeb,
+ 0x12, 0x9c, 0x8d, 0xff, 0xfb, 0x6c, 0xbf, 0xfa, 0xb6, 0xc3, 0xfd, 0xef,
+ 0x64, 0x3d, 0xe4, 0xbd, 0x6d, 0xce, 0x2b, 0x3a, 0x5c, 0x09, 0x62, 0x7f,
+ 0x20, 0x62, 0x3c, 0x84, 0x34, 0xb3, 0x6c, 0x69, 0x1b, 0x00, 0xfa, 0xe6,
+ 0x86, 0x66, 0x46, 0x73, 0xfa, 0xf8, 0x07, 0xc7, 0x5e, 0xb5, 0x3c, 0x6a,
+ 0x53, 0xc7, 0x2b, 0x11, 0x40, 0x3e, 0xbe, 0x47, 0x04, 0x6b, 0xdd, 0x3f,
+ 0xd4, 0xfe, 0x02, 0xfa, 0x09, 0x33, 0xa8, 0xb0, 0x47, 0xfb, 0x21, 0x82,
+ 0x5f, 0xd9, 0x77, 0xcf, 0xaf, 0xa3, 0x06, 0x70, 0x1c, 0x82, 0x3f, 0xd9,
+ 0x0c, 0x12, 0xfe, 0xd3, 0x74, 0x80, 0x9c, 0x10, 0xc1, 0x81, 0x23, 0xf7,
+ 0x11, 0xbd, 0x00, 0x30, 0x24, 0xf1, 0x17, 0x8d, 0xee, 0x70, 0x60, 0x05,
+ 0xc0, 0x21, 0x26, 0x95, 0x83, 0x71, 0x41, 0x85, 0x15, 0xf3, 0x80, 0x52,
+ 0x5a, 0x50, 0x5b, 0x0f, 0x19, 0x83, 0x0b, 0x65, 0x2f, 0x64, 0xf4, 0x73,
+ 0x3e, 0xd7, 0x7c, 0x9a, 0x9d, 0x8a, 0x2d, 0xd7, 0x86, 0x77, 0x10, 0xd7,
+ 0x9b, 0x21, 0x80, 0x27, 0x2c, 0xa4, 0x96, 0x05, 0x39, 0x34, 0x07, 0x41,
+ 0x84, 0xde, 0x4d, 0x6c, 0x94, 0xe2, 0xf9, 0x41, 0x85, 0x37, 0x7c, 0x5e,
+ 0x35, 0x39, 0x38, 0x61, 0xed, 0xdd, 0xec, 0x00, 0x1e, 0x00, 0x60, 0x80,
+ 0x18, 0xe2, 0xfa, 0x51, 0xd2, 0x30, 0xcc, 0x47, 0xb9, 0x08, 0x64, 0xd2,
+ 0x53, 0x2d, 0xab, 0x4e, 0xe7, 0x37, 0x7c, 0x1d, 0xc7, 0x72, 0x27, 0xb8,
+ 0x84, 0x24, 0x9e, 0x81, 0xc7, 0x08, 0x1c, 0x1c, 0x40, 0xaf, 0x21, 0xfe,
+ 0x94, 0x10, 0x8b, 0x3b, 0xa7, 0x37, 0x0a, 0x7b, 0xa0, 0x19, 0xd8, 0x35,
+ 0x02, 0xdf, 0x13, 0x9c, 0x89, 0x57, 0x41, 0x29, 0x2c, 0x67, 0xb5, 0xeb,
+ 0xd5, 0x47, 0x28, 0x01, 0xe9, 0x4d, 0x83, 0x09, 0xb8, 0x0f, 0x24, 0x94,
+ 0x93, 0xc9, 0x05, 0xf6, 0xc1, 0x45, 0xb1, 0xe7, 0x6f, 0xee, 0xfb, 0xde,
+ 0x34, 0x03, 0x32, 0x80, 0xc8, 0x0c, 0x08, 0x68, 0xca, 0xe4, 0xa4, 0xb7,
+ 0xc7, 0xef, 0xb3, 0xef, 0x83, 0xef, 0x6f, 0xb2, 0x53, 0xb7, 0xc8, 0x4f,
+ 0xdf, 0x3e, 0x57, 0x36, 0xe9, 0x02, 0xa5, 0x38, 0xc4, 0xe1, 0x1c, 0x3a,
+ 0x60, 0x51, 0x2a, 0xfb, 0xda, 0x3c, 0xef, 0x02, 0x51, 0x60, 0x49, 0x21,
+ 0x5e, 0x7e, 0x50, 0x6a, 0xc0, 0xb1, 0x7d, 0x87, 0x21, 0x3f, 0x85, 0x6d,
+ 0xff, 0xbb, 0xc9, 0x49, 0x1d, 0xee, 0x21, 0xb8, 0x7e, 0xb8, 0xf7, 0x97,
+ 0x00, 0x70, 0xe0, 0x60, 0x9a, 0xee, 0x08, 0x7f, 0x6a, 0x70, 0x47, 0x04,
+ 0x28, 0xe1, 0x44, 0x57, 0xbd, 0x08, 0x60, 0x09, 0x80, 0x76, 0x43, 0x61,
+ 0x85, 0x72, 0xb7, 0x3d, 0x21, 0xbb, 0xa1, 0x81, 0x20, 0x0f, 0xb1, 0x7f,
+ 0x8a, 0x6d, 0x85, 0xeb, 0xc2, 0x10, 0x88, 0x48, 0x02, 0x81, 0x88, 0x0c,
+ 0x41, 0xd8, 0xd1, 0xff, 0xf7, 0xff, 0xb3, 0x67, 0xfd, 0x7e, 0xf3, 0x08,
+ 0x41, 0x9d, 0x0f, 0xfa, 0x9f, 0x33, 0x5e, 0x81, 0x0c, 0xbd, 0xf3, 0x65,
+ 0xdf, 0xa4, 0x00, 0x66, 0xa0, 0x03, 0xee, 0x00, 0x29, 0x4e, 0x13, 0xb9,
+ 0x49, 0xec, 0x17, 0xb7, 0x0e, 0xbd, 0x2b, 0xdc, 0xa0, 0x07, 0x64, 0xdc,
+ 0x1a, 0x43, 0x28, 0xac, 0xbc, 0x4c, 0xdd, 0x3c, 0xf2, 0x4a, 0x73, 0x61,
+ 0x44, 0x87, 0x71, 0x3a, 0xee, 0xbc, 0xc0, 0x77, 0x82, 0x76, 0x1c, 0x85,
+ 0xd8, 0x10, 0x94, 0x55, 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf7, 0x6b, 0x5c,
+ 0xd7, 0x4b, 0xce, 0xf5, 0xaf, 0x3b, 0xd0, 0xd3, 0xba, 0x5e, 0x77, 0xad,
+ 0x79, 0x9e, 0x86, 0x9d, 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0xb4, 0x5d,
+ 0x4f, 0x33, 0xd6, 0xbc, 0xef, 0x43, 0x4e, 0xe9, 0x79, 0xde, 0xb5, 0xe7,
+ 0x7a, 0x1a, 0x77, 0x4b, 0xce, 0xf5, 0xaf, 0x33, 0xd2, 0xd3, 0xba, 0x9e,
+ 0x67, 0xae, 0x79, 0x9e, 0x86, 0x9d, 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4,
+ 0x34, 0xee, 0xa7, 0x99, 0xeb, 0x5e, 0x67, 0xa5, 0xa2, 0xea, 0x79, 0x9e,
+ 0xb9, 0xe7, 0x7a, 0x1a, 0x77, 0x4b, 0xcc, 0xf5, 0xcf, 0x33, 0xd0, 0xd3,
+ 0xba, 0x9e, 0x67, 0xad, 0x79, 0xde, 0x96, 0x9d, 0xd2, 0xf3, 0x3d, 0x73,
+ 0xcc, 0xf4, 0x34, 0xee, 0xa7, 0x9d, 0xeb, 0x5e, 0x67, 0xa1, 0xa7, 0x75,
+ 0x3c, 0xcf, 0x5a, 0xf3, 0xbd, 0x2d, 0x17, 0x4b, 0xce, 0xf5, 0xaf, 0x3b,
+ 0xd0, 0xd3, 0xba, 0x5e, 0x77, 0xad, 0x79, 0x9e, 0x86, 0x9d, 0xd4, 0xf3,
+ 0x3d, 0x73, 0xcc, 0xf4, 0xb4, 0xee, 0xa7, 0x99, 0xeb, 0x5e, 0x77, 0xa1,
+ 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9, 0xe7, 0x7a,
+ 0xd7, 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd7, 0x3c, 0xcf, 0x43, 0x45,
+ 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0x34, 0xee, 0x97, 0x9d, 0xeb, 0x5e,
+ 0x77, 0xa5, 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9,
+ 0xe6, 0x7a, 0xca, 0x52, 0xd3, 0xb5, 0x79, 0xa9, 0x49, 0x45, 0xca, 0x52,
+ 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x00, 0x00, 0x00,
+ 0x01, 0x06, 0x43, 0xf1, 0x4f, 0x33, 0xd6, 0xbc, 0xef, 0x7e, 0xc4, 0xd7,
+ 0xcf, 0x5d, 0x2f, 0x3b, 0xd6, 0xbc, 0xcf, 0x43, 0x4e, 0xea, 0x79, 0xde,
+ 0xb5, 0xe6, 0x7a, 0x1a, 0x77, 0x53, 0xcc, 0xf5, 0xaf, 0x3b, 0xd2, 0xd3,
+ 0xad, 0xf9, 0x04, 0xce, 0xdf, 0xe0, 0xfc, 0x45, 0x27, 0xac, 0x3e, 0xb4,
+ 0x9b, 0x99, 0x3b, 0x8f, 0x57, 0x23, 0xe2, 0x2d, 0xd3, 0x71, 0x9f, 0x71,
+ 0xc4, 0x63, 0x48, 0x21, 0xd7, 0x94, 0x0d, 0x40, 0xd4, 0x7c, 0x69, 0x82,
+ 0x71, 0xd7, 0xcd, 0x60, 0x9c, 0x4e, 0xbd, 0x9e, 0xaf, 0x54, 0x7a, 0x97,
+ 0xa1, 0x48, 0x00, 0xb4, 0x9a, 0x18, 0x18, 0x3f, 0x8d, 0x4a, 0xd8, 0x20,
+ 0xa6, 0xfc, 0x4e, 0xfd, 0x91, 0xf0, 0xe4, 0xda, 0xd0, 0x58, 0xd4, 0x64,
+ 0xe7, 0x5e, 0xdd, 0x67, 0xae, 0xf3, 0xe0, 0x0f, 0x8a, 0x72, 0x59, 0x34,
+ 0x7f, 0x25, 0x21, 0x6a, 0x64, 0x3b, 0xfd, 0x8c, 0xfd, 0x2f, 0xb8, 0xf1,
+ 0x9a, 0xf4, 0x40, 0xa0, 0x60, 0x17, 0x58, 0x1e, 0x58, 0x7d, 0xc4, 0x4d,
+ 0x2d, 0x8a, 0x13, 0x7c, 0xa0, 0x13, 0x93, 0x40, 0x2c, 0x21, 0x16, 0x9c,
+ 0x7b, 0x32, 0x30, 0xf4, 0xf5, 0x6c, 0xb1, 0xfe, 0xf7, 0x28, 0xc4, 0xa0,
+ 0xcc, 0x83, 0xfe, 0xcb, 0xec, 0xcf, 0xcd, 0xec, 0x2f, 0xaf, 0xdc, 0x80,
+ 0x07, 0xa1, 0xa4, 0xb2, 0x68, 0x61, 0x33, 0x1c, 0x80, 0x14, 0xa5, 0x4e,
+ 0x29, 0x18, 0x52, 0xc2, 0x77, 0x01, 0xe5, 0xd8, 0xfe, 0xf3, 0xc0, 0xaf,
+ 0x59, 0x45, 0x00, 0x8f, 0x89, 0xf7, 0x41, 0x31, 0x0c, 0x57, 0xe3, 0xef,
+ 0xe6, 0x97, 0xd3, 0x11, 0xc0, 0x72, 0x08, 0xff, 0x84, 0xd0, 0x4b, 0xfc,
+ 0x4d, 0xf3, 0x4b, 0xea, 0x3b, 0xac, 0xb0, 0x47, 0xfc, 0x26, 0x82, 0x5f,
+ 0xe2, 0x68, 0x02, 0xab, 0x0c, 0x01, 0x1e, 0x23, 0x7b, 0x60, 0x1d, 0x12,
+ 0x78, 0x8b, 0xcf, 0xca, 0x01, 0xbe, 0x4a, 0x3b, 0xe4, 0x0c, 0x4f, 0x0d,
+ 0x4e, 0x01, 0x21, 0x5b, 0x71, 0xa9, 0x16, 0xd8, 0xec, 0xcb, 0xff, 0x6b,
+ 0xe9, 0xc0, 0x54, 0x01, 0xb9, 0x41, 0xa9, 0x0d, 0x0d, 0xc4, 0xc0, 0x2e,
+ 0x92, 0xd3, 0xf3, 0x99, 0xbf, 0xff, 0x28, 0xe7, 0x61, 0xd7, 0x89, 0x00,
+ 0x6e, 0x05, 0x4b, 0x00, 0xd0, 0x01, 0xd0, 0x40, 0x42, 0x40, 0x35, 0x4b,
+ 0x3e, 0x3c, 0x02, 0xc2, 0x97, 0x97, 0xbf, 0x24, 0xfe, 0xfb, 0x81, 0x24,
+ 0xdf, 0x6b, 0xbe, 0x60, 0x03, 0x04, 0x24, 0x06, 0x01, 0x8a, 0xff, 0x74,
+ 0xaf, 0xc1, 0x35, 0x8b, 0xeb, 0x32, 0xbc, 0xfc, 0xd6, 0x4c, 0xe0, 0x16,
+ 0x90, 0x80, 0x7a, 0x82, 0x21, 0x07, 0x5b, 0xca, 0x01, 0xca, 0x04, 0xf2,
+ 0x37, 0xbd, 0x80, 0x06, 0x45, 0xf0, 0x32, 0x30, 0x7e, 0x23, 0x5f, 0x1c,
+ 0x49, 0x4c, 0x1a, 0xe6, 0x33, 0x87, 0x9c, 0x46, 0xba, 0x13, 0x9d, 0x70,
+ 0x65, 0x63, 0x8d, 0x24, 0x8e, 0x23, 0xda, 0x03, 0x3e, 0xe5, 0x21, 0xbe,
+ 0x3b, 0x4c, 0x43, 0x48, 0xc0, 0xc2, 0xf8, 0xed, 0xef, 0xaa, 0x64, 0x6d,
+ 0x99, 0x6a, 0x1d, 0xfe, 0x22, 0xde, 0xab, 0xed, 0x96, 0xf6, 0xe8, 0x43,
+ 0xd5, 0x3f, 0x1c, 0x7c, 0x3f, 0x49, 0x7d, 0x98, 0x95, 0xb0, 0x1f, 0x0d,
+ 0x04, 0x9f, 0xb0, 0xd0, 0x01, 0x8d, 0xc2, 0x01, 0xd0, 0x05, 0xe5, 0x80,
+ 0xe9, 0x3b, 0x06, 0xfe, 0x59, 0x33, 0x9e, 0x9e, 0x49, 0x0c, 0x16, 0x2d,
+ 0x03, 0xcd, 0xc7, 0xae, 0xac, 0x92, 0x92, 0xad, 0xfe, 0xe2, 0xec, 0xd2,
+ 0x4c, 0xfb, 0x56, 0xfe, 0x09, 0x25, 0xa1, 0x07, 0xf6, 0xbd, 0x59, 0x60,
+ 0x55, 0xd4, 0x80, 0xbe, 0x03, 0x5b, 0xc9, 0xa5, 0x18, 0xbc, 0xde, 0xfa,
+ 0x71, 0x68, 0xe5, 0x76, 0xe1, 0xdc, 0x78, 0x0b, 0xe8, 0x76, 0xab, 0x35,
+ 0x53, 0xab, 0x29, 0xcd, 0xff, 0xbf, 0xfc, 0xff, 0xc7, 0xfa, 0x3d, 0x6b,
+ 0xcc, 0xf7, 0xab, 0xdf, 0xf7, 0xf7, 0x93, 0x75, 0x3c, 0xef, 0x5a, 0xf3,
+ 0x3c, 0x9a, 0x77, 0x53, 0xcc, 0xf5, 0xcf, 0x33, 0xd0, 0xd1, 0x75, 0x3c,
+ 0xcf, 0x5c, 0xf3, 0x3d, 0x2d, 0x3b, 0xa5, 0xe7, 0x7a, 0xd7, 0x9d, 0xe8,
+ 0x69, 0xdd, 0x2f, 0x3b, 0xd6, 0xbc, 0xcf, 0x43, 0x4e, 0xea, 0x79, 0xde,
+ 0xb1, 0xe7, 0x7a, 0x5a, 0x77, 0x53, 0xcc, 0xf5, 0xaf, 0x3b, 0xd0, 0xd3,
+ 0xba, 0x5e, 0x67, 0xae, 0x79, 0x9e, 0x86, 0x8b, 0xa9, 0xe7, 0x7a, 0xd7,
+ 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd6, 0xbc, 0xef, 0x43, 0x4e, 0xe9,
+ 0x79, 0xde, 0xb5, 0xe7, 0x7a, 0x1a, 0x77, 0x4b, 0xce, 0xf5, 0xaf, 0x33,
+ 0xd2, 0xd3, 0xba, 0x9e, 0x67, 0xad, 0x79, 0xde, 0x86, 0x9d, 0xd2, 0xf3,
+ 0xbd, 0x6b, 0xce, 0xf4, 0x34, 0x5d, 0x2f, 0x3b, 0xd6, 0xbc, 0xcf, 0x4b,
+ 0x4e, 0xea, 0x79, 0xde, 0xb5, 0xe6, 0x7a, 0x1a, 0x77, 0x53, 0xcc, 0xf5,
+ 0xcf, 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x67, 0xad, 0x79, 0xde, 0x96, 0x9d,
+ 0xd2, 0xf3, 0xbd, 0x6b, 0xcc, 0xf4, 0x34, 0xee, 0xa7, 0x99, 0xeb, 0x9e,
+ 0x67, 0xa1, 0xa7, 0x75, 0x3c, 0xcf, 0x5c, 0xf3, 0x3d, 0x2d, 0x17, 0x53,
+ 0xcc, 0xf5, 0xaf, 0x3b, 0xd0, 0xd3, 0xba, 0x5e, 0x77, 0xad, 0x78, 0xd2,
+ 0xd3, 0xba, 0xde, 0x67, 0x9e, 0x94, 0xce, 0xc4, 0x69, 0x49, 0x45, 0xca,
+ 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94,
+ 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x40, 0x00, 0x00,
+ 0x01, 0x07, 0x4b, 0xf3, 0x2f, 0x33, 0xd6, 0xbc, 0xef, 0x7e, 0xb2, 0xd7,
+ 0x83, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0xbd, 0x0d, 0x3b, 0xa5, 0xe7, 0x7a,
+ 0xd7, 0x9d, 0xe9, 0x69, 0xdd, 0x2f, 0x3b, 0xd6, 0xbc, 0xcf, 0x43, 0x4e,
+ 0xd3, 0xb7, 0xdf, 0x76, 0xfb, 0xab, 0xee, 0x77, 0xbc, 0x80, 0x06, 0x41,
+ 0xa0, 0x64, 0x85, 0xb7, 0x3c, 0xae, 0x4a, 0xef, 0xf7, 0xea, 0x3b, 0xf6,
+ 0x35, 0x28, 0x6e, 0x1f, 0x7b, 0x47, 0xb9, 0x40, 0x19, 0x06, 0x92, 0x88,
+ 0x63, 0x3f, 0x50, 0x6e, 0x6d, 0x80, 0x7a, 0x87, 0xea, 0x12, 0x87, 0x71,
+ 0x1a, 0xf3, 0x40, 0xa7, 0x6f, 0xf0, 0xf2, 0x3e, 0xbb, 0x48, 0x68, 0x74,
+ 0x38, 0xea, 0xe3, 0x7a, 0x70, 0xc4, 0xfd, 0x87, 0xbe, 0x0f, 0x03, 0xb7,
+ 0x83, 0xd8, 0x62, 0x36, 0x1d, 0xad, 0xa9, 0x28, 0x69, 0x68, 0x48, 0xe7,
+ 0x0f, 0xb4, 0x90, 0xd2, 0xc8, 0x17, 0xd5, 0x79, 0x3b, 0x5e, 0x8b, 0xbb,
+ 0x55, 0x3e, 0xc3, 0x86, 0x80, 0xdc, 0xb2, 0xc3, 0x40, 0x25, 0x4f, 0x65,
+ 0x01, 0xec, 0xac, 0x27, 0x75, 0xa7, 0x09, 0x8b, 0xd7, 0xab, 0x66, 0xca,
+ 0xd8, 0xc8, 0x1f, 0x7a, 0xff, 0x92, 0xcb, 0x71, 0xfe, 0xf2, 0x19, 0x90,
+ 0xc2, 0xaf, 0xe4, 0xf7, 0xde, 0x40, 0x4e, 0x43, 0x0d, 0x03, 0x21, 0xa1,
+ 0x85, 0x27, 0x14, 0x12, 0x5f, 0x4a, 0x59, 0xd2, 0xb0, 0xd2, 0xd4, 0x83,
+ 0x31, 0xc7, 0xf1, 0xea, 0xbe, 0x0f, 0x7d, 0x30, 0x10, 0x46, 0x8b, 0x48,
+ 0x15, 0x26, 0x96, 0x94, 0x95, 0x90, 0x1b, 0xdd, 0x5d, 0x3d, 0x2e, 0x37,
+ 0xf5, 0xee, 0x8d, 0xb2, 0xbb, 0x2b, 0x99, 0x7c, 0xb0, 0x09, 0x80, 0x2c,
+ 0xe1, 0xb8, 0x02, 0xd2, 0x46, 0xef, 0x7b, 0xa3, 0x7a, 0x32, 0x58, 0xfa,
+ 0xf3, 0xd6, 0xb0, 0x0d, 0xd9, 0x09, 0xe0, 0x2a, 0xe3, 0x80, 0xe5, 0xf4,
+ 0x94, 0xa3, 0xa3, 0xfd, 0xcc, 0x55, 0xf0, 0xa0, 0x03, 0xce, 0x3f, 0x5c,
+ 0x20, 0x03, 0xc2, 0x11, 0xfd, 0x0f, 0xc4, 0xf6, 0xbe, 0x5c, 0xbe, 0x51,
+ 0x9e, 0xd3, 0x57, 0xff, 0x58, 0x01, 0xd7, 0x25, 0x7c, 0x5f, 0x17, 0xaf,
+ 0x90, 0xa0, 0x87, 0x8b, 0x4f, 0xc7, 0x0e, 0x89, 0x34, 0x98, 0x35, 0x86,
+ 0x66, 0xd8, 0xca, 0xdc, 0x4c, 0x28, 0x31, 0x69, 0x5f, 0xc1, 0x5a, 0xcc,
+ 0x0b, 0x74, 0x0b, 0xad, 0x6f, 0x54, 0xa0, 0x03, 0x72, 0x68, 0xc2, 0x90,
+ 0x19, 0xba, 0xcb, 0x4e, 0x70, 0x15, 0x21, 0x7c, 0x2c, 0xe0, 0xfb, 0xdb,
+ 0xbc, 0xa4, 0x32, 0x1f, 0x01, 0xd9, 0x37, 0x93, 0x7b, 0xe7, 0x52, 0x37,
+ 0x03, 0xc8, 0x20, 0xf3, 0xf8, 0x76, 0x32, 0xd2, 0xf7, 0xe8, 0xe4, 0xdf,
+ 0xbf, 0x6c, 0x72, 0x15, 0x78, 0x41, 0x88, 0x19, 0xae, 0xa7, 0x99, 0xeb,
+ 0x9e, 0x67, 0xba, 0x5a, 0xc2, 0xb4, 0xf1, 0x00, 0x3a, 0x0d, 0x01, 0x27,
+ 0x01, 0x11, 0x00, 0x81, 0x79, 0xc2, 0x68, 0x60, 0x19, 0x43, 0x1a, 0x67,
+ 0x17, 0x7d, 0x75, 0xcd, 0xc7, 0xe5, 0xe1, 0x37, 0xc8, 0x09, 0x81, 0xb8,
+ 0x35, 0x0e, 0x1d, 0xc4, 0xde, 0x7d, 0xea, 0x27, 0x35, 0x55, 0xf5, 0xbe,
+ 0xf9, 0xf7, 0xdf, 0x7c, 0xaf, 0xb9, 0xfb, 0xe3, 0xf4, 0xef, 0x78, 0xd0,
+ 0x07, 0x20, 0x3a, 0x19, 0xc0, 0x2d, 0x46, 0x3d, 0xb1, 0x6d, 0x8d, 0x3b,
+ 0x24, 0x89, 0xc3, 0x85, 0xde, 0xe9, 0xed, 0xfa, 0x1a, 0xe1, 0x42, 0x46,
+ 0xeb, 0xa5, 0xe7, 0x7a, 0xd7, 0x9d, 0xe6, 0xd6, 0x77, 0x4b, 0xce, 0xf5,
+ 0xaf, 0x33, 0xd2, 0xd3, 0xba, 0x9e, 0x67, 0xae, 0x79, 0x9e, 0x86, 0x9d,
+ 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0x34, 0xee, 0x97, 0x9d, 0xeb, 0x5e,
+ 0x77, 0xa5, 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x17, 0x53,
+ 0xcc, 0xf5, 0xcf, 0x33, 0xd0, 0xd3, 0xba, 0x5e, 0x77, 0xad, 0x79, 0x9e,
+ 0x96, 0x9d, 0xd4, 0xf3, 0xbd, 0x6b, 0xcc, 0xf4, 0x34, 0xee, 0xa7, 0x99,
+ 0xeb, 0x5e, 0x77, 0xa1, 0xa7, 0x75, 0x3c, 0xcf, 0x5a, 0xf3, 0xbd, 0x2d,
+ 0x3b, 0xa5, 0xe7, 0x7a, 0xd7, 0x99, 0xe8, 0x69, 0xdd, 0x4f, 0x3b, 0xd6,
+ 0xbc, 0xcf, 0x43, 0x45, 0xd4, 0xf3, 0x3d, 0x73, 0xcc, 0xf4, 0xb4, 0xee,
+ 0xa7, 0x99, 0xeb, 0x9e, 0x67, 0xa1, 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3,
+ 0x3d, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xe7, 0x99, 0xe9, 0x69, 0xdd, 0x4f,
+ 0x33, 0xd7, 0x3c, 0xcf, 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb5, 0xe7, 0x7a,
+ 0x1a, 0x77, 0x53, 0xcc, 0xf5, 0xb1, 0xa5, 0xa2, 0xeb, 0x79, 0x9e, 0x6a,
+ 0x4a, 0x77, 0x29, 0x4a, 0x4a, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0x80, 0x00, 0x00, 0x01, 0x08, 0x53, 0xe4, 0x3c, 0xef,
+ 0x5a, 0xf3, 0x3d, 0xfa, 0x83, 0x5e, 0x25, 0xd4, 0xf3, 0x3d, 0x6b, 0xce,
+ 0xf4, 0xb4, 0xee, 0xa7, 0x99, 0xeb, 0x5e, 0x77, 0xa1, 0xa7, 0x74, 0xbc,
+ 0xef, 0x69, 0x49, 0xc1, 0x41, 0xf9, 0xd7, 0x8c, 0x67, 0xca, 0x73, 0x2d,
+ 0x3c, 0x6a, 0x0b, 0x42, 0x3a, 0x73, 0xaf, 0xf0, 0x1e, 0xa0, 0xed, 0xc7,
+ 0x39, 0xc9, 0x53, 0x29, 0x2c, 0x65, 0xc4, 0x51, 0x30, 0x6a, 0x3f, 0x7c,
+ 0xa3, 0xed, 0x7a, 0x5b, 0xb5, 0xf3, 0xde, 0x61, 0xbd, 0x1f, 0x7c, 0x7e,
+ 0xfb, 0xe3, 0x17, 0x96, 0xb1, 0x43, 0xed, 0x43, 0x06, 0x97, 0xca, 0x61,
+ 0xa4, 0x95, 0x30, 0xd7, 0x00, 0xa3, 0xa4, 0xef, 0xbe, 0xed, 0xce, 0x54,
+ 0xe4, 0x81, 0x9b, 0xab, 0x8c, 0xef, 0x8e, 0x61, 0x9d, 0x95, 0x9b, 0x33,
+ 0xee, 0x3b, 0x65, 0x3e, 0xcb, 0xb9, 0x30, 0x14, 0xf9, 0x6e, 0xbd, 0xed,
+ 0x49, 0x6e, 0xaa, 0xf7, 0xe7, 0x00, 0x37, 0x28, 0x7e, 0xbd, 0x70, 0x6a,
+ 0x72, 0x52, 0xa5, 0xec, 0x47, 0xba, 0xe9, 0xcc, 0x93, 0x42, 0xb6, 0x23,
+ 0x4e, 0xc4, 0x63, 0xc3, 0x88, 0x26, 0x5e, 0x5b, 0x5d, 0x95, 0x55, 0x2f,
+ 0x11, 0xac, 0xbb, 0x5a, 0x12, 0x35, 0x1b, 0x8f, 0xdb, 0x85, 0xd4, 0x96,
+ 0x8e, 0x82, 0x5f, 0xe8, 0x6c, 0x4a, 0x42, 0x50, 0x96, 0xc8, 0x74, 0xed,
+ 0x94, 0xf8, 0xa0, 0x97, 0xcf, 0x97, 0xff, 0x37, 0x1d, 0x7a, 0xa1, 0x84,
+ 0xce, 0x97, 0x15, 0x71, 0x25, 0x2c, 0x1f, 0x5c, 0x7c, 0xd8, 0x02, 0xd0,
+ 0xc0, 0x27, 0x82, 0xf4, 0xa0, 0x37, 0x0c, 0x02, 0x78, 0x2f, 0x5f, 0x54,
+ 0xea, 0xce, 0x24, 0x89, 0x64, 0x4e, 0x6c, 0xe7, 0x2c, 0xdc, 0xc0, 0x6c,
+ 0x4d, 0xe5, 0x30, 0xab, 0xd0, 0x6a, 0xbf, 0xe6, 0xc0, 0x07, 0xa4, 0x20,
+ 0x45, 0xfc, 0x40, 0x5e, 0xad, 0xe0, 0x27, 0x21, 0x60, 0x12, 0xa3, 0x88,
+ 0xee, 0x46, 0xbe, 0x9b, 0xca, 0x01, 0x42, 0x3e, 0x4a, 0xfa, 0x0a, 0xe9,
+ 0x14, 0xfb, 0x2f, 0x61, 0xce, 0x78, 0x1b, 0xb5, 0xa7, 0xab, 0x88, 0xab,
+ 0xb2, 0x19, 0x44, 0xfa, 0x72, 0x37, 0xaf, 0xbe, 0x7b, 0xc0, 0xae, 0x33,
+ 0x7e, 0x4e, 0xbd, 0x8a, 0x53, 0xd2, 0x78, 0x55, 0x52, 0x76, 0xce, 0xc6,
+ 0x71, 0xd9, 0x41, 0x56, 0xaf, 0x82, 0x1d, 0x66, 0x99, 0x87, 0x8f, 0x3e,
+ 0xcd, 0x74, 0x55, 0x57, 0xbc, 0xcf, 0x56, 0x82, 0x93, 0xd0, 0x35, 0x08,
+ 0x25, 0x81, 0x76, 0xfb, 0xed, 0xce, 0xdb, 0xe3, 0xd1, 0xd8, 0xd5, 0xe6,
+ 0xe2, 0xd5, 0x5e, 0x19, 0x89, 0x68, 0x2d, 0xb3, 0xfd, 0xbb, 0x65, 0x25,
+ 0xf0, 0xd6, 0x01, 0xee, 0xea, 0x1e, 0xea, 0xff, 0xb2, 0xae, 0xc0, 0x0b,
+ 0x0e, 0x59, 0xf7, 0x38, 0xd3, 0xee, 0x3c, 0xcf, 0x63, 0x42, 0x30, 0x0d,
+ 0xc0, 0xa2, 0x3a, 0x18, 0x97, 0xf0, 0xd2, 0x94, 0xa6, 0x2f, 0x20, 0xe3,
+ 0xb6, 0xe8, 0x6e, 0x31, 0xa6, 0x26, 0x94, 0x18, 0x51, 0x48, 0x25, 0x7d,
+ 0xc0, 0xba, 0x50, 0xf9, 0x05, 0x21, 0x94, 0x48, 0xf8, 0xa5, 0x3a, 0x9f,
+ 0x7e, 0x22, 0x90, 0x0b, 0x0f, 0x15, 0x50, 0xd3, 0xaf, 0x63, 0xdc, 0x80,
+ 0x10, 0x00, 0x9c, 0x00, 0xf0, 0x35, 0xff, 0x02, 0xc9, 0x51, 0x62, 0x87,
+ 0x24, 0x38, 0xd1, 0x42, 0x2b, 0x80, 0xc0, 0x46, 0x74, 0x36, 0xe4, 0x20,
+ 0xc4, 0xe4, 0xb6, 0x40, 0x17, 0x25, 0x6e, 0x78, 0xc7, 0x4b, 0x9d, 0xdf,
+ 0xf3, 0xff, 0x32, 0x25, 0x13, 0x06, 0x90, 0x89, 0x79, 0x09, 0xfc, 0x6a,
+ 0x70, 0x40, 0x61, 0x49, 0x03, 0xc8, 0x35, 0x39, 0xf0, 0x75, 0x8e, 0x26,
+ 0x32, 0x4f, 0xaf, 0xfd, 0xf5, 0x77, 0xf3, 0x2e, 0x1a, 0x19, 0xf3, 0x0d,
+ 0xc1, 0x7a, 0xfa, 0xef, 0x6d, 0xfe, 0xdd, 0xf0, 0xfa, 0xb2, 0xb6, 0xfb,
+ 0xbf, 0x02, 0x4b, 0x6d, 0xcf, 0x71, 0xf6, 0x84, 0xa9, 0x3e, 0x8f, 0x95,
+ 0x5e, 0xaa, 0xae, 0x79, 0x9e, 0xb9, 0xe6, 0x7b, 0xb5, 0xae, 0x5b, 0xa5,
+ 0xe7, 0x7a, 0xd7, 0x99, 0xe8, 0x69, 0xdd, 0x4f, 0x3b, 0xd6, 0xbc, 0xcf,
+ 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb9, 0xe6, 0x7a, 0x5a, 0x2e, 0xa7, 0x99,
+ 0xeb, 0x5e, 0x77, 0xa1, 0xa7, 0x75, 0x3c, 0xcf, 0x5a, 0xf3, 0x3d, 0x0d,
+ 0x3b, 0xa9, 0xe6, 0x7a, 0xe7, 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd6,
+ 0xbc, 0xef, 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb5, 0xe7, 0x7a, 0x5a, 0x77,
+ 0x4b, 0xce, 0xf5, 0xaf, 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x67, 0xae, 0x79,
+ 0x9e, 0x86, 0x8b, 0xa9, 0xe6, 0x7a, 0xd7, 0x9d, 0xe8, 0x69, 0xdd, 0x2f,
+ 0x3b, 0xd6, 0xbc, 0xef, 0x4b, 0x4e, 0xe9, 0x79, 0xde, 0xb5, 0xe6, 0x7a,
+ 0x1a, 0x77, 0x53, 0xcc, 0xf5, 0xcf, 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x67,
+ 0xad, 0x79, 0xde, 0x96, 0x9d, 0xd4, 0xf3, 0x3d, 0x64, 0x69, 0x68, 0xb4,
+ 0x79, 0xa3, 0x4a, 0x67, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17,
+ 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca,
+ 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94,
+ 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29,
+ 0x11, 0x72, 0x94, 0xa4, 0x44, 0x00, 0x00, 0x01, 0x09, 0x53, 0xa1, 0xe6,
+ 0x7a, 0xd7, 0x9d, 0xef, 0xd2, 0x1a, 0xf1, 0xee, 0x97, 0x9d, 0xeb, 0x5e,
+ 0x67, 0xa1, 0xa7, 0x75, 0x3c, 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9,
+ 0xed, 0x08, 0x46, 0x41, 0xc1, 0x46, 0x6c, 0x3b, 0x0a, 0xa3, 0xcc, 0xf6,
+ 0x59, 0xf0, 0x7c, 0xed, 0xf1, 0x5b, 0x66, 0xca, 0x5b, 0x88, 0x1c, 0xc6,
+ 0x28, 0xea, 0xc4, 0x14, 0x84, 0x66, 0x3c, 0xf3, 0xf6, 0x34, 0xfc, 0xdb,
+ 0x6c, 0xb3, 0x54, 0xba, 0xa7, 0x9d, 0xec, 0x46, 0xa5, 0x99, 0xfa, 0xeb,
+ 0x6d, 0x76, 0xe2, 0x99, 0x23, 0x46, 0xff, 0xc4, 0x21, 0x62, 0x7e, 0x46,
+ 0xe4, 0xf8, 0xf2, 0xb7, 0xee, 0xfc, 0x42, 0x8d, 0x3d, 0x6c, 0xf8, 0x3b,
+ 0xea, 0xb7, 0x9d, 0xec, 0xc9, 0x69, 0x77, 0x7e, 0xe7, 0x4d, 0xb5, 0xd4,
+ 0xf6, 0xb2, 0x56, 0x0e, 0x66, 0x66, 0x43, 0x30, 0xe3, 0x9d, 0x85, 0x3d,
+ 0x5b, 0xcc, 0xf1, 0xbf, 0x41, 0xdd, 0x9e, 0x47, 0xd8, 0x65, 0xbd, 0x68,
+ 0xcc, 0xe3, 0xce, 0xcc, 0xa3, 0x0e, 0x5b, 0x3f, 0x61, 0x7e, 0x0f, 0x33,
+ 0xd1, 0x92, 0x9c, 0x6f, 0xa9, 0xb5, 0xbf, 0x2b, 0x2f, 0xaf, 0x7e, 0xa7,
+ 0x14, 0xb5, 0x08, 0x5f, 0xa9, 0x7a, 0xe7, 0x99, 0xe4, 0xff, 0x9f, 0xe2,
+ 0xd4, 0x3f, 0x81, 0x17, 0x62, 0x75, 0x6a, 0x50, 0xea, 0x75, 0x2d, 0x4c,
+ 0x8e, 0x79, 0xe7, 0xa3, 0xc1, 0xe6, 0x7b, 0x2c, 0x94, 0xe3, 0x66, 0xda,
+ 0xd7, 0x81, 0xb3, 0xbb, 0x89, 0x7d, 0xe2, 0x1f, 0xc4, 0x89, 0xac, 0x79,
+ 0x9e, 0x4f, 0xc7, 0x9d, 0x3b, 0x53, 0x18, 0x0e, 0x11, 0x9b, 0x4c, 0x1f,
+ 0xcf, 0x7e, 0x2f, 0xaf, 0xac, 0x3f, 0xce, 0xf3, 0x3d, 0x0f, 0xc7, 0xf9,
+ 0xdd, 0x7f, 0xf1, 0xe2, 0x8e, 0xc7, 0x0e, 0x76, 0x72, 0x7c, 0xcf, 0xce,
+ 0x75, 0x0e, 0x64, 0x75, 0x8f, 0x5e, 0xf5, 0x8f, 0x3b, 0xd0, 0xe9, 0x1f,
+ 0x36, 0xd6, 0x86, 0x35, 0x1e, 0xb5, 0xe6, 0x79, 0x2e, 0x2e, 0xa7, 0x99,
+ 0xeb, 0x9e, 0x67, 0x86, 0x8b, 0xa9, 0xe6, 0x7a, 0xd7, 0x9d, 0xe9, 0x69,
+ 0xdd, 0x4f, 0x33, 0xd6, 0xbc, 0xcf, 0x43, 0x45, 0xd4, 0xf3, 0x3d, 0x73,
+ 0xcc, 0xf4, 0x34, 0xee, 0xa7, 0x99, 0xeb, 0x9e, 0x67, 0xa5, 0xa7, 0x75,
+ 0x3c, 0xcf, 0x5a, 0xf3, 0xbd, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xd7, 0x99,
+ 0xe8, 0x69, 0xdd, 0x4f, 0x3b, 0xd6, 0xbc, 0xcf, 0x43, 0x4e, 0xea, 0x79,
+ 0x9e, 0xb9, 0xe6, 0x7a, 0x5a, 0x2e, 0xa7, 0x99, 0xeb, 0x5e, 0x77, 0xa1,
+ 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0xbd, 0x0d, 0x3b, 0xa5, 0xe7, 0x7a,
+ 0xd7, 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd7, 0x3c, 0x68, 0x69, 0xdd,
+ 0x6f, 0x33, 0xd6, 0x52, 0x99, 0xda, 0xbc, 0xd4, 0xa4, 0xa2, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00,
+ 0x01, 0x0a, 0x53, 0xd0, 0xf3, 0xbd, 0x6b, 0xcc, 0xf7, 0xdf, 0xb5, 0xe5,
+ 0x5d, 0x4f, 0x33, 0xd6, 0xbc, 0xef, 0x43, 0x45, 0xd2, 0xf3, 0xbd, 0x6b,
+ 0xce, 0xf4, 0xb4, 0xee, 0x97, 0x9d, 0xeb, 0x5e, 0x67, 0xa1, 0xa7, 0x75,
+ 0x3c, 0xcf, 0x5c, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xe7, 0x99,
+ 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd6, 0xbc, 0xcf, 0x43, 0x4e, 0xea, 0x79,
+ 0xde, 0xb5, 0xe6, 0x7a, 0x1a, 0x77, 0x53, 0xcc, 0xf5, 0xcf, 0x33, 0xd2,
+ 0xd1, 0x75, 0x3c, 0xcf, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b, 0xad, 0xe6, 0x7a,
+ 0xd7, 0x99, 0xe8, 0x69, 0xdd, 0x4f, 0x33, 0xd7, 0x3c, 0xcf, 0x4b, 0x4e,
+ 0xea, 0x79, 0x9e, 0xb5, 0xe7, 0x7a, 0x1a, 0x77, 0x53, 0xcc, 0xf5, 0xaf,
+ 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x77, 0xad, 0x79, 0x9e, 0x96, 0x8b, 0xa9,
+ 0xe6, 0x7a, 0xe7, 0x99, 0xe8, 0x69, 0xdd, 0x4f, 0x33, 0xd6, 0xbc, 0xef,
+ 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb5, 0xe7, 0x7a, 0x5a, 0x77, 0x4b, 0xce,
+ 0xf5, 0xaf, 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x67, 0xad, 0x79, 0xde, 0x86,
+ 0x9d, 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0xb4, 0xee, 0x97, 0x9d, 0xeb,
+ 0x5e, 0x77, 0xa1, 0xa2, 0xe9, 0x79, 0xde, 0xb5, 0xe6, 0x7a, 0x1a, 0x77,
+ 0x53, 0xcc, 0xf5, 0xcf, 0x1a, 0x5a, 0x77, 0x5b, 0xcc, 0xf3, 0xd2, 0x99,
+ 0xd8, 0x8d, 0x29, 0x28, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x20, 0x00, 0x00, 0x01, 0x0b, 0x53, 0xeb, 0xbc, 0xef,
+ 0x5a, 0xf3, 0xbd, 0xf6, 0xcd, 0x79, 0x97, 0x4b, 0xce, 0xf5, 0xaf, 0x33,
+ 0xd2, 0xd3, 0xba, 0x9e, 0x67, 0xae, 0x79, 0x9e, 0x86, 0x9d, 0xd4, 0xf3,
+ 0x3d, 0x6b, 0xce, 0xf4, 0x34, 0xee, 0xa7, 0x99, 0xeb, 0x5e, 0x67, 0xa5,
+ 0xa7, 0x75, 0x3c, 0xcf, 0x5c, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a,
+ 0xd7, 0x9d, 0xe8, 0x68, 0xba, 0x9e, 0x67, 0xad, 0x79, 0xde, 0x96, 0x9d,
+ 0xd2, 0xf3, 0xbd, 0x6b, 0xcc, 0xf4, 0x34, 0xee, 0xa7, 0x99, 0xeb, 0x5e,
+ 0x77, 0xa1, 0xa7, 0x75, 0x3c, 0xcf, 0x5a, 0xf3, 0xbd, 0x2d, 0x3b, 0xa5,
+ 0xe7, 0x7a, 0xd7, 0x9d, 0xe8, 0x69, 0xdd, 0x2f, 0x3b, 0xd6, 0xbc, 0xcf,
+ 0x43, 0x45, 0xd4, 0xf3, 0x3d, 0x73, 0xcc, 0xf4, 0xb4, 0xee, 0xa7, 0x99,
+ 0xeb, 0x5e, 0x77, 0xa1, 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0x3d, 0x0d,
+ 0x3b, 0xa9, 0xe7, 0x7a, 0xd7, 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33, 0xd6,
+ 0xbc, 0xef, 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb5, 0xe7, 0x7a, 0x1a, 0x77,
+ 0x4b, 0xce, 0xf5, 0xaf, 0x33, 0xd2, 0xd3, 0xba, 0x9e, 0x77, 0xac, 0x9a,
+ 0x86, 0x8b, 0xad, 0xe6, 0x79, 0xa9, 0x29, 0xd8, 0x8d, 0x29, 0x28, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x88, 0x00, 0x00,
+ 0x01, 0x0c, 0x53, 0xf4, 0xef, 0x33, 0xd6, 0xbc, 0xef, 0x7d, 0x73, 0x5e,
+ 0x7d, 0xd2, 0xf3, 0xbd, 0x6b, 0xce, 0xf4, 0x34, 0xee, 0x97, 0x99, 0xeb,
+ 0x9e, 0x67, 0xa1, 0xa7, 0x75, 0x3c, 0xef, 0x58, 0xf3, 0xbd, 0x2d, 0x3b,
+ 0xa9, 0xe6, 0x7a, 0xd7, 0x9d, 0xe8, 0x68, 0xba, 0x5e, 0x77, 0xad, 0x79,
+ 0x9e, 0x86, 0x9d, 0xd4, 0xf3, 0xbd, 0x6b, 0xcc, 0xf4, 0xb4, 0xee, 0xa7,
+ 0x99, 0xeb, 0x5e, 0x77, 0xa1, 0xa7, 0x74, 0xbc, 0xef, 0x5a, 0xf3, 0xbd,
+ 0x0d, 0x3b, 0xa5, 0xe7, 0x7a, 0xd7, 0x99, 0xe9, 0x69, 0xdd, 0x4f, 0x33,
+ 0xd7, 0x3c, 0xcf, 0x43, 0x45, 0xd4, 0xf3, 0x3d, 0x6b, 0xce, 0xf4, 0x34,
+ 0xee, 0x97, 0x9d, 0xeb, 0x5e, 0x67, 0xa5, 0xa7, 0x75, 0x3c, 0xef, 0x5a,
+ 0xf3, 0x3d, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xe7, 0x99, 0xe8, 0x69, 0xdd,
+ 0x4f, 0x33, 0xd6, 0xbc, 0xef, 0x4b, 0x4e, 0xea, 0x79, 0x9e, 0xb5, 0xe6,
+ 0x7a, 0x1a, 0x77, 0x53, 0xce, 0xf5, 0x91, 0xa5, 0xa2, 0xd1, 0xe6, 0x8d,
+ 0x29, 0x9d, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29,
+ 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44,
+ 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17,
+ 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca,
+ 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94,
+ 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29,
+ 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44,
+ 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17,
+ 0x29, 0x4a, 0x44, 0x40, 0x00, 0x00, 0x01, 0x0d, 0x53, 0xf6, 0xcf, 0x3b,
+ 0xd6, 0x3c, 0xef, 0x7d, 0x2b, 0x5c, 0x57, 0x53, 0xcc, 0xf5, 0xaf, 0x3b,
+ 0xd0, 0xd3, 0xba, 0x5e, 0x77, 0xad, 0x79, 0x9e, 0x96, 0x8b, 0xa9, 0xe7,
+ 0x7a, 0xd7, 0x99, 0xe8, 0x69, 0xdd, 0x4f, 0x33, 0xd6, 0xbc, 0xef, 0x43,
+ 0x4e, 0xe9, 0x79, 0xde, 0xb5, 0xe7, 0x7a, 0x5a, 0x77, 0x4b, 0xce, 0xf5,
+ 0xaf, 0x33, 0xd0, 0xd3, 0xba, 0x9e, 0x67, 0xae, 0x79, 0x9e, 0x86, 0x9d,
+ 0xd4, 0xf3, 0x3d, 0x73, 0xcc, 0xf4, 0xb4, 0xee, 0xa7, 0x99, 0xeb, 0x5e,
+ 0x77, 0xa1, 0xa2, 0xe9, 0x79, 0xde, 0xb5, 0xe6, 0x7a, 0x1a, 0x77, 0x53,
+ 0xcc, 0xf5, 0xcf, 0x33, 0xd2, 0xd3, 0xba, 0x9e, 0x67, 0xae, 0x79, 0x9e,
+ 0x86, 0x9d, 0xd4, 0xf3, 0x3d, 0x6b, 0xcc, 0xf4, 0x34, 0xee, 0xa7, 0x9d,
+ 0xeb, 0x29, 0x4c, 0xed, 0x5e, 0x31, 0xa4, 0xa2, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x88, 0x00, 0x00, 0x01,
+ 0x0e, 0x53, 0xfa, 0x2b, 0xce, 0xf5, 0xaf, 0x33, 0xde, 0xe3, 0x5c, 0xb7,
+ 0x53, 0xcc, 0xf5, 0xcf, 0x33, 0xd2, 0xd1, 0x75, 0x3c, 0xcf, 0x5a, 0xf3,
+ 0xbd, 0x0d, 0x3b, 0xa9, 0xe6, 0x7a, 0xd7, 0x9d, 0xe8, 0x69, 0xdd, 0x2f,
+ 0x3b, 0xd6, 0xbc, 0xcf, 0x4b, 0x4e, 0xea, 0x79, 0x9e, 0xb9, 0xe6, 0x7a,
+ 0x1a, 0x77, 0x53, 0xcc, 0xf5, 0xaf, 0x3b, 0xd0, 0xd3, 0xba, 0x5e, 0x77,
+ 0xad, 0x79, 0x9e, 0x96, 0x8b, 0xa9, 0xe7, 0x7a, 0xd7, 0x99, 0xe8, 0x69,
+ 0xdd, 0x4f, 0x33, 0xd7, 0x3c, 0xcf, 0x43, 0x4e, 0xea, 0x79, 0x9e, 0xb5,
+ 0xe6, 0xa5, 0xa7, 0x75, 0x3c, 0xef, 0x3d, 0x29, 0x9d, 0x88, 0xd2, 0x92,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x88, 0x00, 0x00, 0x01, 0x0f, 0x53, 0xfa, 0xab, 0xcc, 0xf5, 0xaf, 0x3b,
+ 0xde, 0xa3, 0x5c, 0xf7, 0x4b, 0xce, 0xf5, 0xaf, 0x33, 0xd0, 0xd3, 0xba,
+ 0x9e, 0x67, 0xae, 0x79, 0x9e, 0x86, 0x9d, 0xd4, 0xf3, 0x3d, 0x6b, 0xce,
+ 0xf4, 0xb4, 0xee, 0xa7, 0x99, 0xeb, 0x5e, 0x77, 0xa1, 0xa7, 0x74, 0xbc,
+ 0xef, 0x5a, 0xf3, 0x3d, 0x0d, 0x3b, 0xa9, 0xe7, 0x7a, 0xd7, 0x99, 0xe9,
+ 0x68, 0xba, 0x9e, 0x67, 0xad, 0x78, 0xd0, 0xd3, 0xb4, 0x79, 0x9e, 0x6a,
+ 0x4a, 0x76, 0x23, 0x4a, 0x4a, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x97, 0xcf,
+ 0xca, 0x00, 0x58, 0x90, 0xd0, 0x1d, 0x00, 0x1f, 0xa0, 0x0a, 0x86, 0x01,
+ 0x81, 0x89, 0x4b, 0xb1, 0x6e, 0xc5, 0x3b, 0xa9, 0x9c, 0xcf, 0x6e, 0x58,
+ 0x6a, 0x03, 0x18, 0x6f, 0x67, 0xed, 0x84, 0xd3, 0xb7, 0xf7, 0xf4, 0x0a,
+ 0x5c, 0x22, 0x10, 0x0c, 0x0a, 0x21, 0x93, 0x40, 0x6c, 0x82, 0x1a, 0x1f,
+ 0xf4, 0x21, 0x1c, 0x61, 0x6c, 0x9e, 0x90, 0xe5, 0x31, 0xaf, 0x54, 0x01,
+ 0xa8, 0x06, 0x98, 0x03, 0x44, 0x92, 0xb9, 0x34, 0xa2, 0xcb, 0xcc, 0xe8,
+ 0x40, 0xd5, 0x38, 0xff, 0xf3, 0x07, 0x1e, 0xb9, 0x12, 0xd0, 0x34, 0x61,
+ 0xac, 0xec, 0xdc, 0xe8, 0x6e, 0x7d, 0xfa, 0x2a, 0x52, 0x96, 0x35, 0x5c,
+ 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0xf1, 0xa0, 0x18,
+ 0x00, 0x38, 0x48, 0x05, 0xe8, 0x4f, 0x28, 0x9a, 0x56, 0xe8, 0x61, 0xa8,
+ 0xf9, 0x2a, 0x77, 0x65, 0xb3, 0x73, 0xad, 0x8b, 0x2d, 0x01, 0x98, 0x6a,
+ 0x7b, 0x61, 0xf4, 0xec, 0xf7, 0xec, 0xa9, 0x72, 0x80, 0x62, 0x05, 0x10,
+ 0x03, 0xa2, 0xf9, 0x40, 0x67, 0x16, 0x94, 0x25, 0x28, 0x4b, 0x64, 0xe6,
+ 0xe8, 0xec, 0x6e, 0xce, 0x1d, 0x71, 0x09, 0x80, 0x0f, 0x31, 0x34, 0x07,
+ 0x5c, 0x07, 0x60, 0x15, 0x86, 0x20, 0xa4, 0x29, 0x23, 0x72, 0x5f, 0x25,
+ 0xb7, 0x18, 0x72, 0xfa, 0xcc, 0x3e, 0x7c, 0xb4, 0x6d, 0xbf, 0xea, 0xe7,
+ 0x2b, 0x9b, 0x26, 0xf7, 0xec, 0x29, 0x78, 0x00, 0x13, 0x00, 0x2e, 0x48,
+ 0x06, 0xa1, 0x9c, 0x34, 0x98, 0x43, 0x0c, 0xfb, 0x71, 0x9d, 0xf1, 0x79,
+ 0x6d, 0xb8, 0xe1, 0x76, 0xde, 0x00, 0xe9, 0xdb, 0x13, 0x00, 0x62, 0x03,
+ 0xa2, 0x6a, 0x7f, 0x24, 0x62, 0xdb, 0x9d, 0xfb, 0x84, 0xb6, 0xb5, 0x00,
+ 0xb4, 0x31, 0xfe, 0x1a, 0xbc, 0x7a, 0xba, 0x84, 0xaa, 0x43, 0x3d, 0xfb,
+ 0x2a, 0x5c, 0xd0, 0x1d, 0x80, 0xc0, 0x9a, 0x02, 0x62, 0xc9, 0x44, 0xd2,
+ 0xba, 0x39, 0x8e, 0x77, 0x5b, 0x3e, 0xe6, 0xeb, 0x20, 0x06, 0x80, 0x26,
+ 0x00, 0x37, 0x0d, 0xc4, 0xcc, 0x5a, 0x0a, 0x4f, 0x24, 0x6f, 0xba, 0xdb,
+ 0x7f, 0xd7, 0xb2, 0x9b, 0x63, 0x6c, 0x39, 0x68, 0xc8, 0x1a, 0xea, 0x67,
+ 0x73, 0xd5, 0x53, 0x2d, 0xaf, 0xbb, 0x4b, 0xe7, 0x25, 0x80, 0x2a, 0xe1,
+ 0x81, 0xa8, 0x0c, 0x48, 0x0c, 0x40, 0xa2, 0x0b, 0x4b, 0x0c, 0x47, 0x1a,
+ 0xfd, 0xfb, 0x66, 0x51, 0xbe, 0xf5, 0x60, 0x27, 0x00, 0xc8, 0x0a, 0x80,
+ 0x65, 0xd1, 0x89, 0xa8, 0x61, 0xbb, 0xfd, 0xf7, 0xdf, 0x76, 0x3d, 0x78,
+ 0xdd, 0x6c, 0x82, 0x18, 0x61, 0x7f, 0x6c, 0x9d, 0xdd, 0x78, 0x58, 0x81,
+ 0xf2, 0xe8, 0xfa, 0xfb, 0x74, 0xa5, 0xe4, 0x00, 0x60, 0x00, 0xd8, 0x0a,
+ 0x80, 0x9c, 0x0a, 0x16, 0x43, 0x43, 0x64, 0x23, 0x76, 0xdc, 0xf2, 0xc6,
+ 0x65, 0xec, 0xc1, 0x4b, 0xb1, 0x49, 0x68, 0x2b, 0x3a, 0x7b, 0x63, 0xaa,
+ 0xd9, 0xef, 0xd7, 0xd2, 0x94, 0xb2, 0x9d, 0xca, 0x52, 0x91, 0x17, 0x29,
+ 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52,
+ 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xb8,
+ 0x40, 0x1a, 0x00, 0x98, 0x00, 0xdc, 0x37, 0x13, 0x31, 0x68, 0x29, 0x3c,
+ 0x91, 0xbe, 0xeb, 0x6d, 0xff, 0x5e, 0xca, 0x6d, 0x8d, 0xad, 0x29, 0xc8,
+ 0xdf, 0xf5, 0x6c, 0x7c, 0x8f, 0xbe, 0xed, 0x2f, 0x22, 0x00, 0xec, 0x03,
+ 0x04, 0x00, 0x5c, 0x90, 0xc2, 0x80, 0xcf, 0x2c, 0xb4, 0xa0, 0x6a, 0x73,
+ 0x36, 0xc6, 0x66, 0xe6, 0xbf, 0xdc, 0x2a, 0xf5, 0xd5, 0x14, 0x5e, 0x2d,
+ 0x19, 0x28, 0x5e, 0xe7, 0x4b, 0xe6, 0xb9, 0x4a, 0x52, 0xca, 0xab, 0x94,
+ 0xbe, 0x6a, 0x03, 0xa0, 0x05, 0x88, 0x26, 0x90, 0xb8, 0x0e, 0xd2, 0x05,
+ 0x70, 0x0d, 0x86, 0x25, 0x2e, 0x84, 0x24, 0x68, 0x16, 0xfd, 0xd4, 0x96,
+ 0x1d, 0xef, 0xa5, 0x5d, 0x25, 0x06, 0xa0, 0xbe, 0x9c, 0x8e, 0xe3, 0x3b,
+ 0x71, 0x23, 0xa8, 0xfb, 0xeb, 0x94, 0xa5, 0x2e, 0x6a, 0xee, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x88,
+ 0x00, 0x00, 0x01, 0x10, 0x53, 0xfb, 0x23, 0xcc, 0xf5, 0xcf, 0x33, 0xdd,
+ 0x6d, 0x65, 0x75, 0x3c, 0xcf, 0x5a, 0xf3, 0xbd, 0x2d, 0x3b, 0xa5, 0xe7,
+ 0x7a, 0xd7, 0x9d, 0xe8, 0x69, 0xdd, 0x2f, 0x3b, 0xd6, 0xbc, 0xcf, 0x43,
+ 0x4e, 0xea, 0x79, 0x9e, 0xb6, 0x34, 0xb4, 0x5a, 0x3c, 0xd1, 0xa5, 0x33,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x7c, 0x24, 0x00, 0xb8, 0x37,
+ 0x06, 0x80, 0xe8, 0x9a, 0x4c, 0xf9, 0xc6, 0x25, 0xd6, 0xbc, 0x30, 0xbc,
+ 0xcc, 0xc0, 0x22, 0xee, 0x26, 0xfb, 0xb5, 0xf2, 0xb0, 0x02, 0xac, 0x90,
+ 0x03, 0xf2, 0x6f, 0x58, 0xc0, 0x30, 0xdc, 0x73, 0xf4, 0xe6, 0x71, 0x6c,
+ 0x35, 0x83, 0xef, 0x64, 0x03, 0x54, 0x38, 0x14, 0x2c, 0x53, 0x7c, 0x27,
+ 0x7b, 0x00, 0xce, 0xc9, 0xd5, 0xff, 0x41, 0x00, 0x84, 0x0c, 0x8e, 0x9e,
+ 0x49, 0xef, 0x91, 0x8d, 0xc3, 0xfd, 0xea, 0x4a, 0x29, 0x21, 0xa9, 0x6c,
+ 0x1f, 0xee, 0x70, 0x15, 0x4f, 0x48, 0x6a, 0x45, 0x76, 0x0a, 0xbe, 0x58,
+ 0x03, 0xad, 0x8a, 0x26, 0x72, 0xc7, 0xbf, 0xe1, 0xd6, 0xbf, 0x8c, 0xce,
+ 0x6f, 0xa2, 0xfd, 0xa0, 0x05, 0x48, 0xdf, 0x23, 0x96, 0x13, 0xcc, 0x65,
+ 0x0a, 0xbd, 0x29, 0x64, 0xce, 0x18, 0x96, 0x4f, 0x0f, 0xb9, 0x64, 0x2d,
+ 0xc3, 0x49, 0xbb, 0xf7, 0xeb, 0x7f, 0xc0, 0x3f, 0xbc, 0x88, 0x0e, 0xd8,
+ 0xb0, 0xd2, 0x8a, 0x0b, 0x0f, 0x6a, 0x9f, 0xe4, 0xec, 0xee, 0xa7, 0xe2,
+ 0xa2, 0xfd, 0x29, 0x60, 0x50, 0x94, 0x50, 0xde, 0x91, 0xcc, 0x2e, 0x72,
+ 0x60, 0x14, 0xc1, 0xa8, 0xe9, 0xfd, 0xb6, 0xbc, 0x58, 0x09, 0xfb, 0x92,
+ 0x8a, 0xc6, 0xf7, 0x20, 0x11, 0x6e, 0x71, 0x60, 0x28, 0x02, 0x8d, 0xbb,
+ 0xbe, 0x61, 0x2e, 0x7b, 0x13, 0xee, 0xd1, 0xbc, 0x66, 0x1f, 0xf9, 0x3a,
+ 0xcd, 0xaf, 0xec, 0xa1, 0x85, 0x01, 0x94, 0xb3, 0xb5, 0xe3, 0x80, 0x0f,
+ 0x00, 0xbb, 0x6e, 0xac, 0x7f, 0xe4, 0x6c, 0x1d, 0x56, 0x02, 0x62, 0x80,
+ 0xbf, 0xff, 0x12, 0x09, 0xdc, 0x07, 0xf7, 0x64, 0x0a, 0x86, 0xfe, 0x1b,
+ 0xdb, 0x92, 0x15, 0x88, 0xb7, 0x07, 0xff, 0xa5, 0xb7, 0x32, 0xd0, 0xca,
+ 0xb3, 0xd4, 0x00, 0xc4, 0x99, 0x80, 0xa1, 0x0c, 0xb0, 0xcc, 0x9c, 0x5e,
+ 0x47, 0x61, 0xb8, 0xd0, 0x3b, 0x8e, 0xe2, 0xef, 0x00, 0x00, 0x91, 0x3c,
+ 0x02, 0xb0, 0xd4, 0x3a, 0xb8, 0x63, 0xfc, 0x2f, 0x27, 0x31, 0x1f, 0xdf,
+ 0x53, 0xbe, 0x7e, 0x00, 0xb0, 0x34, 0x94, 0x02, 0x1c, 0x86, 0x01, 0xca,
+ 0x12, 0x81, 0x0d, 0x86, 0x80, 0x0c, 0xae, 0x50, 0x2b, 0x9c, 0x84, 0x5e,
+ 0x3c, 0x23, 0x93, 0xad, 0x10, 0x49, 0xd5, 0xc6, 0xf0, 0x1d, 0x94, 0x08,
+ 0x5f, 0x29, 0xd8, 0xdf, 0x82, 0xfa, 0xc8, 0xfe, 0xa4, 0x0a, 0xa7, 0x23,
+ 0x20, 0x99, 0x8e, 0x28, 0xfe, 0x3d, 0x26, 0x85, 0x1d, 0x78, 0x52, 0x1a,
+ 0x00, 0xc0, 0x69, 0x64, 0x3e, 0x3b, 0x0c, 0x01, 0x5f, 0xcc, 0x4e, 0x67,
+ 0xbe, 0xd8, 0x7f, 0xb4, 0x28, 0x27, 0x61, 0x5b, 0x05, 0xd3, 0xea, 0xdf,
+ 0x81, 0x00, 0x98, 0x10, 0x82, 0x40, 0x1d, 0x72, 0xc0, 0x70, 0x9e, 0x51,
+ 0x69, 0x70, 0x1e, 0xf7, 0xc8, 0xe1, 0xe1, 0x0d, 0x7e, 0x81, 0xbe, 0x00,
+ 0x00, 0xec, 0x10, 0x81, 0xc0, 0x30, 0x41, 0x30, 0xf7, 0x25, 0x06, 0x39,
+ 0xac, 0x8c, 0xee, 0xc0, 0x22, 0x27, 0xdf, 0x68, 0x01, 0x80, 0x14, 0xe0,
+ 0x3b, 0x26, 0x94, 0x19, 0x80, 0xff, 0x5f, 0x1d, 0x8d, 0xe1, 0x57, 0x50,
+ 0x0e, 0xbe, 0x18, 0x1a, 0x1b, 0xc0, 0xfa, 0x7f, 0x71, 0x5a, 0x84, 0x9f,
+ 0xb5, 0x7f, 0xf2, 0x32, 0x18, 0x49, 0x09, 0x1f, 0x9e, 0x11, 0xc2, 0xf5,
+ 0xe9, 0xc0, 0x40, 0x87, 0x2f, 0xf6, 0x3b, 0x13, 0xc0, 0x7f, 0x79, 0x80,
+ 0x13, 0xa7, 0x64, 0x64, 0x63, 0x56, 0x1d, 0xa0, 0x02, 0x0c, 0x10, 0x9e,
+ 0x3f, 0xb0, 0x50, 0x1b, 0xbd, 0x27, 0x01, 0x47, 0x16, 0x70, 0x7d, 0x91,
+ 0xb7, 0xeb, 0xc8, 0x63, 0x4b, 0x21, 0xfc, 0x85, 0xb3, 0x6c, 0x28, 0x08,
+ 0xde, 0x4c, 0x04, 0x29, 0xc3, 0x36, 0x35, 0xdc, 0x3a, 0x50, 0x28, 0x4d,
+ 0xe1, 0xa5, 0xf5, 0x6c, 0xaf, 0xd5, 0x96, 0x7e, 0x36, 0xfa, 0x81, 0x0d,
+ 0x03, 0x03, 0x53, 0x9f, 0xf1, 0x22, 0x2e, 0x3d, 0x82, 0x76, 0x38, 0x66,
+ 0xae, 0xfb, 0xbb, 0x3f, 0x1d, 0x7c, 0x9f, 0x86, 0x24, 0x30, 0x99, 0xf9,
+ 0x2d, 0x5c, 0xcc, 0x77, 0x7b, 0xea, 0x48, 0x40, 0xd4, 0xec, 0x3f, 0xb5,
+ 0xf1, 0x90, 0x13, 0xf5, 0x21, 0x1b, 0x0b, 0x11, 0xb6, 0xb8, 0x53, 0xd6,
+ 0x8d, 0x6b, 0xaf, 0xe8, 0x85, 0x13, 0x1d, 0x04, 0xb4, 0xf6, 0x45, 0x9c,
+ 0xb2, 0x16, 0x42, 0x31, 0x68, 0x48, 0xdd, 0x79, 0x50, 0x28, 0x5e, 0xd8,
+ 0x0c, 0x17, 0x8f, 0x39, 0xc5, 0x99, 0x7a, 0xa0, 0x2a, 0x18, 0x03, 0x6e,
+ 0xdb, 0xf6, 0xeb, 0xad, 0xf8, 0xd6, 0x0a, 0x1d, 0xf4, 0xaf, 0xd9, 0x6c,
+ 0xfd, 0xb5, 0xf3, 0xc0, 0x0a, 0x91, 0xbe, 0x41, 0x69, 0x64, 0xf1, 0x4a,
+ 0x0b, 0xbd, 0xda, 0x1d, 0xd4, 0x7e, 0x58, 0x55, 0xf0, 0xa0, 0x2c, 0x03,
+ 0x14, 0x0e, 0x4e, 0x0b, 0xc0, 0x72, 0x82, 0xfb, 0x08, 0x34, 0x54, 0xf5,
+ 0xfd, 0x40, 0x02, 0xc6, 0x2c, 0x95, 0xfe, 0xdc, 0xc3, 0xd7, 0x12, 0x19,
+ 0x33, 0x13, 0x06, 0x67, 0x7f, 0xcf, 0xb8, 0x60, 0x3a, 0x47, 0xe4, 0xd5,
+ 0xbb, 0xa3, 0x72, 0x05, 0x8c, 0x37, 0x00, 0xdc, 0x86, 0xcf, 0x9b, 0x36,
+ 0x03, 0x82, 0x5f, 0xda, 0x3f, 0x1a, 0x7a, 0xb6, 0x7f, 0x4d, 0xf6, 0x52,
+ 0x05, 0x32, 0x03, 0x31, 0x7d, 0x2b, 0xec, 0xa1, 0x20, 0x72, 0xe8, 0x94,
+ 0x4c, 0x74, 0x12, 0xd3, 0xd9, 0x17, 0xcf, 0x00, 0x4f, 0xff, 0x18, 0x8c,
+ 0x2f, 0xf0, 0xe0, 0x23, 0x74, 0x40, 0xa1, 0x7b, 0x60, 0x30, 0x5e, 0x3c,
+ 0xe7, 0x16, 0x65, 0xd1, 0x92, 0x91, 0x8e, 0x2c, 0x9d, 0x49, 0xb7, 0xea,
+ 0x8b, 0x21, 0x64, 0x23, 0x16, 0x84, 0x8d, 0xd7, 0x19, 0x00, 0x3a, 0xdc,
+ 0xa1, 0xbd, 0x2a, 0x5f, 0x56, 0x33, 0x5d, 0x90, 0x2a, 0x18, 0x03, 0x6f,
+ 0xb6, 0xfd, 0xba, 0xef, 0x98, 0x80, 0x4c, 0x03, 0xac, 0x23, 0x70, 0xff,
+ 0xdc, 0x0d, 0x8a, 0x8e, 0x9e, 0xd9, 0xb9, 0xfe, 0x2f, 0xe8, 0xc1, 0x80,
+ 0x50, 0x96, 0x7f, 0xdb, 0xb3, 0xec, 0x68, 0x1a, 0xbb, 0xc0, 0x36, 0x49,
+ 0x2f, 0xa3, 0x67, 0xf8, 0x07, 0xf7, 0xce, 0x00, 0x4d, 0x9f, 0x96, 0x5f,
+ 0x0b, 0x27, 0xfb, 0xc6, 0x06, 0x77, 0xc9, 0x2d, 0x41, 0x3f, 0xf7, 0x15,
+ 0x95, 0x9e, 0xd3, 0x97, 0xf7, 0xe6, 0x9c, 0x17, 0xe4, 0xd7, 0xf5, 0xa0,
+ 0x0a, 0xb0, 0xd2, 0x51, 0x2f, 0x0d, 0x30, 0x70, 0x7d, 0xaf, 0x10, 0x80,
+ 0xb9, 0x2b, 0xa7, 0x6e, 0xe4, 0xe6, 0x7b, 0x86, 0x18, 0x92, 0x8a, 0xef,
+ 0x9c, 0xb4, 0xfb, 0x92, 0x03, 0xa7, 0x2c, 0x34, 0xb4, 0xa4, 0xfc, 0xa0,
+ 0x0e, 0x2c, 0x3f, 0xfb, 0x7e, 0x28, 0x9f, 0x55, 0xfa, 0xa2, 0xc0, 0xa0,
+ 0xc4, 0xb6, 0x49, 0x8f, 0xff, 0x56, 0xcb, 0x69, 0x49, 0xa0, 0x50, 0x06,
+ 0xc8, 0xdd, 0xdc, 0xcf, 0x72, 0x12, 0x02, 0x90, 0x2a, 0x30, 0xc7, 0x58,
+ 0xb6, 0x01, 0xf5, 0x84, 0x06, 0x2e, 0x5a, 0x72, 0x31, 0x87, 0x89, 0xfd,
+ 0x96, 0x02, 0xf9, 0xef, 0xdd, 0x19, 0xcc, 0x7f, 0x2b, 0xf7, 0x01, 0x84,
+ 0x24, 0x86, 0xbf, 0x3b, 0x63, 0x7d, 0xe1, 0x48, 0x41, 0x85, 0x12, 0xdd,
+ 0x09, 0xfc, 0x63, 0xba, 0x83, 0xae, 0x78, 0x0e, 0xf8, 0x18, 0x0c, 0xc5,
+ 0x63, 0x54, 0x1d, 0xae, 0x68, 0x0e, 0x91, 0x8a, 0x2b, 0xf3, 0x4f, 0xe2,
+ 0x80, 0x82, 0xee, 0xd4, 0xa7, 0xf4, 0x7e, 0x3d, 0x5b, 0x50, 0xd7, 0xf4,
+ 0xd2, 0x1b, 0x86, 0x93, 0x7e, 0xcf, 0xd9, 0x41, 0x47, 0x93, 0xe4, 0x00,
+ 0xab, 0x23, 0xec, 0x94, 0xed, 0xf9, 0xdb, 0x2d, 0x62, 0xef, 0x0c, 0x03,
+ 0x04, 0x70, 0x92, 0xf9, 0xe9, 0x02, 0x37, 0xa4, 0xc9, 0x0c, 0x41, 0x7c,
+ 0xbf, 0xfa, 0x52, 0xe7, 0x63, 0x8d, 0x1e, 0x7d, 0xc6, 0xe6, 0x63, 0x35,
+ 0x77, 0xec, 0x0b, 0x26, 0x24, 0xa4, 0x8c, 0x3f, 0xf3, 0x9a, 0xf3, 0xdc,
+ 0x0a, 0x62, 0xb0, 0x17, 0x4b, 0x39, 0x99, 0x77, 0xcf, 0x88, 0x43, 0x4b,
+ 0x2d, 0x25, 0xa7, 0x37, 0xc1, 0x1b, 0x0e, 0x36, 0xfa, 0x2e, 0x04, 0x2f,
+ 0xa2, 0x6b, 0xf3, 0x9c, 0x9c, 0x66, 0x0f, 0xa4, 0x6f, 0xe1, 0xd9, 0x73,
+ 0xab, 0x7c, 0x28, 0x0e, 0xf0, 0x01, 0xb0, 0x03, 0xac, 0x18, 0x37, 0xbf,
+ 0xd9, 0x0e, 0xcc, 0x03, 0x9e, 0x35, 0x39, 0x8c, 0x53, 0xeb, 0xef, 0x77,
+ 0xc4, 0x40, 0x16, 0xf4, 0xa4, 0x06, 0xc1, 0x88, 0x5a, 0x8b, 0x2d, 0x28,
+ 0xc3, 0xb6, 0x52, 0x78, 0x70, 0xdb, 0xec, 0x25, 0x93, 0x03, 0x43, 0x18,
+ 0x6a, 0x3a, 0x1f, 0x6f, 0x9f, 0x1f, 0xbd, 0x90, 0x09, 0x80, 0x70, 0x37,
+ 0x9e, 0x5f, 0xe9, 0xa8, 0xb3, 0xc4, 0x5e, 0xda, 0x58, 0xf9, 0x30, 0x35,
+ 0x08, 0xc5, 0xf4, 0x27, 0x21, 0x27, 0x76, 0x57, 0x68, 0x00, 0xd8, 0x34,
+ 0x94, 0x4b, 0x19, 0xc6, 0x3b, 0x0d, 0x65, 0x3d, 0xe2, 0x3e, 0x1f, 0x74,
+ 0x5e, 0xda, 0x52, 0x94, 0x4e, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x20, 0x00, 0x00, 0x01, 0x11, 0x6b, 0xfb, 0x9b, 0xce,
+ 0xf5, 0xaf, 0x35, 0x4d, 0x4d, 0xd4, 0xf3, 0x3d, 0x64, 0x65, 0x16, 0xaf,
+ 0x18, 0xd2, 0x99, 0xdc, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca,
+ 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94,
+ 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29,
+ 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91, 0x17, 0x2f, 0x99, 0x00,
+ 0x64, 0x01, 0x98, 0x0e, 0x80, 0x34, 0xc5, 0xb2, 0x09, 0xa9, 0xe5, 0xfc,
+ 0xff, 0x8c, 0xc7, 0x1c, 0x68, 0xbf, 0x7d, 0x36, 0x97, 0x49, 0x65, 0x60,
+ 0xdc, 0xdc, 0xea, 0x37, 0x6b, 0xc4, 0x1b, 0xd1, 0xd2, 0xe8, 0xe9, 0xee,
+ 0x7f, 0x4b, 0x3b, 0x87, 0x7f, 0x79, 0x60, 0x13, 0x00, 0x5f, 0xc0, 0xa1,
+ 0x31, 0x24, 0x24, 0xa0, 0x96, 0x51, 0x6e, 0xeb, 0x6f, 0xb2, 0x73, 0x25,
+ 0x8c, 0x10, 0x2e, 0xf6, 0xd4, 0xa5, 0x25, 0x64, 0xe6, 0xeb, 0x9b, 0xb5,
+ 0xfc, 0xd4, 0x30, 0x01, 0xf9, 0x08, 0x04, 0xc8, 0x4e, 0x01, 0xd1, 0x31,
+ 0x2e, 0x93, 0xf9, 0x7d, 0xce, 0x38, 0xe1, 0xcb, 0xbd, 0x38, 0x14, 0x01,
+ 0x3a, 0x49, 0x80, 0x31, 0x40, 0x15, 0x2d, 0xcb, 0xef, 0xdc, 0x7f, 0x7d,
+ 0xf1, 0x15, 0x57, 0xa3, 0xa5, 0xae, 0x26, 0x23, 0x0d, 0x51, 0x25, 0x5f,
+ 0xf3, 0xf8, 0x7d, 0x2f, 0xc2, 0xaf, 0xc0, 0x80, 0x6a, 0x00, 0xff, 0x00,
+ 0xef, 0xf2, 0x50, 0x66, 0x43, 0xa0, 0x60, 0xde, 0x49, 0x18, 0xee, 0xc3,
+ 0xb2, 0xdc, 0x4e, 0xf7, 0x2c, 0x86, 0x00, 0xcc, 0x0c, 0x86, 0x21, 0x08,
+ 0x26, 0x64, 0x27, 0x2f, 0x73, 0xf1, 0x5c, 0xed, 0xd1, 0x87, 0xb7, 0xe7,
+ 0x9d, 0xef, 0xa9, 0x52, 0xd0, 0x02, 0xc2, 0x99, 0x19, 0x89, 0x07, 0x2f,
+ 0xc8, 0x6f, 0xbf, 0x9c, 0x80, 0x64, 0x00, 0xfc, 0xa0, 0x13, 0x06, 0x06,
+ 0xb9, 0x49, 0x48, 0x69, 0x7d, 0xc6, 0xb9, 0xea, 0x56, 0xe1, 0xee, 0x17,
+ 0x7d, 0x01, 0x29, 0xe5, 0xa7, 0xa5, 0x3d, 0xfa, 0x7f, 0xff, 0x8f, 0xfe,
+ 0xba, 0x96, 0x18, 0xa4, 0x23, 0xa5, 0x3b, 0x2d, 0x27, 0x87, 0x54, 0xf7,
+ 0x2e, 0x00, 0x06, 0x80, 0x57, 0x00, 0xc0, 0x0a, 0x94, 0x1a, 0x9d, 0xfe,
+ 0x40, 0xd5, 0x63, 0xd6, 0x8f, 0x88, 0xb7, 0x7e, 0x96, 0x5f, 0x64, 0xef,
+ 0xb9, 0xdd, 0x55, 0x1d, 0x7e, 0x18, 0x01, 0xf8, 0x06, 0x20, 0x06, 0xfc,
+ 0xac, 0x8d, 0xd0, 0x84, 0x63, 0xb8, 0x13, 0xe6, 0xa8, 0x51, 0xc1, 0xf7,
+ 0x7c, 0x06, 0x05, 0x86, 0x06, 0x06, 0xa0, 0xb2, 0xc6, 0x81, 0x64, 0xa1,
+ 0x3b, 0x23, 0x65, 0xb7, 0x75, 0xbf, 0xd7, 0x6a, 0x96, 0xa8, 0x29, 0x08,
+ 0x40, 0xcc, 0xad, 0x4b, 0xbf, 0x7b, 0xf9, 0x28, 0x0c, 0x40, 0x1f, 0x80,
+ 0x80, 0x04, 0xf9, 0x18, 0x34, 0x98, 0x4d, 0x08, 0xfd, 0xbe, 0xfb, 0x75,
+ 0x9f, 0x76, 0x4a, 0x00, 0x7e, 0x50, 0x0c, 0x32, 0x70, 0x0e, 0x88, 0x59,
+ 0x0e, 0xc0, 0x5c, 0xbe, 0xe9, 0x1e, 0xb3, 0x02, 0xaf, 0xa0, 0xd2, 0xe9,
+ 0xc0, 0x50, 0xad, 0x86, 0x2d, 0x87, 0x3f, 0x6a, 0x06, 0xfb, 0xe7, 0x16,
+ 0x4d, 0x49, 0x0c, 0xb1, 0xa4, 0xd4, 0xf4, 0x9c, 0xfc, 0xd6, 0x14, 0x65,
+ 0xf3, 0xa2, 0x10, 0x03, 0xf0, 0x28, 0x42, 0x01, 0xd7, 0x21, 0x21, 0x01,
+ 0xab, 0xc9, 0xc4, 0xb0, 0x8d, 0xdd, 0x2e, 0xb3, 0xcf, 0xc4, 0x4b, 0xea,
+ 0xd4, 0xb1, 0x48, 0x62, 0x0b, 0xdb, 0x73, 0xb2, 0xf6, 0xca, 0x3a, 0xad,
+ 0xfe, 0xbf, 0x2e, 0x02, 0x00, 0x13, 0x80, 0x1c, 0x10, 0xc9, 0x7b, 0x0d,
+ 0x47, 0x74, 0x7d, 0xcf, 0x19, 0xf9, 0x1d, 0x55, 0x60, 0x19, 0x81, 0x52,
+ 0x60, 0x0c, 0x43, 0x78, 0x69, 0x58, 0xb4, 0x27, 0xb3, 0xee, 0xcc, 0xac,
+ 0xcf, 0x9b, 0x88, 0xbd, 0x65, 0x28, 0x25, 0x20, 0x69, 0x2c, 0xd6, 0x60,
+ 0xe9, 0xba, 0x9a, 0xf8, 0x80, 0x20, 0x02, 0xa0, 0x07, 0x80, 0x54, 0xa0,
+ 0xd6, 0x71, 0x8e, 0xf8, 0x57, 0xdf, 0x11, 0x6f, 0x2e, 0x02, 0x10, 0x07,
+ 0x7c, 0x86, 0x90, 0x14, 0x20, 0x94, 0x76, 0xe9, 0xeb, 0x4a, 0x76, 0x58,
+ 0xce, 0x63, 0x3b, 0xa8, 0xd3, 0x6f, 0xa1, 0xd2, 0xae, 0x18, 0x8e, 0x9c,
+ 0x9f, 0x97, 0xb3, 0x49, 0xfb, 0x35, 0xfc, 0xcc, 0x34, 0x02, 0xf0, 0x28,
+ 0x02, 0x74, 0x20, 0x00, 0xfc, 0x98, 0x92, 0x5a, 0x00, 0xf9, 0x5f, 0x65,
+ 0x30, 0xb1, 0x66, 0x5e, 0x98, 0x03, 0x50, 0x0d, 0x4b, 0x00, 0xd5, 0x3b,
+ 0xa7, 0x64, 0x64, 0x12, 0x11, 0x8c, 0x73, 0xd6, 0x2e, 0xf4, 0xd4, 0xa9,
+ 0x04, 0xc4, 0x23, 0xef, 0xb1, 0xce, 0xc2, 0x9c, 0xf6, 0x8f, 0xff, 0xbf,
+ 0x36, 0x01, 0xa0, 0x08, 0x52, 0x01, 0xa1, 0x7d, 0x28, 0xd9, 0x3b, 0xe6,
+ 0xfb, 0x90, 0x4f, 0xd7, 0x97, 0x00, 0x13, 0x81, 0x42, 0x11, 0x65, 0x93,
+ 0x40, 0xa1, 0x31, 0x28, 0x2c, 0xbd, 0xf0, 0x4f, 0xc4, 0xac, 0xeb, 0x7d,
+ 0xb0, 0xbd, 0x95, 0x7d, 0x32, 0x92, 0x49, 0x31, 0x09, 0xef, 0xf1, 0xf9,
+ 0xba, 0xcf, 0xc2, 0xe1, 0xfd, 0xf8, 0x00, 0x0c, 0x00, 0x1f, 0x80, 0x1e,
+ 0x16, 0x4d, 0x48, 0x6e, 0xe5, 0x81, 0x96, 0xff, 0xe6, 0x77, 0xdf, 0x91,
+ 0xdf, 0xda, 0x80, 0x04, 0xe0, 0x85, 0xf3, 0x89, 0xb8, 0x98, 0x56, 0xd9,
+ 0x29, 0x2c, 0x62, 0xd6, 0x94, 0xe6, 0x7f, 0xcd, 0x6e, 0xbc, 0xa5, 0x5e,
+ 0xd6, 0x93, 0x01, 0xb1, 0x4f, 0xd2, 0xcb, 0x4e, 0x6e, 0x22, 0x06, 0xfb,
+ 0xf9, 0xe0, 0x08, 0x40, 0x1d, 0xf2, 0x1a, 0x40, 0x50, 0x82, 0x51, 0xdb,
+ 0xa7, 0xad, 0x29, 0xd9, 0x63, 0x39, 0x8c, 0xee, 0xa3, 0x4d, 0xb3, 0x06,
+ 0x80, 0x5e, 0x05, 0x00, 0x4e, 0x84, 0x00, 0x1f, 0x93, 0x12, 0x4b, 0x40,
+ 0x1f, 0x2b, 0xec, 0xa6, 0x16, 0x2c, 0xcb, 0xe9, 0x94, 0xac, 0x02, 0xc2,
+ 0xb6, 0xcd, 0x98, 0x61, 0xdf, 0x7e, 0xe1, 0x72, 0x1b, 0xeb, 0xff, 0x1a,
+ 0x58, 0x6a, 0x40, 0xa9, 0x68, 0xc7, 0x19, 0x83, 0xef, 0x97, 0x00, 0xc5,
+ 0x28, 0xc3, 0x32, 0x77, 0xfb, 0xbf, 0x51, 0xea, 0x03, 0x77, 0xdb, 0x8a,
+ 0x49, 0x29, 0x39, 0x2c, 0xec, 0x65, 0xcd, 0x26, 0x86, 0x80, 0xdd, 0x2e,
+ 0xcc, 0xa6, 0xbb, 0x3a, 0x17, 0x87, 0x67, 0xb3, 0x7a, 0xbb, 0x92, 0x1a,
+ 0x01, 0x7b, 0x13, 0x00, 0x2c, 0x02, 0x85, 0x01, 0x82, 0x99, 0xbb, 0xad,
+ 0x3d, 0xcf, 0x71, 0x2b, 0x0e, 0xaa, 0x01, 0x00, 0x05, 0xe0, 0x16, 0x06,
+ 0x24, 0x98, 0x1a, 0x8e, 0x59, 0x5f, 0x76, 0xd8, 0xfc, 0xe7, 0xe1, 0x1e,
+ 0xfa, 0x15, 0x2e, 0x20, 0x1b, 0x15, 0xf3, 0x31, 0xae, 0x2d, 0xc7, 0xb8,
+ 0xfb, 0x47, 0xf7, 0xe5, 0xb8, 0x15, 0x0c, 0x0c, 0xe9, 0x00, 0xb0, 0x33,
+ 0xa3, 0xf5, 0x64, 0xa5, 0x2e, 0x9d, 0xba, 0x3e, 0xec, 0xcd, 0xb7, 0x59,
+ 0xeb, 0xbc, 0xf0, 0x06, 0x80, 0x17, 0x86, 0x00, 0x80, 0x99, 0xd0, 0x4a,
+ 0x4a, 0x53, 0xff, 0xee, 0xad, 0x8e, 0x56, 0x73, 0xd8, 0x83, 0x7d, 0x2a,
+ 0x94, 0x24, 0x31, 0x09, 0xcd, 0xd6, 0x1e, 0x3a, 0x6f, 0xf5, 0xf9, 0x20,
+ 0x0c, 0x80, 0x4e, 0x00, 0x78, 0x43, 0xe5, 0xa7, 0x74, 0x8d, 0xdf, 0x71,
+ 0xeb, 0xfb, 0xba, 0xc5, 0xeb, 0x30, 0x0c, 0x40, 0x2f, 0x49, 0x34, 0xb7,
+ 0x2b, 0x01, 0x8c, 0x37, 0x25, 0x47, 0xa7, 0xa0, 0x91, 0xd2, 0x23, 0x6c,
+ 0xd8, 0xeb, 0xdb, 0x52, 0x40, 0x61, 0x03, 0x46, 0xb2, 0xd9, 0xa1, 0xfb,
+ 0x35, 0xfc, 0xbc, 0x07, 0x60, 0x0e, 0xca, 0x21, 0xe2, 0x81, 0x08, 0x1b,
+ 0x74, 0xa1, 0x6e, 0x95, 0xed, 0xd4, 0x76, 0x34, 0xe3, 0x6b, 0xc0, 0xa0,
+ 0x03, 0xdc, 0x4c, 0x02, 0x9c, 0x98, 0x90, 0xc2, 0x5f, 0xee, 0xb7, 0x24,
+ 0x8d, 0xfd, 0xc6, 0x9a, 0x72, 0xaf, 0xa4, 0xd2, 0xdc, 0x02, 0xc2, 0x86,
+ 0x0c, 0x65, 0x3b, 0x9f, 0xe9, 0x1b, 0xef, 0xe7, 0x00, 0x30, 0x00, 0x72,
+ 0x1a, 0x4c, 0x2d, 0x3c, 0xb0, 0x94, 0x24, 0xcc, 0xa1, 0x8a, 0x50, 0xc1,
+ 0x46, 0x35, 0xd6, 0xe0, 0x3b, 0x02, 0x85, 0x16, 0x4b, 0x21, 0x13, 0x3e,
+ 0xe7, 0xe2, 0x5f, 0x7c, 0x8e, 0xee, 0xad, 0x89, 0xcf, 0xef, 0x63, 0x4b,
+ 0x20, 0x30, 0x8d, 0xff, 0xd9, 0x9c, 0xf6, 0x36, 0xa7, 0xf7, 0xf3, 0xe0,
+ 0x0c, 0x00, 0x2f, 0x00, 0x3c, 0x25, 0xe2, 0xf2, 0x4b, 0xc9, 0xe3, 0x45,
+ 0x8d, 0x37, 0xac, 0x79, 0x12, 0xe8, 0xa0, 0x03, 0x5c, 0x51, 0x34, 0xa2,
+ 0xd0, 0x4c, 0x29, 0x08, 0x47, 0xfc, 0x95, 0x9d, 0x7f, 0xa1, 0x9f, 0xfe,
+ 0x7b, 0x1f, 0x87, 0x5e, 0xc2, 0x90, 0x06, 0x10, 0xff, 0xb1, 0x24, 0xf8,
+ 0x7f, 0x7f, 0x36, 0x01, 0xd8, 0x03, 0xb0, 0x32, 0x5e, 0xe5, 0x15, 0xb6,
+ 0xc3, 0x06, 0xb9, 0xe5, 0xa3, 0x77, 0x19, 0xc7, 0x67, 0x77, 0x1f, 0x6a,
+ 0x00, 0xcc, 0x01, 0xf8, 0x01, 0xd9, 0x45, 0x15, 0x90, 0x33, 0x66, 0x4f,
+ 0x01, 0x5b, 0x32, 0x85, 0x2e, 0xf7, 0xf4, 0xab, 0x13, 0x0a, 0xc3, 0x1b,
+ 0x12, 0x0e, 0x90, 0xdf, 0x7f, 0x36, 0x01, 0x88, 0x03, 0xb0, 0x0a, 0xc0,
+ 0xa6, 0x26, 0x62, 0xb1, 0x4e, 0x49, 0x1c, 0xdb, 0xbe, 0xc8, 0xa0, 0x00,
+ 0x84, 0x10, 0x82, 0x80, 0x2c, 0xc5, 0x6d, 0xc6, 0x12, 0x9c, 0xc1, 0x8c,
+ 0xdf, 0x89, 0xf7, 0xd2, 0x69, 0x30, 0x0b, 0x0a, 0xdb, 0x66, 0x3b, 0x8d,
+ 0x34, 0xf8, 0x1b, 0xee, 0x52, 0x94, 0xbc, 0xfb, 0x5b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0x80, 0x00, 0x00, 0x01, 0x12,
+ 0x73, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4b, 0x31, 0x5b, 0x25, 0x3b, 0x7f, 0xf3, 0x8e, 0xce,
+ 0x45, 0xd7, 0x9c, 0x0d, 0x01, 0x32, 0x03, 0x08, 0x60, 0x16, 0x01, 0x90,
+ 0x97, 0xd9, 0xfa, 0x19, 0x0b, 0xdb, 0x9f, 0xbf, 0xe6, 0x81, 0x2b, 0x5e,
+ 0x9d, 0xbb, 0x07, 0xd2, 0xd7, 0xeb, 0x29, 0x63, 0x0d, 0x0c, 0x49, 0x30,
+ 0xbe, 0x52, 0x73, 0x74, 0x76, 0xf6, 0xcb, 0x33, 0xe7, 0x72, 0x94, 0xa4,
+ 0xa7, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x5e, 0x5c, 0x06, 0x00, 0x3a, 0x28,
+ 0x9a, 0x51, 0x34, 0xb4, 0xa5, 0x38, 0x0c, 0x21, 0xdb, 0x6c, 0xb1, 0xcb,
+ 0xfc, 0x2d, 0x57, 0xa8, 0xb4, 0xdf, 0x7f, 0xf0, 0xea, 0x6e, 0x52, 0x94,
+ 0xb3, 0xaa, 0xe5, 0x29, 0x79, 0x70, 0x1d, 0x00, 0xe8, 0xa2, 0x69, 0x44,
+ 0xd2, 0xd2, 0x94, 0xe0, 0x30, 0x87, 0x6d, 0xb2, 0xc7, 0x2f, 0xf0, 0xbb,
+ 0x4f, 0xf2, 0x33, 0xfa, 0x4f, 0xbf, 0x51, 0x4a, 0x52, 0xce, 0xab, 0x94,
+ 0xa9, 0x4a, 0x3a, 0x0f, 0xcc, 0xa7, 0x0e, 0xf5, 0xd1, 0x17, 0x29, 0x4a,
+ 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x94, 0xa4, 0x45, 0xca, 0x52, 0x91,
+ 0x17, 0x29, 0x4a, 0x44, 0x5c, 0xa5, 0x29, 0x11, 0x72, 0x97, 0x9a, 0x00,
+ 0x3e, 0x40, 0x01, 0xe7, 0x21, 0x8d, 0xe4, 0x9c, 0x8d, 0x98, 0xfe, 0x69,
+ 0xbc, 0xc1, 0x16, 0xe0, 0x1b, 0x60, 0x0b, 0x30, 0x69, 0x2d, 0x0e, 0x34,
+ 0x61, 0x28, 0x0f, 0x89, 0xb6, 0x1b, 0x89, 0xec, 0x1f, 0x4b, 0x5f, 0x5e,
+ 0x94, 0xa5, 0x8d, 0x57, 0x29, 0x4b, 0x20, 0x61, 0x5c, 0x34, 0xb4, 0x23,
+ 0x01, 0xff, 0xb4, 0xe2, 0xf5, 0xd2, 0xf2, 0x21, 0x80, 0x26, 0x28, 0x9b,
+ 0xcb, 0x18, 0x1b, 0xd8, 0x33, 0x7f, 0xd2, 0x4a, 0xdb, 0x36, 0x1c, 0x05,
+ 0xdd, 0x66, 0x2a, 0xb0, 0x98, 0x03, 0xa0, 0xc2, 0x19, 0xc4, 0xdf, 0x82,
+ 0x50, 0x53, 0x72, 0x8d, 0x49, 0xc7, 0x27, 0x8e, 0xba, 0x09, 0x79, 0x62,
+ 0x85, 0x7a, 0x1a, 0xfd, 0x55, 0x2e, 0x50, 0x15, 0x26, 0x62, 0x10, 0x6a,
+ 0x4a, 0x1a, 0x37, 0xa3, 0xb7, 0xec, 0xcb, 0x14, 0xbf, 0x64, 0x26, 0x81,
+ 0x44, 0x13, 0x0a, 0x42, 0x49, 0x7d, 0xcb, 0xcf, 0x91, 0xd0, 0xdd, 0x9d,
+ 0x9f, 0x84, 0xf6, 0x39, 0x47, 0xd9, 0x8d, 0xca, 0x16, 0x74, 0xda, 0xfd,
+ 0x05, 0x29, 0x4b, 0x2a, 0xae, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x20, 0x00,
+ 0x00, 0x01, 0x13, 0x73, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xad, 0xfc, 0xc8, 0x0e, 0x90, 0x34, 0x9a,
+ 0x50, 0xae, 0xe1, 0x4b, 0xb8, 0x5c, 0xaf, 0xc8, 0x7c, 0xb4, 0x84, 0x20,
+ 0x6b, 0xbf, 0x22, 0x0f, 0xb7, 0x80, 0xeb, 0xa0, 0xa1, 0xa9, 0xff, 0x6e,
+ 0x33, 0xe4, 0x09, 0xbd, 0x87, 0xbd, 0x13, 0xd3, 0xc4, 0x35, 0x8d, 0x7f,
+ 0xf3, 0x07, 0x41, 0x35, 0x25, 0xa7, 0xec, 0xdb, 0x1f, 0xdc, 0x89, 0xee,
+ 0xea, 0x32, 0x0b, 0x3b, 0x36, 0x46, 0x74, 0xf3, 0x78, 0x1d, 0xb4, 0xe4,
+ 0xec, 0x4c, 0xf9, 0xd6, 0x94, 0x93, 0xb5, 0x90, 0x84, 0x5e, 0xd8, 0xb4,
+ 0x7e, 0x30, 0x6e, 0xcd, 0xc5, 0xeb, 0xa1, 0x98, 0x89, 0x45, 0xb8, 0xcc,
+ 0x4a, 0xfd, 0x38, 0x60, 0x12, 0x1e, 0x06, 0xaa, 0xba, 0x10, 0x8c, 0x8f,
+ 0xf0, 0xd4, 0x7c, 0x79, 0xaf, 0x76, 0xc2, 0x1f, 0x3f, 0x75, 0xaf, 0x90,
+ 0x2e, 0x08, 0xd4, 0x21, 0x05, 0xa1, 0xc6, 0xee, 0x71, 0x06, 0xca, 0xaa,
+ 0xdf, 0x6a, 0x0a, 0xc0, 0x60, 0x97, 0xb0, 0xd6, 0xfc, 0x97, 0xb9, 0x98,
+ 0xc0, 0x37, 0x7a, 0x42, 0xc6, 0x74, 0xf1, 0x9b, 0xec, 0x66, 0xf7, 0x88,
+ 0x28, 0xb0, 0xc2, 0x62, 0x72, 0x50, 0x97, 0x47, 0x40, 0x4a, 0x39, 0xee,
+ 0xc7, 0x01, 0xdb, 0xe8, 0x1e, 0xc3, 0x1f, 0xea, 0xaf, 0xfe, 0x7e, 0x8c,
+ 0xc4, 0x2f, 0xf8, 0x1f, 0xe4, 0xec, 0x38, 0x3e, 0xd6, 0x33, 0x24, 0x98,
+ 0x37, 0x6d, 0xb8, 0xd6, 0x53, 0xac, 0x2f, 0xd4, 0x27, 0xa1, 0x21, 0x85,
+ 0x23, 0x76, 0x18, 0x7b, 0x8b, 0x97, 0x06, 0xa3, 0x24, 0xac, 0x07, 0x90,
+ 0x4f, 0xe3, 0xda, 0xec, 0x59, 0x3e, 0xce, 0xf7, 0x96, 0x8c, 0x19, 0xc6,
+ 0x6c, 0x35, 0x26, 0x89, 0x1d, 0xae, 0x70, 0x68, 0x66, 0x03, 0x38, 0xa4,
+ 0x36, 0x52, 0xc8, 0xff, 0xda, 0xb7, 0x42, 0x03, 0x77, 0x1a, 0xeb, 0x3c,
+ 0x70, 0x59, 0xf7, 0x3f, 0x06, 0xa3, 0x13, 0x7f, 0x77, 0xdd, 0xdf, 0xb0,
+ 0xf9, 0xac, 0x9c, 0x4f, 0x8b, 0xf4, 0x19, 0x25, 0x6f, 0xf0, 0xc7, 0xc6,
+ 0x0f, 0x12, 0x7d, 0xe6, 0x83, 0x0a, 0xfc, 0x85, 0xc0, 0x7a, 0x95, 0x88,
+ 0xcb, 0x70, 0xb5, 0x5e, 0xcd, 0x39, 0x08, 0x3b, 0x8d, 0xbc, 0x40, 0x0d,
+ 0xf1, 0x40, 0x63, 0x65, 0xed, 0x82, 0x43, 0xcf, 0xa3, 0x8a, 0x01, 0xf4,
+ 0xef, 0xda, 0xa5, 0x25, 0x33, 0x21, 0x01, 0xff, 0xac, 0x81, 0x02, 0x66,
+ 0x1a, 0x5e, 0xc3, 0xfc, 0x4b, 0xc5, 0x23, 0x84, 0x71, 0xa2, 0xee, 0x58,
+ 0x14, 0x4e, 0x42, 0x7f, 0xfd, 0x95, 0xd8, 0x4d, 0xcc, 0x65, 0x77, 0xcd,
+ 0x04, 0x3f, 0x90, 0xde, 0x73, 0x1e, 0xe2, 0xb5, 0x68, 0x62, 0x10, 0x4d,
+ 0x4f, 0x46, 0xcd, 0x9b, 0xac, 0xd1, 0x35, 0xa1, 0x85, 0xa1, 0x1d, 0x38,
+ 0xc4, 0xa3, 0xa0, 0x69, 0x15, 0xa7, 0x42, 0x50, 0x18, 0x84, 0x9a, 0x94,
+ 0xa8, 0x46, 0xba, 0x96, 0x46, 0x6b, 0x3a, 0xc3, 0xda, 0xde, 0x19, 0x08,
+ 0x0c, 0x40, 0x0c, 0x30, 0x6a, 0x4a, 0x43, 0xf2, 0xdb, 0x12, 0x5d, 0x3b,
+ 0x61, 0xef, 0xf6, 0x16, 0x4e, 0xbd, 0xd5, 0xe4, 0xc0, 0x62, 0x1a, 0x84,
+ 0xa0, 0x84, 0x52, 0x3b, 0xe2, 0x8a, 0x58, 0x0a, 0xf9, 0xf7, 0x12, 0x5f,
+ 0xb6, 0x16, 0xbb, 0x5d, 0x5f, 0xe3, 0x19, 0xbe, 0xe5, 0xe4, 0x1f, 0xd9,
+ 0x08, 0x23, 0xd1, 0x28, 0x46, 0x25, 0x6e, 0xaf, 0xc9, 0x2c, 0x66, 0x20,
+ 0xd9, 0x72, 0x72, 0x49, 0x99, 0x03, 0x46, 0x74, 0x7e, 0x3d, 0x7b, 0x88,
+ 0xbb, 0xc8, 0xc5, 0x7e, 0xdf, 0xfc, 0xa5, 0x71, 0x63, 0xfd, 0xd6, 0x16,
+ 0xab, 0x3b, 0xca, 0x5e, 0xc5, 0x3a, 0x12, 0x86, 0xe6, 0x30, 0xe2, 0x2c,
+ 0x03, 0x72, 0x32, 0x0a, 0x53, 0x7f, 0x9f, 0x91, 0x0f, 0x90, 0xb2, 0xf7,
+ 0x41, 0x48, 0xeb, 0xf8, 0xd1, 0x43, 0xae, 0x68, 0x6a, 0x4a, 0xe5, 0x8d,
+ 0x1a, 0xe7, 0x32, 0x8e, 0x85, 0xa8, 0x3e, 0x2f, 0xa2, 0x43, 0x46, 0x28,
+ 0x66, 0x65, 0xb3, 0xfb, 0x0a, 0x50, 0x8c, 0x18, 0x57, 0x66, 0xfd, 0x64,
+ 0x03, 0x42, 0xed, 0xc4, 0x34, 0xa0, 0xb2, 0xdf, 0x77, 0x16, 0x2a, 0x62,
+ 0x6a, 0x50, 0x92, 0xf3, 0x70, 0x8c, 0xda, 0x79, 0xd4, 0x17, 0xe2, 0xf9,
+ 0xa1, 0xa8, 0x42, 0x32, 0x3b, 0x33, 0xa0, 0xe7, 0x34, 0x8f, 0x10, 0xd0,
+ 0xcd, 0xd2, 0x52, 0x11, 0x9b, 0xfd, 0x9c, 0x73, 0xdb, 0x8b, 0x2f, 0x16,
+ 0x4d, 0x70, 0x3d, 0x94, 0x1d, 0xae, 0x20, 0x19, 0x42, 0x08, 0x63, 0x5d,
+ 0xf2, 0xed, 0x16, 0x4e, 0xf4, 0xd6, 0x1b, 0x0a, 0x26, 0x06, 0x0d, 0x4f,
+ 0xe8, 0x62, 0x12, 0x1f, 0x72, 0xfb, 0x8d, 0x4a, 0x94, 0xc2, 0xdd, 0xba,
+ 0xb3, 0x5f, 0x42, 0xbc, 0xd1, 0x34, 0x94, 0x8f, 0xc0, 0x52, 0x03, 0x7e,
+ 0xb6, 0x3c, 0xd3, 0x7f, 0xe7, 0xf1, 0x43, 0xef, 0x47, 0x8f, 0x5d, 0xe7,
+ 0xa0, 0x7a, 0xed, 0xbd, 0x7f, 0xe1, 0xcb, 0xe3, 0x03, 0x03, 0x10, 0x02,
+ 0x3f, 0x69, 0x0d, 0xc8, 0x42, 0x0a, 0x6c, 0xdf, 0xe7, 0xe1, 0xe7, 0x59,
+ 0x88, 0x69, 0x29, 0x29, 0xcd, 0xdf, 0x2b, 0x08, 0xd3, 0x90, 0xd2, 0x84,
+ 0x96, 0xfb, 0xb9, 0x19, 0xae, 0xcc, 0x61, 0xe6, 0xfb, 0x2b, 0xb8, 0x9b,
+ 0xb6, 0xc5, 0x6d, 0xb6, 0xec, 0xfc, 0xfb, 0x9b, 0xc3, 0x10, 0xe2, 0x90,
+ 0x8c, 0x34, 0x48, 0xea, 0xe2, 0x1a, 0x51, 0xcb, 0x1b, 0xbb, 0x9c, 0xd8,
+ 0x74, 0xc4, 0xc2, 0xf0, 0xc2, 0xd1, 0xd2, 0x33, 0xa5, 0x97, 0x52, 0xdb,
+ 0x45, 0x69, 0xa5, 0x25, 0x23, 0x13, 0x3f, 0x2d, 0x19, 0x09, 0xff, 0x12,
+ 0xb6, 0x3c, 0x5b, 0x9e, 0xa6, 0x1f, 0x7b, 0x17, 0x6b, 0x9c, 0x58, 0xcc,
+ 0xad, 0xc6, 0x80, 0xf4, 0xe0, 0xec, 0x41, 0xba, 0x37, 0x9b, 0xad, 0xaf,
+ 0xc0, 0x93, 0x00, 0xb0, 0x0c, 0x08, 0x69, 0x02, 0x7f, 0x23, 0x11, 0x49,
+ 0xd7, 0xad, 0x26, 0x24, 0x61, 0x68, 0xe3, 0x93, 0xb8, 0x57, 0xbc, 0xa8,
+ 0x6f, 0x46, 0x02, 0x85, 0x14, 0x82, 0xd1, 0xfb, 0xf4, 0xa7, 0x0b, 0x22,
+ 0xde, 0xef, 0x2a, 0xe9, 0x42, 0xc6, 0x8b, 0xfc, 0x81, 0x47, 0x32, 0xb0,
+ 0xf0, 0x00, 0x3b, 0x26, 0x20, 0x00, 0xe4, 0x34, 0x6f, 0x08, 0xc0, 0x5d,
+ 0x22, 0x3e, 0xdd, 0x82, 0xfb, 0x5e, 0xc4, 0x9a, 0x1b, 0xc9, 0xa5, 0xf4,
+ 0xf3, 0x49, 0xc2, 0xaf, 0x1a, 0x01, 0x98, 0x15, 0x28, 0x37, 0xb1, 0x4d,
+ 0xc6, 0xe4, 0x72, 0xd2, 0x6f, 0xfb, 0x33, 0x08, 0x22, 0xdf, 0x42, 0x90,
+ 0x63, 0x8c, 0xdf, 0x8e, 0x69, 0xfb, 0x94, 0xa5, 0x2e, 0x0b, 0x5b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x88, 0x00, 0x00, 0x01, 0x14, 0x83, 0xfb, 0xfd,
+ 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0x00, 0x00, 0x01, 0x15, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x16, 0x83,
+ 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0x00, 0x00, 0x01, 0x17, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01,
+ 0x18, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x19, 0x83, 0xfb, 0xfd, 0x29,
+ 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00,
+ 0x00, 0x01, 0x1a, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x1b, 0x83, 0xfb,
+ 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0x00, 0x00, 0x01, 0x1c, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x1d,
+ 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x1e, 0x83, 0xfb, 0xfd, 0x29, 0x49,
+ 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00,
+ 0x01, 0x1f, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x20, 0x83, 0xfb, 0xfd,
+ 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0x00, 0x00, 0x01, 0x21, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0x22, 0x83,
+ 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94,
+ 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22,
+ 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b,
+ 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5,
+ 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a,
+ 0x52, 0x22, 0x00, 0x00, 0x01, 0x23, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48,
+ 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22,
+ 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9,
+ 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52,
+ 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5,
+ 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01,
+ 0x24, 0x83, 0xfb, 0xfd, 0x29, 0x49, 0x4a, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e,
+ 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94,
+ 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52, 0x22, 0xe5, 0x29,
+ 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88, 0xb9, 0x4a, 0x52,
+ 0x22, 0xe5, 0x29, 0x48, 0x8b, 0x94, 0xa5, 0x22, 0x2e, 0x52, 0x94, 0x88,
+ 0xb9, 0x4a, 0x52, 0x22, 0x00, 0x00, 0x01, 0xb7,
+};
diff --git a/plugins/streamdev/streamdev-cvs/server/suspend.h b/plugins/streamdev/streamdev-cvs/server/suspend.h
new file mode 100644
index 0000000..bea25ee
--- /dev/null
+++ b/plugins/streamdev/streamdev-cvs/server/suspend.h
@@ -0,0 +1,36 @@
+/*
+ * $Id: suspend.h,v 1.2 2008/10/22 11:59:32 schmirl Exp $
+ */
+
+#ifndef VDR_STREAMDEV_SUSPEND_H
+#define VDR_STREAMDEV_SUSPEND_H
+
+#include <vdr/player.h>
+
+class cSuspendLive: public cPlayer, public cThread {
+protected:
+ virtual void Activate(bool On);
+ virtual void Action(void);
+
+ void Stop(void);
+
+public:
+ cSuspendLive(void);
+ virtual ~cSuspendLive();
+};
+
+class cSuspendCtl: public cControl {
+private:
+ cSuspendLive *m_Suspend;
+ static bool m_Active;
+
+public:
+ cSuspendCtl(void);
+ virtual ~cSuspendCtl();
+ virtual void Hide(void) {}
+ virtual eOSState ProcessKey(eKeys Key);
+
+ static bool IsActive(void) { return m_Active; }
+};
+
+#endif // VDR_STREAMDEV_SUSPEND_H