Index: /trunk/ExpressoCertMailMessages_pt_BR.properties
===================================================================
--- /trunk/ExpressoCertMailMessages_pt_BR.properties	(revision 1035)
+++ /trunk/ExpressoCertMailMessages_pt_BR.properties	(revision 1035)
@@ -0,0 +1,8 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+ParamReaderThread001 = N\u00E3o foi poss\u00EDvel carregar Token/SmartCard: senha incorreta
+ParamReaderThread002 = Erro no processamento da assinatura.
+ParamReaderThread003 = Erro no processamento da mensagem.
+ParamReaderThread004 = Erro ao decifrar mensagem: Detectado problema na integridade da mensagem cifrada.
+ParamReaderThread005 = Problema no acesso \u00E0s informa\u00E7\u00F5es do Token.
Index: /trunk/nbproject/project.properties
===================================================================
--- /trunk/nbproject/project.properties	(revision 1035)
+++ /trunk/nbproject/project.properties	(revision 1035)
@@ -0,0 +1,6 @@
+include.path=${php.global.include.path}
+source.encoding=ISO-8859-1
+src.dir=.
+tags.asp=false
+tags.short=true
+web.root=.
Index: /trunk/nbproject/project.xml
===================================================================
--- /trunk/nbproject/project.xml	(revision 1035)
+++ /trunk/nbproject/project.xml	(revision 1035)
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.php.project</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/php-project/1">
+            <name>expresso-comunidade-trunk</name>
+        </data>
+    </configuration>
+</project>
Index: /trunk/admin/inc/hook_admin.inc.php
===================================================================
--- /trunk/admin/inc/hook_admin.inc.php	(revision 357)
+++ /trunk/admin/inc/hook_admin.inc.php	(revision 1035)
@@ -76,5 +76,19 @@
 		$file['phpInfo']         = $GLOBALS['phpgw']->link('/admin/phpinfo.php');
 	}
- 
+
+	if (! $GLOBALS['phpgw']->acl->check('asyncservice_access',1,'admin'))
+	{
+		if($GLOBALS['phpgw_info']['server']['use_assinar_criptografar']  ||  $GLOBALS['phpgw_info']['server']['certificado'])
+		{
+			$file['CASCRLS']    = $GLOBALS['phpgw']->link('../seguranca/security_admin.php');
+		}
+	}
+
+
+	if (! $GLOBALS['phpgw']->acl->check('asyncservice_access',1,'admin'))
+	{
+		$file['subversion']    = $GLOBALS['phpgw']->link('subversion.php');
+	}
+
 	if (! $GLOBALS['phpgw']->acl->check('site_config_access',1,'admin'))
 	{
Index: /trunk/admin/templates/default/config.tpl
===================================================================
--- /trunk/admin/templates/default/config.tpl	(revision 32)
+++ /trunk/admin/templates/default/config.tpl	(revision 1035)
@@ -118,4 +118,31 @@
    <tr class="th">
     <td colspan="2">&nbsp;<b>{lang_security}</b></td>
+   </tr>
+
+   <tr class="row_off">
+   <td valign="top"><pre>
+Nome, um ponto-e-virgula como separador, e o caminho completo para os drivers dos tokens
+que ser&atilde;o suportados (At&eacute; 10):<br/>
+
+   Ex:  ePass2000Lx;/usr/lib/libepsng_p11.so
+	ePass2000Win;c:/windows/system32/ngp11v211.dll
+
+        Estes s&atilde;o os drivers para o token ePass2000, utilizado no Serpro,
+        nos ambientes Linux e Windows respectivamente.
+
+        <b>Aten&ccedil;&atilde;o</b>: O caminho no ambiente Windows n&atilde;o deve usar contra barra.
+         </pre>	</td>
+    <td>
+	<input name="newsettings[test_token11]" value="{value_test_token11}"><br/>
+	<input name="newsettings[test_token21]" value="{value_test_token21}"><br/>
+	<input name="newsettings[test_token31]" value="{value_test_token31}"><br/>
+	<input name="newsettings[test_token41]" value="{value_test_token41}"><br/>
+	<input name="newsettings[test_token51]" value="{value_test_token51}"><br/>
+	<input name="newsettings[test_token61]" value="{value_test_token61}"><br/>
+	<input name="newsettings[test_token71]" value="{value_test_token71}"><br/>
+	<input name="newsettings[test_token81]" value="{value_test_token81}"><br/>
+	<input name="newsettings[test_token91]" value="{value_test_token91}"><br/>
+	<input name="newsettings[test_token101]" value="{value_test_token101}"><br/>
+    </td>
    </tr>
 
Index: /trunk/ExpressoCertLoginMessages_pt_BR.properties
===================================================================
--- /trunk/ExpressoCertLoginMessages_pt_BR.properties	(revision 1035)
+++ /trunk/ExpressoCertLoginMessages_pt_BR.properties	(revision 1035)
@@ -0,0 +1,8 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+LoginApplet001 = N\u00E3o foi poss\u00EDvel validar o certificado do servidor!
+LoginApplet002 = Algum erro ocorreu ao realizar o logon!
+LoginApplet003 = PIN incorreto!
+LoginApplet004 = N\u00E3o foi poss\u00EDvel fazer a conex\u00E3o com o servidor do Expresso.\nVerifique suas configura\u00E7\u00F5es de rede/proxy.
+LoginApplet005 = Deseja tentar carreg\u00E1-lo novamente?
Index: /trunk/ExpressoCertMessages_pt_BR.properties
===================================================================
--- /trunk/ExpressoCertMessages_pt_BR.properties	(revision 1035)
+++ /trunk/ExpressoCertMessages_pt_BR.properties	(revision 1035)
@@ -0,0 +1,14 @@
+# To change this template, choose Tools | Templates
+# and open the template in the editor.
+
+DigitalCertificate001 = Nenhum token/smartcard foi detectado.\nOpera\u00E7\u00E3o n\u00E3o p\u00F4de ser realizada!
+DigitalCertificate002 = N\u00E3o \u00E9 poss\u00EDvel ler este e-mail com o Certificado Digital apresentado!\nMotivo: Este e-mail n\u00E3o foi cifrado com a chave p\u00FAblica deste Certificado Digital.
+
+DialogBuilder001 = Entre com o seu PIN:
+DialogBuilder002 = Selecione o certificado:
+
+cancel = Cancelar
+pin = PIN
+ok = Ok
+certificate = Certificado
+select = Selecionar
Index: /trunk/setup/manageheader.php
===================================================================
--- /trunk/setup/manageheader.php	(revision 2)
+++ /trunk/setup/manageheader.php	(revision 1035)
@@ -599,4 +599,26 @@
 					break;
 			}
+
+            switch($GLOBALS['phpgw_info']['server']['use_assinar_criptografar'])
+			{
+				case '0':
+					$setup_tpl->set_var('use_assinar_criptografar_0',' checked');
+					break;
+				case '1':
+					$setup_tpl->set_var('use_assinar_criptografar_1',' checked');
+					break;
+				default:
+					$setup_tpl->set_var('use_assinar_criptografar_0',' checked');
+			}
+
+			if($GLOBALS['phpgw_info']['server']['num_max_certs_to_cipher'])
+			{
+				$setup_tpl->set_var('num_max_certs_to_cipher',$GLOBALS['phpgw_info']['server']['num_max_certs_to_cipher']);
+			}
+			else
+			{
+				$setup_tpl->set_var('num_max_certs_to_cipher','10');
+			}
+
 			if(@$GLOBALS['phpgw_info']['server']['sugestoes_email_to'])
 			{
Index: /trunk/setup/templates/default/manageheader.tpl
===================================================================
--- /trunk/setup/templates/default/manageheader.tpl	(revision 2)
+++ /trunk/setup/templates/default/manageheader.tpl	(revision 1035)
@@ -102,5 +102,27 @@
 		<INPUT type="radio"{use_https_2} name="setting[use_https]" value="2">Usar HTTPS no Site inteiro.<BR>	
   	</td></tr>
-		
+
+    <tr><td colspan="2">
+	<fieldset><legend>Segurança</legend>
+	<table>
+	<tr><td colspan="2"><b>Habilitar Assinar/Cifrar digitalmente?</b></td></tr>
+	        <tr><td colspan="2">
+		<INPUT type="radio" {use_assinar_criptografar_0} name="setting[use_assinar_criptografar]" value="0"  />NAO habilitar.<BR>
+		<INPUT type="radio" {use_assinar_criptografar_1} name="setting[use_assinar_criptografar]" value="1" />Habilitar.<BR>
+	</td></tr>
+	<tr><td colspan="2"><b>Numero maximo de destinatários para uma mensagem cifrada:</b><br>Este valor e utilizado se Assinar/Criptografar for habilitado.</td></tr>
+  	<tr><td colspan="2">
+		<INPUT type="text" maxlength="2" size="3" name="setting[num_max_certs_to_cipher]" id="maxcerttxt" value="{num_max_certs_to_cipher}" onkeypress="return soNumero(this, event);">
+  	</td></tr>
+	<!--
+	<tr><td colspan="2"><b>Aponta um certificado corporativo:</b><br> Este certificado sera incluido como destinatario adicional, quando cifrar uma msg.</td></tr>
+  	<tr><td colspan="2">
+		<INPUT type="text"  size="40" name="setting[corporative_certificate]" id="corpcerttxt" value="{corporative_certificate}" >
+  	</td></tr>
+	-->
+	</fieldset>
+           </table>
+	   <br>
+
 	<tr><td colspan="2"><b>Digite os endereços de emails, separados por vírgula, que devem receber as sugestões enviados pelos usuários.</b></td></tr>
 	<tr><td colspan="2"><INPUT size="50" name="setting[sugestoes_email_to]" value="{sugestoes_email_to}"></td></tr>
Index: /trunk/preferences/preferences.php
===================================================================
--- /trunk/preferences/preferences.php	(revision 1002)
+++ /trunk/preferences/preferences.php	(revision 1035)
@@ -122,4 +122,5 @@
 			$def_text = $def_text != '' ? ' <i><font size="-1">'.lang('default').':&nbsp;'.$def_text.'</font></i>' : '';
 		}
+        $t->set_var('row_id', "${GLOBALS[type]}[$name]");
 		$t->set_var('row_value',"<input name=\"${GLOBALS[type]}[$name]\"value=\"".
 			@htmlentities($default,ENT_COMPAT,$charSet)."\"$options>$def_text");
@@ -148,5 +149,5 @@
 	}
 
-	function create_check_box($label,$name,$help='',$default='',$run_lang=True)
+	function create_check_box($label,$name,$help='',$default='',$run_lang=True,$checkbox_prop='',$visible=True)
 	{
 		// checkboxes itself can't be use as they return nothing if uncheckt !!!
@@ -165,5 +166,5 @@
 			'0' => lang('No'),
 			'1' => lang('Yes')
-		),$help,$default,$run_lang);
+		),$help,$default,$run_lang,$checkbox_prop,$visible);
 	}
 
@@ -196,4 +197,5 @@
 	{
 		global $t,$prefs;
+        $t->set_var('row_id', "${GLOBALS[type]}[$name]");
 		$t->set_var('row_value',$code.$prefs[$name].$appendcode);
 		$t->set_var('row_name',lang("signature"));
@@ -202,5 +204,5 @@
 	}
 
-	function create_select_box($label,$name,$values,$help='',$default='',$run_lang=True,$select_prop = '')
+	function create_select_box($label,$name,$values,$help='',$default='',$run_lang=True,$select_prop = '',$visible=True)
 	{
 		global $t,$prefs;
@@ -235,8 +237,18 @@
 			$def_text = $def_text != '' ? ' <i><font size="-1">'.lang('default').':&nbsp;'.$values[$def_text].'</font></i>' : '';
 		}
+        $t->set_var('row_id', "${GLOBALS[type]}[$name]");
 		$t->set_var('row_value',"<select name=\"${GLOBALS[type]}[$name]\" $select_prop>$s</select>$def_text");
 		$t->set_var('row_name',lang($label));
+        if ($visible)
+        {
+            $t->set_var('row_visibility', '');
+        }
+        else
+        {
+            $t->set_var('row_visibility', 'style="display: none;"');
+        }
+        
 		$GLOBALS['phpgw']->nextmatchs->template_alternate_row_color($t);
-
+        
 		$t->fp('rows',process_help($help,$run_lang) ? 'help_row' : 'row',True);
 	}
@@ -314,4 +326,5 @@
 			$def_text = $def_text != '' ? '<br><i><font size="-1"><b>'.lang('default').'</b>:<br>'.nl2br($def_text).'</font></i>' : '';
 		}
+        $t->set_var('row_id', "${GLOBALS[type]}[$name]");
 		$t->set_var('row_value',"<textarea rows=\"$rows\" cols=\"$cols\" name=\"${GLOBALS[type]}[$name]\">".
 			htmlentities($default,ENT_COMPAT,$charSet)."</textarea>$def_text");
Index: /trunk/preferences/templates/default/preferences.tpl
===================================================================
--- /trunk/preferences/templates/default/preferences.tpl	(revision 2)
+++ /trunk/preferences/templates/default/preferences.tpl	(revision 1035)
@@ -30,5 +30,5 @@
 
 <!-- BEGIN row -->
- <tr bgcolor="{tr_color}">
+ <tr id="{row_id}" bgcolor="{tr_color}" {row_visibility}>
   <td>{row_name}</td>
   <td>{row_value}</td>
Index: /trunk/preferences/templates/azul/preferences.tpl
===================================================================
--- /trunk/preferences/templates/azul/preferences.tpl	(revision 1026)
+++ /trunk/preferences/templates/azul/preferences.tpl	(revision 1035)
@@ -23,5 +23,5 @@
 
 <!-- BEGIN row -->
- <tr bgcolor="{tr_color}">
+ <tr id="{row_id}" bgcolor="{tr_color}" {row_visibility}>
   <td>{row_name}</td>
   <td>{row_value}</td>
Index: /trunk/seguranca/ExpressoCertLogin/manifest.mf
===================================================================
--- /trunk/seguranca/ExpressoCertLogin/manifest.mf	(revision 1035)
+++ /trunk/seguranca/ExpressoCertLogin/manifest.mf	(revision 1035)
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
Index: /trunk/seguranca/ExpressoCertLogin/src/LoginApplet.java
===================================================================
--- /trunk/seguranca/ExpressoCertLogin/src/LoginApplet.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertLogin/src/LoginApplet.java	(revision 1035)
@@ -0,0 +1,831 @@
+
+import java.awt.Frame;
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.ProviderException;
+
+import javax.net.ssl.SSLHandshakeException;
+import javax.swing.JApplet;
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+import org.apache.commons.httpclient.HttpException;
+
+import netscape.javascript.JSObject;
+
+import br.gov.serpro.cert.DigitalCertificate;
+import br.gov.serpro.setup.Setup;
+import br.gov.serpro.ui.DialogBuilder;
+
+/**
+ * GUI que realiza o login com certificados A1 e A3 ou login com usuário e senha no expresso.
+ * Esta classe estende a classe JApplet
+ * @author Mário César Kolling - mario.kolling@serpro.gov.br
+ */
+public class LoginApplet extends JApplet{
+
+	/**
+	 * Valor gerado aleatoriamente
+	 */
+
+	//TODO: Alterar a cor e fonte dos labels e das caixas de texto e senha.
+	private static final long serialVersionUID = -6204158613173951516L;
+
+	//private PinCodePanel pinPanel;
+	//private LoginPanel loginPanel;
+	//private PinCodePanel alreadyLoadedPanel;
+	//private int useCertificate = DigitalCertificate.KEYSTORE_DETECTED;
+//	private String uid;
+	private DigitalCertificate dc;
+    private Setup setup;
+
+	/* (non-Javadoc)
+	 * @see java.applet.Applet#init()
+	 */
+	public void init() {
+		super.init();
+		this.setSize(0, 0);
+        this.setup = new Setup(this);
+        this.setup.addLanguageResource("ExpressoCertLoginMessages");
+	}
+
+	/* (non-Javadoc)
+	 * @see java.applet.Applet#start()
+	 */
+	@Override
+	public void start() {
+		super.start();
+
+		int useCertificate = DigitalCertificate.KEYSTORE_NOT_DETECTED;
+		boolean tryAgain = true;
+
+		do
+		{
+
+			// Cria uma instância de DigitalCertificate e a inicializa
+			this.dc = new DigitalCertificate(this.getDocumentBase(), setup);
+			useCertificate = dc.init();
+			String[] returnCode = null;
+
+			try {
+				switch (useCertificate){
+					case DigitalCertificate.KEYSTORE_DETECTED:
+						// Mostra PinNeedeDialog.
+						//tryAgain = false;
+						String pin = DialogBuilder.showPinDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), this.setup);
+						if (pin != null) {
+							dc.openKeyStore(pin.toCharArray());
+							returnCode = dc.getCredentials(pin);
+
+							// se chegou aqui, keystore foi acessada e as credenciais do usuário foram recuperadas
+							//tryAgain = false;
+							assert (returnCode != null): "Valor de returnCode não pode ser nulo";
+
+							//this.dc.destroy();
+
+							// Faz o login
+
+                            if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                                System.out.println("Código de retorno: " + returnCode[0].trim());
+                            }
+
+							if (Integer.parseInt(returnCode[0].trim()) == 0){
+
+								tryAgain = false;
+								// Pega usuário e senha de credentials[1] e credentials[2], respectivamente
+								// adiciona na página e faz o submit.
+								JSObject document = (JSObject) JSObject.getWindow( this ).getMember("document");
+								JSObject loginForm =  (JSObject) document.getMember("flogin");
+								JSObject loginField = (JSObject) loginForm.getMember("user");
+								loginField.setMember("value", returnCode[1].trim());
+
+								JSObject passwdField = (JSObject) loginForm.getMember("passwd");
+								passwdField.setMember("value", returnCode[2].trim());
+
+								loginForm.call("submit", null);
+								Thread.yield();
+
+							}
+							else if (Integer.parseInt(returnCode[0].trim()) == 6){
+
+								tryAgain = false;
+
+								if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                                    System.out.println("Mensagem de retorno: " + returnCode[1].trim());
+                                }
+
+								//JOptionPane.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), credentials[1]);
+								DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), returnCode[1].trim(), this.setup);
+
+
+
+								String redirect = this.getCodeBase().toExternalForm() + "login.php?cd=98&ts=202";
+								try {
+									this.getAppletContext().showDocument(new URL(redirect));
+								} catch (MalformedURLException e) {
+									// TODO Bloco catch gerado automaticamente
+                                    if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                                        e.printStackTrace();
+                                    }
+								}
+							}
+							else {
+								tryAgain = true;
+								dc.destroy();
+								System.gc();
+
+                                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                                    System.out.println("Mensagem de retorno: " + returnCode[1].trim());
+                                }
+
+								// Mostra mensagem de erro para o usuário
+								//JOptionPane.showMessageDialog(this, credentials[1]);
+								DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), returnCode[1].trim(), this.setup);
+								Thread.yield();
+							}
+
+						}
+						else {
+
+							tryAgain = false;
+							String redirect = this.getCodeBase().toExternalForm() + "login.php";
+							try {
+								this.getAppletContext().showDocument(new URL(redirect));
+							} catch (MalformedURLException e) {
+								// TODO Bloco catch gerado automaticamente
+                                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                                    e.printStackTrace();
+                                }
+							}
+						}
+
+						break;
+						/*
+					case DigitalCertificate.KEYSTORE_ALREADY_LOADED:
+						// Mostra PinNotNeededDialog
+						tryAgain = false;
+
+						//Verifica na página se operação anterior foi um logout
+						JSObject document = (JSObject) JSObject.getWindow( this ).getMember("document");
+						JSObject loginForm =  (JSObject) document.getMember("flogin");
+						JSObject loginField = (JSObject) loginForm.getMember("cd");
+						String cdValue = (String) loginField.getMember("value");
+
+						int cd = 0;
+						if (cdValue.length() != 0){
+							cd = Integer.parseInt(cdValue);
+						}
+
+						// Se não foi logout prossegue com o login, senão pára tudo
+						if (cd != 1 && cd != 5){
+
+							DialogBuilder.showPinNotNeededDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this));
+							dc.openKeyStore(null);
+							returnCode = dc.getCredentials("");
+
+							// se chegou aqui, keystore foi acessada e as credenciais do usuário foram recuperadas
+							assert (returnCode != null): "Valor de returnCode não pode ser nulo";
+
+							// Faz o login
+							doLogin(returnCode);
+						}
+						else if (cd == 5){
+							JOptionPane.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+									"Não foi possível realizar o Logon com certificado!");
+							// Redireciona para a tela de login
+							String redirect = this.getCodeBase().toExternalForm() + "login.php";
+							try {
+								this.getAppletContext().showDocument(new URL(redirect));
+							} catch (MalformedURLException e) {
+								// TODO Bloco catch gerado automaticamente
+								e.printStackTrace();
+							}
+
+						}
+
+						//DialogBuilder.showPinNotNeededDialog(findParentframe());
+
+						break;
+						*/
+					default:
+
+						// Mostra Diálogo dizendo que token não foi encontrado
+						// ou repositório de chaves públicas não foi configurado.
+						// Tentar carregar token/keystore novamente? / Logon sem certificado digital?
+
+						tryAgain = false;
+                        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                            System.out.println("não achou token");
+                        }
+						
+						dc.destroy();
+						System.gc();
+
+						String redirect = this.getCodeBase().toExternalForm() + "login.php";
+						try {
+							this.getAppletContext().showDocument(new URL(redirect));
+						} catch (MalformedURLException e) {
+							// TODO Bloco catch gerado automaticamente
+                            if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                                e.printStackTrace();
+                            }
+						}
+
+						//int resultado = JOptionPane.showConfirmDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+						//	"Deseja tentar novamente?",
+						//	"Token não foi encontrado!",
+						//	JOptionPane.OK_CANCEL_OPTION,
+						//	JOptionPane.QUESTION_MESSAGE);
+
+						//if (resultado == JOptionPane.OK_OPTION){
+						//	tryAgain = true;
+						//}
+						//else {
+
+						//}
+
+						// if () {
+						//	tryAgain = true;
+						//}
+				}
+
+			}
+			catch (SSLHandshakeException e){
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+				dc.destroy();
+				System.gc();
+				//JOptionPane.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), "Não foi possível validar o certificado do servidor!");
+				//DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+				//		"Não foi possível validar o certificado do servidor!", this.setup);
+                DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+						this.setup.getLang("ExpressoCertLoginMessages", "LoginApplet001"), this.setup);
+
+				Thread.yield();
+
+				tryAgain = true;
+			}
+			catch (HttpException e) {
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+				
+				tryAgain = true;
+				Thread.yield();
+			}
+			catch (GeneralSecurityException e){
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+				
+				//DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+				//		"Algum erro ocorreu ao realizar o logon!", this.setup);
+                DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+						this.setup.getLang("ExpressoCertLoginMessages", "LoginApplet002"), this.setup);
+
+				Thread.yield();
+				tryAgain = true;
+			}
+			catch (IOException e) {
+				dc.destroy();
+				System.gc();
+
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+                //System.out.println("Classe que originou o erro de IO: " + e.getClass().getCanonicalName());;
+
+                Throwable cause = null;
+                if ((cause = e.getCause()) != null){
+                    if (cause instanceof javax.security.auth.login.LoginException){
+                        //DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), "PIN incorreto!", this.setup);
+                        DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), this.setup.getLang("ExpressoCertLoginMessages", "LoginApplet003"), this.setup);
+                    } else {
+                        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                            System.out.println("Exception lançada: " + cause.getClass().getCanonicalName());
+                        }
+                    }
+                }
+                else {
+                    if (e instanceof java.net.ConnectException){
+                        //DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+                        //        "Não foi possível fazer a conexão com o servidor do Expresso.\n" +
+                        //        "Verifique suas configurações de rede/proxy.", this.setup);
+                        DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+                                this.setup.getLang("ExpressoCertLoginMessages", "LoginApplet004"), this.setup);
+                    } else {
+                        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                            System.out.println("Exception lançada: " + e.getClass().getCanonicalName());
+                        }
+                    }
+                }
+
+				Thread.yield();
+                tryAgain = true;
+			}
+			catch (ProviderException e) {
+				// Tentar novamente / cancel
+				//JOptionPane.showMessageDialog(this, "Token foi removido! Favor inserir seu token");
+
+				dc.destroy();
+				System.gc();
+
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+
+/*
+				JOptionPane optionPane = new JOptionPane("Token foi removido\nDeseja tentar carregá-lo novamente?",
+						JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
+				JDialog dialog = new JDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), true);
+				dialog.setContentPane(optionPane);
+				//Posicionando no centro da tela.
+
+				Dimension mySize = dialog.getSize();
+				Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+				dialog.setLocation(screenSize.width/2 - (mySize.width/2), screenSize.height/2 - (mySize.height/2));
+				dialog.setVisible(true);
+
+				Object selectedValue = optionPane.getValue();
+
+				if (selectedValue == null){
+
+				}
+				else {
+					if (selectedValue instanceof Integer){
+						Integer
+					}
+				}
+*/
+
+				int resultado = DialogBuilder.showConfirmDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+						//"Deseja tentar carregá-lo novamente?",
+                        this.setup.getLang("ExpressoCertLoginMessages", "LoginApplet005"),
+						JOptionPane.QUESTION_MESSAGE,
+						JOptionPane.OK_CANCEL_OPTION, this.setup);
+
+/*				int resultado = JOptionPane.showConfirmDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this),
+						"Deseja tentar carregá-lo novamente?",
+						"Token foi removido!",
+						JOptionPane.OK_CANCEL_OPTION,
+						JOptionPane.QUESTION_MESSAGE);
+*/
+
+				if (resultado == JOptionPane.OK_OPTION){
+					tryAgain = true;
+				}
+				else {
+					tryAgain = false;
+				}
+
+				Thread.yield();
+			}
+
+		}
+		while (tryAgain);
+
+		// chama o método que cria a interface na thread de lançamento de eventos (Event Dispatching Thread).
+		//try
+		//{
+		//	SwingUtilities.invokeAndWait(new Runnable(){
+
+				/* (non-Javadoc)
+				 * @see java.lang.Runnable#run()
+				 */
+		//		public void run() {
+		//			createGUI();
+		//		}
+
+		//	});
+		//} catch (Exception e){
+		//	System.out.println("Método createGUI não pôde ser carregado: " + e.getMessage());
+		//}
+
+	}
+
+	/*
+
+	public void doLogin(String[] credentials){
+
+		if (Integer.valueOf(credentials[0]) == 0){
+
+			// Pega usuário e senha de credentials[1] e credentials[2], respectivamente
+			// adiciona na página e faz o submit.
+			JSObject document = (JSObject) JSObject.getWindow( this ).getMember("document");
+			JSObject loginForm =  (JSObject) document.getMember("flogin");
+			JSObject loginField = (JSObject) loginForm.getMember("user");
+			loginField.setMember("value", credentials[1]);
+
+			JSObject passwdField = (JSObject) loginForm.getMember("passwd");
+			passwdField.setMember("value", credentials[2]);
+
+			loginForm.call("submit", null);
+
+		}
+		else if (Integer.valueOf(credentials[0]) == 6){
+
+			//JOptionPane.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), credentials[1]);
+			DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), credentials[1]);
+			String redirect = this.getCodeBase().toExternalForm() + "login.php?cd=98&ts=202";
+			try {
+				this.getAppletContext().showDocument(new URL(redirect));
+			} catch (MalformedURLException e) {
+				// TODO Bloco catch gerado automaticamente
+				e.printStackTrace();
+			}
+		}
+		else {
+			// Mostra mensagem de erro para o usuário
+			//JOptionPane.showMessageDialog(this, credentials[1]);
+			DialogBuilder.showMessageDialog((Frame) SwingUtilities.getAncestorOfClass(Frame.class, this), credentials[1]);
+		}
+
+	}
+
+	*/
+
+	/**
+	 * Destrói a Applet, executando códigos para desregistrar tokens, keystores, etc.
+	 */
+	@Override
+	public void stop() {
+		//super.destroy();
+        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+            System.out.println("Finalizando Applet de Login!");
+        }
+		
+		this.dc.destroy();
+		this.dc = null;
+		//Component[] components = this.getComponents();
+		//for (Component component : components){
+		//	this.remove(component);
+		//	component = null;
+		//}
+		System.gc();
+	}
+
+	/**
+	 * Cria a interface e seleciona o Painel que será exibido de acordo com o parâmetro useCertificate
+	 */
+	/*
+	private void createGUI(){
+
+		this.setLayout(new FlowLayout());
+		this.getContentPane().setBackground(Color.WHITE);
+
+		JSObject document = (JSObject) JSObject.getWindow( this ).getMember("document");
+		JSObject loginForm =  (JSObject) document.getMember("flogin");
+		JSObject loginField = (JSObject) loginForm.getMember("user");
+
+		uid = loginField.getMember("value").toString();
+
+		pinPanel = new PinCodePanel(uid, true); // mostra pinCodeField
+		alreadyLoadedPanel = new PinCodePanel(uid, false); // não mostra pinCodeField
+		loginPanel = new LoginPanel(uid);
+
+		switch (useCertificate){
+			case DigitalCertificate.KEYSTORE_NOT_DETECTED:
+				// Mostra interface de login com usuário e senha
+				this.getContentPane().add(loginPanel);
+				break;
+			case DigitalCertificate.KEYSTORE_ALREADY_LOADED:
+				// Mostra interface de login sem pedir o pin
+				this.getContentPane().add(alreadyLoadedPanel);
+				break;
+			default:
+				// Mostra interface de login pedindo o pin
+				this.getContentPane().add(pinPanel);
+
+		}
+
+		this.setVisible(true);
+
+	}
+	*/
+
+	/**
+	 * Ação executada quando o Botão cancel de PinPanel for pressionado
+	 *
+	 */
+	/*
+	private void cancelButtonActionPerformed(){
+
+		pinPanel.setVisible(false);
+		this.remove(pinPanel);
+		this.add(loginPanel);
+		loginPanel.setVisible(true);
+		this.setVisible(true);
+		pinPanel.clearPasswordField();
+
+	}
+	*/
+
+	/**
+	 * Ação realizada quando o usuário pressiona o botão Ok ou Prossegir
+	 * nas telas de login com pin ou sem o pin, respectivamente
+	 *
+	 */
+	/*
+	private void okButtonActionPerformed(){
+		// atribui o valor da senha para o atributo Pin
+		char[] pin = pinPanel.getPin();
+		String[] returnCode = null;
+
+		// abre a keystore com o pin e recupera as credenciais do usuário
+		try {
+			dc.openKeyStore(pin);
+
+			returnCode = dc.getCredentials(new String(pin));
+
+			assert (returnCode != null): "Valor de returnCode não pode ser nulo";
+
+			if (Integer.valueOf(returnCode[0]) == 0){
+
+				// Pega usuário e senha de returnCode[1] e returnCode[2], respectivamente
+				// adiciona na página e faz o submit.
+				JSObject document = (JSObject) JSObject.getWindow( this ).getMember("document");
+				JSObject loginForm =  (JSObject) document.getMember("flogin");
+				JSObject loginField = (JSObject) loginForm.getMember("user");
+				loginField.setMember("value", returnCode[1]);
+
+				JSObject passwdField = (JSObject) loginForm.getMember("passwd");
+				passwdField.setMember("value", returnCode[2]);
+
+				this.pinPanel.clearPasswordField();
+				loginForm.call("submit", null);
+
+			}
+			else {
+				// Mostra mensagem de erro para o usuário
+				showGetCredentialsError(returnCode[1]);
+			}
+
+		} catch (SSLHandshakeException e){
+			e.printStackTrace();
+			JOptionPane.showMessageDialog(this, "Não foi possível validar o certificado do servidor!");
+		} catch (HttpException e) {
+			e.printStackTrace();
+		} catch (GeneralSecurityException e){
+			e.printStackTrace();
+		} catch (IOException e) {
+			JOptionPane.showMessageDialog(this, "Senha não confere!");
+		} catch (ProviderException e) {
+			JOptionPane.showMessageDialog(this, "Token foi removido!");
+		} finally {
+			this.pinPanel.clearPasswordField();
+		}
+
+	}
+	*/
+
+	/**
+	 * Ação realizada quando o usuário pressiona o botão acessar na
+	 * tela de login com usuário e senha
+	 *
+	 */
+	/*
+	private void acessarButtonActionPerformed(){
+
+		// Pega usuário e senha dos campos tfUsername e pfPasswd, respectivamente,
+		// adiciona na página e faz o submit.
+		String username = this.loginPanel.tfUsername.getText();
+		String passwd = String.valueOf(this.loginPanel.pfPasswd.getPassword());
+
+		JSObject document = (JSObject) JSObject.getWindow( this ).getMember("document");
+		JSObject loginForm =  (JSObject) document.getMember("flogin");
+		JSObject loginField = (JSObject) loginForm.getMember("user");
+		loginField.setMember("value", username);
+
+		JSObject passwdField = (JSObject) loginForm.getMember("passwd");
+		passwdField.setMember("value", passwd);
+
+		this.loginPanel.clearPasswordField();
+		loginForm.call("submit", null);
+
+	}
+	*/
+
+	/**
+	 * Mostra mensagem "Campo PIN não foi preenchido!" quando o botão Ok for pressionado
+	 *  e o campo pin estiver vazio
+	 *
+	 */
+	/*
+	private void okButtonPinEmpty(){
+		JOptionPane.showMessageDialog(this, "Campo PIN não foi preenchido!");
+	}
+	*/
+
+	/**
+	 * Mostra mensagem de erro recebida de dc.getCredentials();
+	 * TODO: Mudar este método para ser mais genérico... Todas as mensagens de erro devem ser passadas para este
+	 * 		método para serem exibidas.
+	 * @param errorMsg Mensagem de erro que deve ser exibida
+	 */
+	/*
+	private void showGetCredentialsError(String errorMsg){
+		JOptionPane.showMessageDialog(this, errorMsg);
+	}
+
+	private final class PinCodePanel extends JPanel  implements ActionListener{
+*/
+		/**
+		 * Gerado automaticamente
+		 */
+	/*
+		private static final long serialVersionUID = 1003857725229120014L;
+
+		JPanel pNorte, pCentro, pSul;
+		JButton btOk, btCancel;
+		JLabel lTitle, lPin;
+		JPasswordField pfPin;
+
+		// TODO: Implementar um construtor default (sem parâmetros);
+		public PinCodePanel(String uid, boolean showPinField){
+
+			this.setLayout(new BorderLayout());
+			Dimension panelsDimension = new Dimension(300, 42);
+			Dimension fieldsDimension = new Dimension(80, 20);
+
+			pNorte = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			pNorte.setBackground(Color.WHITE);
+			pNorte.setPreferredSize(panelsDimension);
+
+			pCentro = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			pCentro.setBackground(Color.WHITE);
+			pCentro.setPreferredSize(panelsDimension);
+
+			pSul = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			pSul.setBackground(Color.WHITE);
+			pSul.setPreferredSize(panelsDimension);
+
+			JPanel pTitle = new JPanel(new GridLayout(2, 0));
+			pTitle.setBackground(Color.WHITE);
+			JLabel lTitle2 = null;
+
+
+			if (showPinField){
+				lTitle = new JLabel("Entre com o seu PIN:");
+				lTitle.setHorizontalTextPosition(SwingConstants.CENTER);
+
+				pfPin = new JPasswordField(20);
+				pfPin.setPreferredSize(fieldsDimension);
+				pfPin.addActionListener(this);
+				pfPin.setActionCommand("ok");
+				pCentro.add(pfPin);
+				btOk = new JButton("Ok");
+				btCancel = new JButton("Cancel");
+			}
+			else {
+				lTitle = new JLabel("Token inserido e desbloqueado");
+				lTitle.setHorizontalTextPosition(SwingConstants.CENTER);
+				lTitle2 = new JLabel(" pelo usuário " + uid + " foi detectado:");
+				lTitle2.setHorizontalTextPosition(SwingConstants.CENTER);
+				btOk = new JButton("Prossegir");
+			}
+
+			JPanel pTitle1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			pTitle1.setPreferredSize(new Dimension(300, 20));
+			pTitle1.setBackground(Color.WHITE);
+			pTitle1.add(lTitle);
+			pTitle.add(pTitle1);
+			if (lTitle2 != null) {
+				JPanel pTitle2 = new JPanel(new FlowLayout(FlowLayout.CENTER));
+				pTitle2.setPreferredSize(new Dimension(300,20));
+				pTitle2.setBackground(Color.WHITE);
+				pTitle.add(pTitle2);
+				pTitle2.add(lTitle2);
+			}
+
+			pNorte.add(pTitle);
+
+			btOk.setMnemonic(KeyEvent.VK_ENTER);
+			btOk.setActionCommand("ok");
+			btOk.addActionListener(this);
+			pSul.add(btOk);
+
+			if (btCancel != null){
+				btCancel.setActionCommand("cancel");
+				btCancel.addActionListener(this);
+				pSul.add(btCancel);
+			}
+
+			this.add(pNorte, BorderLayout.NORTH);
+			this.add(pCentro, BorderLayout.CENTER);
+			this.add(pSul, BorderLayout.SOUTH);
+		}
+
+		// design ruim!!! azar :-S
+		public char[] getPin() {
+			if (pfPin == null){
+				return null;
+			}
+			return pfPin.getPassword();
+		}
+
+		void clearPasswordField(){
+			if (pfPin != null){
+				pfPin.setText("");
+			}
+		}
+
+		public void actionPerformed(ActionEvent evt) {
+
+			String command = evt.getActionCommand();
+
+			// Atribui o valor digitado para o campo
+			// senha e esconde a interface e assina o certificado
+			if (command.equals("ok")){
+
+				if (pfPin != null && pfPin.getPassword().length <= 0){
+					// Mostra um aviso de que o campo PIN não foi preenchido
+					okButtonPinEmpty();
+				}
+				else {
+					okButtonActionPerformed();
+				}
+
+			}
+			else if (command.equals("cancel")){
+				cancelButtonActionPerformed();
+			}
+		}
+
+
+	}
+
+	private final class LoginPanel extends JPanel implements ActionListener{
+*/
+		/**
+		 *
+		 */
+	/*
+		private static final long serialVersionUID = -8604718192554937222L;
+		JButton btAcessar;
+		JTextField tfUsername;
+		JPasswordField pfPasswd;
+
+		public LoginPanel(String uid){
+
+			this.setLayout(new BorderLayout());
+
+			JPanel panelCredentials = new JPanel(new GridLayout(2, 0));
+			panelCredentials.setBackground(Color.WHITE);
+			panelCredentials.setPreferredSize(new Dimension(280, 84));
+
+			JPanel panelUsername = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			panelUsername.setBackground(Color.WHITE);
+			panelUsername.setPreferredSize(new Dimension(300, 42));
+
+			JLabel labelUsername = new JLabel("Usuário");
+			panelUsername.add(labelUsername);
+			labelUsername.setPreferredSize(new Dimension(100, 40));
+
+			tfUsername = new JTextField(15);
+			tfUsername.setText(uid);
+			panelUsername.add(tfUsername);
+
+			JPanel panelPasswd = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			panelPasswd.setPreferredSize(new Dimension(300, 42));
+			JLabel labelPasswd = new JLabel("Senha");
+			panelPasswd.add(labelPasswd);
+			panelPasswd.setBackground(Color.WHITE);
+			labelPasswd.setPreferredSize(new Dimension(100, 20));
+
+			pfPasswd = new JPasswordField(15);
+			panelPasswd.add(pfPasswd);
+
+			panelCredentials.add(panelUsername);
+			panelCredentials.add(panelPasswd);
+			this.add(panelCredentials, BorderLayout.CENTER);
+
+			btAcessar = new JButton("Acessar");
+			btAcessar.setActionCommand("acessar");
+			btAcessar.addActionListener(this);
+			JPanel panelBtAcessar = new JPanel(new FlowLayout(FlowLayout.CENTER));
+			panelBtAcessar.setBackground(Color.WHITE);
+			panelBtAcessar.setPreferredSize(new Dimension(300, 42));
+			panelBtAcessar.add(btAcessar);
+
+			this.add(panelBtAcessar, BorderLayout.SOUTH);
+			this.setVisible(true);
+
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			if (e.getActionCommand().equals("acessar")){
+				acessarButtonActionPerformed();
+			}
+
+		}
+
+		void clearPasswordField(){
+			pfPasswd.setText("");
+		}
+
+	}
+	*/
+
+}
Index: /trunk/seguranca/ExpressoCertLogin/TestApplet.html
===================================================================
--- /trunk/seguranca/ExpressoCertLogin/TestApplet.html	(revision 1035)
+++ /trunk/seguranca/ExpressoCertLogin/TestApplet.html	(revision 1035)
@@ -0,0 +1,24 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+<title>Insert title here</title>
+
+<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93">
+  <param name="type" value="application/x-java-applet;version=1.4">
+  <param name="code" value="LoginApplet.class">
+  <param name="archive" value="ExpressoCert.jar">
+    <comment>
+      <embed code="LoginApplet.class" archive="ExpressoCert.jar"
+        type="application/x-java-applet;version=1.4">
+        <noembed>
+          No Java Support.
+        </noembed>
+      </embed>
+    </comment>
+  </object>
+</head>
+<body>
+
+</body>
+</html>
Index: /trunk/seguranca/ExpressoCertLogin/build.xml
===================================================================
--- /trunk/seguranca/ExpressoCertLogin/build.xml	(revision 1035)
+++ /trunk/seguranca/ExpressoCertLogin/build.xml	(revision 1035)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="ExpressoCertLogin_trunk" default="default" basedir=".">
+    <description>Builds, tests, and runs the project ExpressoCertLogin_trunk.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="ExpressoCertLogin_trunk-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
Index: /trunk/seguranca/ExpressoCert/manifest.mf
===================================================================
--- /trunk/seguranca/ExpressoCert/manifest.mf	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/manifest.mf	(revision 1035)
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/setup/Setup.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/setup/Setup.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/setup/Setup.java	(revision 1035)
@@ -0,0 +1,182 @@
+package br.gov.serpro.setup;
+import java.applet.Applet;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+
+public class Setup {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = -8164125429139606589L;
+
+	private Properties parameters;
+	private Properties preferences;
+    private Map<String, ResourceBundle> langResources;
+    Locale currentLocale;
+	private Applet currentApplet;
+	
+    private static final String PREFERENCES_PATH;
+    private static final String EPASS_2000;
+
+    static {
+
+        //PrintStream ps = new PrintStream(System.out);
+		//System.getProperties().list(System.out);
+
+        if (System.getProperty("os.name").equalsIgnoreCase("linux")){
+			EPASS_2000 = "/usr/lib/libepsng_p11.so";
+		}
+		else {
+			EPASS_2000 = System.getenv("SystemRoot").replaceAll("\\\\", "/")+"/system32/ngp11v211.dll";
+            //EPASS_2000 = System.getenv("ProgramFiles")+"\\Gemplus\\GemSafe Libraries\\BIN\\gclib.dll";
+		}
+
+
+		PREFERENCES_PATH = "TESTE";
+
+	}
+
+	public Setup(Applet applet){
+
+		this.currentApplet = applet;
+		parameters = new Properties();
+		//preferences = Do arquivo apontado por preferences_path
+
+		// Pega os parâmetros da applet
+		for (String[] parameter: getParameterInfo()){
+			String parameterName = parameter[0];
+			String parameterValue = this.currentApplet.getParameter(parameterName);
+
+			//System.out.println("Parameter a ser adicionado - " + parameterName + "= " + parameterValue);
+
+			if (parameterValue != null && !parameterValue.equals("")){
+				parameters.setProperty(parameterName.toLowerCase(), parameterValue);
+                if (parameterName.equalsIgnoreCase("locale")){
+                    System.out.println("Locale recebido.");
+                }
+			}
+            else {
+                //Defaults
+                if (parameterName.equalsIgnoreCase("debug")){
+                    parameters.setProperty(parameterName.toLowerCase(), "false");
+                }
+                if (parameterName.equalsIgnoreCase("token")){
+                    parameters.setProperty(parameterName.toLowerCase(), "Epass2000;"+EPASS_2000);
+                }
+                if (parameterName.equalsIgnoreCase("locale")){
+                    System.out.println("Locale não recebido, definindo valor default.");
+                    parameters.setProperty(parameterName.toLowerCase(), "pt_BR");
+                }
+            }
+		}
+
+		//TODO: Pega as preferências do arquivo de preferências se encontrado;
+
+        // Lang Resources
+        currentLocale = this.buildLocale(parameters.getProperty("locale"));
+        langResources = new HashMap<String, ResourceBundle>(2);
+        langResources.put("ExpressoCertMessages", ResourceBundle.getBundle("ExpressoCertMessages", currentLocale));
+
+	}
+
+	public String[][] getParameterInfo(){
+
+		String[][] info = {
+			{"debug", "boolean", "Habilita mensagens de debug"},
+            {"token", "string", "Lista de tokens suportados. Formato: nome1;caminho1,nome2;caminho2"},
+            {"locale", "string", "Locale do sistema"}
+		};
+
+		return info;
+	}
+
+	public String[][] getPreferencesInfo(){
+
+		String[][] info = {
+			{"preferedToken", "string", "Token preferencial do usuário. Formato: nome;caminho"}
+		};
+
+		return info;
+
+	}
+
+	public String getParameter(String key){
+		return parameters.getProperty(key);
+	}
+
+	public String getPreference(String key){
+		return getPreference(key);
+	}
+
+	//TODO: implementar PreferenceNotRegisteredException
+	public void setPreference(String key, String value){
+
+		boolean exists = false;
+		while (!exists){
+			for (String[] preference: getPreferencesInfo()){
+				if (key.equalsIgnoreCase(preference[1])){
+					exists = true;
+					preferences.setProperty(key, value);
+				}
+			}
+		}
+
+		if (!exists){
+//			 throws PreferenceNotRegisteredException();
+            System.out.println("Preferência não existe!");
+		}
+	}
+
+    Locale buildLocale(String localeCode){
+
+        String[] localeItems = localeCode.split("_");
+        Locale locale;
+        
+        switch (localeItems.length){
+            case 1: locale = new Locale(localeItems[0]);
+                    break;
+            case 2: locale = new Locale(localeItems[0], localeItems[1]);
+                    break;
+            case 3: locale = new Locale(localeItems[0], localeItems[1], localeItems[2]);
+                    break;
+            default: locale = new Locale("pt", "BR");
+                    System.out.println("Locale code error, setting default locale: " + locale.toString());
+        }
+
+        return locale;
+    }
+
+    public void addLanguageResource(String langResource){
+        System.out.println("registrando recusro de linguagem " + langResource);
+        langResources.put(langResource, ResourceBundle.getBundle(langResource, currentLocale));
+    }
+
+    public String getLang(String langResource, String message){
+
+        ResourceBundle resource = langResources.get(langResource);
+
+        String i18nText = new String("????");
+        try {
+            i18nText = resource.getString(message);
+        }
+        catch (MissingResourceException e){
+            e.printStackTrace();
+        }
+
+        return i18nText;
+
+        //return message;
+    }
+
+	// TODO: Not Implemented Yet
+	public boolean savePreferences(){
+		return false;
+	}
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/DigitalCertificate.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/DigitalCertificate.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/DigitalCertificate.java	(revision 1035)
@@ -0,0 +1,727 @@
+package br.gov.serpro.cert;
+
+import br.gov.serpro.setup.Setup;
+import java.awt.Frame;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.security.AuthProvider;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.security.Security;
+import java.security.cert.CertStore;
+import java.security.cert.Certificate;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.crypto.Cipher;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import javax.net.ssl.SSLHandshakeException;
+import javax.security.auth.login.LoginException;
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.cms.AttributeTable;
+import org.bouncycastle.asn1.smime.SMIMECapability;
+import org.bouncycastle.asn1.smime.SMIMECapabilityVector;
+import org.bouncycastle.mail.smime.SMIMEException;
+import org.bouncycastle.mail.smime.SMIMESignedGenerator;
+
+import br.gov.serpro.ui.DialogBuilder;
+import br.gov.serpro.util.Base64Utils;
+import com.sun.mail.util.BASE64DecoderStream;
+import java.security.AlgorithmParameters;
+import javax.mail.BodyPart;
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.RecipientId;
+import org.bouncycastle.cms.RecipientInformation;
+import org.bouncycastle.cms.RecipientInformationStore;
+import org.bouncycastle.mail.smime.SMIMEEnvelopedParser;
+import org.bouncycastle.mail.smime.SMIMEUtil;
+
+/**
+ * Classe que realiza todo o trabalho realizado com o certificado
+ * @author Mário César Kolling - mario.kolling@serpro.gov.br
+ */
+
+//TODO: Criar exceções para serem lançadas, entre elas DigitalCertificateNotLoaded
+//TODO: Adicionar setup
+
+public class DigitalCertificate {
+
+    private TokenCollection tokens;
+	private Certificate cert; // Certificado extraído da KeyStore. Pode ser nulo.
+	private KeyStore keyStore; // KeyStore que guarda o certificado do usuário. Pode ser nulo.
+
+	private Frame parentFrame;
+    private Setup setup;
+
+	// TODO: Transformar pkcs12Input em uma string ou URL com o caminho para a KeyStore pkcs12
+	private FileInputStream pkcs12Input; // stream da KeyStore pkcs12. Pode ser nulo.
+	private String providerName; // Nome do SecurityProvider pkcs11 carregado. Pode ser nulo.
+	private String hostAddress; // Endereço do host, onde a página principal do
+
+	private static final String HOME_SUBDIR; // Subdiretório dentro do diretório home do usuário. Dependente de SO.
+	private static final String EPASS_2000; // Caminho da biblioteca do token ePass2000. Dependente de SO.
+
+	private static final String CRLF = "\r\n"; // Separa campos na resposta do serviço de verificação de certificados
+	private static final String SUBJECT_ALTERNATIVE_NAME = "2.5.29.17"; // Não é mais utilizado.
+	private static final URL[] TRUST_STORES_URLS = new URL[3]; // URLs (file:/) das TrustStores, cacerts (jre),
+															   // trusted.certs e trusted.jssecerts (home do usuário)
+                                                               // Utilizadas para validação do certificado do servidor.
+	private static final String[] TRUST_STORES_PASSWORDS = null; // Senhas para cada uma das TrustStores,
+																 // caso seja necessário.
+	private int keystoreStatus;
+	public static final int KEYSTORE_DETECTED = 0;
+	public static final int KEYSTORE_NOT_DETECTED = 1;
+	public static final int KEYSTORE_ALREADY_LOADED = 2;
+
+	/*
+	 * Bloco estático que define os caminhos padrões da instalação da jre,
+	 * do diretório home do usuário, e da biblioteca de sistema do token ePass2000,
+	 * de acordo com o sistema operacional.
+	 */
+	static {
+
+		Properties systemProperties = System.getProperties();
+        Map<String, String> env = System.getenv();
+
+		/* TODO: Testar a existência de vários drivers de dispositivos. Determinar qual deve ser utilizado
+		 * e guardar em uma property no subdiretório home do usuário.
+		 */
+
+		if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")){
+			HOME_SUBDIR = "/.java/deployment/security";
+			EPASS_2000 = "/usr/lib/libepsng_p11.so";
+		}
+		else {
+			HOME_SUBDIR = "\\dados de aplicativos\\sun\\java\\deployment\\security";
+			EPASS_2000 = System.getenv("SystemRoot")+"\\system32\\ngp11v211.dll";
+            //EPASS_2000 = System.getenv("ProgramFiles")+"\\Gemplus\\GemSafe Libraries\\BIN\\gclib.dll";
+		}
+
+		try {
+			if (systemProperties.getProperty("os.name").equalsIgnoreCase("linux")){
+				TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home")
+					+ "/lib/security/cacerts").toURI().toURL();
+				TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home")
+					+ HOME_SUBDIR + "/trusted.certs").toURI().toURL();
+				TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home")
+					+ HOME_SUBDIR + "/trusted.jssecerts").toURI().toURL();
+			} else {
+
+				TRUST_STORES_URLS[0] = new File(systemProperties.getProperty("java.home") +
+						"\\lib\\security\\cacerts").toURI().toURL();
+				TRUST_STORES_URLS[1] = new File(systemProperties.getProperty("user.home") +
+						HOME_SUBDIR + "\\trusted.certs").toURI().toURL();
+				TRUST_STORES_URLS[2] = new File(systemProperties.getProperty("user.home") +
+						HOME_SUBDIR + "\\trusted.jssecerts").toURI().toURL();
+			}
+
+
+		} catch (MalformedURLException e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 *
+	 */
+	public DigitalCertificate() {
+		this.hostAddress = null;
+		this.parentFrame = null;
+	}
+
+	/**
+	 * Construtor da classe. Recebe a {@link URL} da página em que a Applet está incluída.
+	 * @param pageAddress URL da página em que a Applet está incluída
+	 */
+	private DigitalCertificate(URL pageAddress){
+		this.hostAddress = pageAddress.getHost();
+		this.parentFrame = null;
+	}
+
+	private DigitalCertificate(Frame parent){
+		this.hostAddress = null;
+		this.parentFrame = parent;
+	}
+
+
+    public DigitalCertificate(Frame parent, Setup setup){
+		this(parent);
+        this.setup = setup;
+	}
+
+    public DigitalCertificate(URL pageAddress, Setup setup){
+		this(pageAddress);
+        this.setup = setup;
+	}
+
+	/**
+	 * Destrói a Applet, removendo o security provider inicializado se o atributo providerName
+	 * for diferente de nulo.
+	 */
+	public void destroy(){
+
+		AuthProvider ap = null;
+
+        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+            System.out.println("logout no provider");
+        }
+		if (keyStore != null){
+			ap = (AuthProvider) this.keyStore.getProvider();
+		}
+
+		if (ap != null){
+			try {
+				ap.logout();
+			} catch (LoginException e) {
+                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                    e.printStackTrace();
+                }
+			}
+		}
+
+		if (providerName != null){
+			Security.removeProvider(providerName);
+		}
+
+		this.cert = null;
+		this.keyStore = null;
+		this.hostAddress = null;
+		this.pkcs12Input = null;
+		this.providerName = null;
+
+	}
+
+	/**
+	  * Procura pelo token nos locais padrões (Por enquanto só suporta o token ePass200),
+	  * senão procura por um certificado A1 em System.getProperties().getProperty("user.home") +
+	  * HOME_SUBDIR  + "/trusted.clientcerts" e retorna um inteiro de acordo com resultado desta procura.
+	  *
+	  * @author	Mário César Kolling
+	  * @return	Retorna um destes valores inteiros DigitalCertificate.KEYSTORE_DETECTED,
+	  * 		DigitalCertificate.KEYSTORE_ALREADY_LOADED ou DigitalCertificate.KEYSTORE_NOT_DETECTED
+	  * @see	DigitalCertificate
+	  */
+	public int init(){
+
+		// TODO: Usar dentro de um "loop" para testar outros modelos de tokens.
+        this.tokens = new TokenCollection(setup);
+		int interfaceType = DigitalCertificate.KEYSTORE_DETECTED;
+
+		try
+		{
+			// Tenta abrir o Token padrï¿œo (ePass2000).
+			loadKeyStore();
+
+		}
+		catch (Exception e1){
+
+			Provider[] providers = Security.getProviders();
+            if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                for (Provider provider: providers){
+                    System.out.println(provider.getInfo());
+                }
+
+                // Não conseguiu abrir o token (ePass2000).
+                System.out.println("Erro ao ler o token: " + e1.getMessage());
+            }
+
+			try
+			{
+				// Tenta abrir a keyStore padrão
+				// USER_HOME/deployment/security/trusted.clientcerts
+
+				Properties props = System.getProperties();
+				pkcs12Input = new FileInputStream(props.getProperty("user.home") +  HOME_SUBDIR  + "/trusted.clientcerts");
+
+				// Se chegar aqui significa que arquivo de KeyStore existe.
+				keyStore = KeyStore.getInstance("JKS");
+
+			}
+			catch (Exception ioe){
+				// Não conseguiu abrir a KeyStore pkcs12
+                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                    System.out.println(ioe.getMessage());
+                }
+			}
+		}
+
+
+		if (keyStore == null){
+			// Não conseguiu inicializar a KeyStore. Mostra tela de login com usuário e senha.
+			this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED;
+		//} else if (keyStore.getType().equalsIgnoreCase("pkcs11")){
+		} else {
+			// Usa certificado digital.
+			try {
+				// Testa se uma keystore já foi carregada previamente
+				if (keyStore.getType().equalsIgnoreCase("pkcs11")){
+					keyStore.load(null, null);
+				} else {
+					keyStore.load(pkcs12Input, null);
+				}
+
+				// Se chegou aqui KeyStore está liberada, mostrar tela de login sem pedir o pin.
+				this.keystoreStatus = DigitalCertificate.KEYSTORE_ALREADY_LOADED;
+
+			} catch (ProviderException e) {
+				// Algum erro ocorreu, mostra  tela de login com usuário e senha.
+				this.keystoreStatus = DigitalCertificate.KEYSTORE_NOT_DETECTED;
+				if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                    e.printStackTrace();
+                }
+			} catch (IOException e){
+				// KeyStore não está liberada, mostra tela de login com o pin.
+                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                    System.out.println(e.getMessage());
+                }
+				this.keystoreStatus = DigitalCertificate.KEYSTORE_DETECTED;
+			} catch (GeneralSecurityException e){
+                if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                    e.printStackTrace();
+                }
+			}
+		}
+
+		return keystoreStatus;
+
+	}
+
+	/**
+	 * Usado para assinar digitalmente um e-mail.
+	 * @param mime
+	 * @return String vazia
+	 */
+	public String signMail (Map<String, String> data) throws IOException, GeneralSecurityException, SMIMEException, MessagingException{
+
+		Key privateKey = null;
+		if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED){
+			String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup);
+			if (pin != null){
+				openKeyStore(pin.toCharArray());
+				privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray());
+			}
+			else {
+				return null;
+			}
+		}
+        /*
+		else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){
+				if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){
+					openKeyStore(null);
+					privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null);
+				}
+				else {
+					return null;
+				}
+		}
+         */
+		else {
+
+            //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!");
+            DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup);
+			return null;
+		}
+
+		Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+
+		Certificate certificate = getCert();
+
+		KeyPair keypair = new KeyPair(certificate.getPublicKey(), (PrivateKey) privateKey);
+
+		// Cria a cadeia de certificados que a gente vai enviar
+        List certList = new ArrayList();
+
+        certList.add(certificate);
+
+        //
+        // create the base for our message
+		//
+        String fullMsg = data.get("body");
+
+        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+            System.out.println("Corpo do e-mail:\n"+fullMsg+"\n");
+        }
+        
+        //
+        // Get a Session object and create the mail message
+        //
+        Properties props = System.getProperties();
+        Session session = Session.getDefaultInstance(props, null);
+
+        InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1"));
+		MimeMessage unsignedMessage = new MimeMessage(session, is);
+
+        //
+        // create a CertStore containing the certificates we want carried
+        // in the signature
+        //
+        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+            System.out.println("Provider: " + providerName);
+        }
+        CertStore certsAndcrls = CertStore.getInstance(
+                                "Collection",
+                                new CollectionCertStoreParameters(certList), "BC");
+
+        //
+        // create some smime capabilities in case someone wants to respond
+        //
+        ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
+
+        SMIMECapabilityVector       caps = new SMIMECapabilityVector();
+
+        caps.addCapability(SMIMECapability.dES_EDE3_CBC);
+        caps.addCapability(SMIMECapability.rC2_CBC, 128);
+        caps.addCapability(SMIMECapability.dES_CBC);
+
+		SMIMESignedGenerator gen = new SMIMESignedGenerator(unsignedMessage.getEncoding());
+
+		gen.addSigner(keypair.getPrivate(), (X509Certificate) certificate, SMIMESignedGenerator.DIGEST_SHA1, new AttributeTable(signedAttrs), null);
+
+		gen.addCertificatesAndCRLs(certsAndcrls);
+
+        //TODO: Extrair todos os headers de unsignedMessage
+
+		// Gera a assinatura
+		Object content = unsignedMessage.getContent();
+
+		//TODO: igualar unsignedMessage a null
+		//TODO: Pegar os headers do objeto que guardarï¿œ esses headers quando necessï¿œrio.
+
+		MimeMultipart mimeMultipartContent = null;
+		MimeBodyPart mimeBodyPartContent = new MimeBodyPart();
+
+		if (content.getClass().getName().contains("MimeMultipart")){
+			mimeMultipartContent = (MimeMultipart) content;
+		}
+		else {
+			is = new ByteArrayInputStream(content.toString().getBytes("iso-8859-1"));
+			mimeBodyPartContent = new MimeBodyPart(is);
+			mimeBodyPartContent.setHeader("Content-Type", unsignedMessage.getHeader("Content-Type", null)); //TODO: testar se valor existe
+			is = null;
+		}
+		content = null;
+
+		MimeBodyPart msg = null;
+		if (mimeMultipartContent == null){
+			msg = mimeBodyPartContent;
+			mimeBodyPartContent = null;
+		}
+		else {
+			msg = new MimeBodyPart();
+			msg.setContent(mimeMultipartContent);
+			mimeMultipartContent = null;
+		}
+
+        //
+        // extract the multipart object from the SMIMESigned object.
+        //
+        MimeMultipart mm = gen.generate(msg, providerName);
+        gen = null;
+        msg = null;
+
+        MimeMessage body = new MimeMessage(session);
+        body.setFrom(unsignedMessage.getFrom()[0]);
+        body.setRecipients(Message.RecipientType.TO, unsignedMessage.getRecipients(Message.RecipientType.TO));
+        body.setRecipients(Message.RecipientType.CC, unsignedMessage.getRecipients(Message.RecipientType.CC));
+        body.setRecipients(Message.RecipientType.BCC, unsignedMessage.getRecipients(Message.RecipientType.BCC));
+        body.setSubject(unsignedMessage.getSubject(), "iso-8859-1");
+
+        // Atrafuia o resto dos headers        
+        body.setHeader("Return-Path", unsignedMessage.getHeader("Return-Path", null));
+        body.setHeader("Message-ID", unsignedMessage.getHeader("Message-ID", null));
+        body.setHeader("X-Priority", unsignedMessage.getHeader("X-Priority", null));
+        body.setHeader("X-Mailer", unsignedMessage.getHeader("X-Mailer", null));
+        body.setHeader("Disposition-Notification-To", unsignedMessage.getHeader("Disposition-Notification-To", null));
+        body.setHeader("Date", unsignedMessage.getHeader("Date", null));
+        body.setContent(mm, mm.getContentType());
+        mm = null;
+
+        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+            System.out.println("\nHeaders do e-mail original:\n");
+        }
+
+        body.saveChanges();
+
+        ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+        
+        oStream = new ByteArrayOutputStream();
+        body.writeTo(oStream);
+      
+        body = null;
+        return oStream.toString("iso-8859-1");
+
+	}
+    
+	/**
+	 * Método utilizado para criptografar um e-mail
+	 * @param source
+	 * @return
+	 */
+    public String cipherMail(Map<String, String> data) throws IOException, GeneralSecurityException, MessagingException, CMSException, SMIMEException{
+        
+        //Pega certificado do usuário.
+        
+        Key privateKey = null;
+		if (this.keystoreStatus == DigitalCertificate.KEYSTORE_DETECTED){
+			String pin = DialogBuilder.showPinDialog(this.parentFrame, this.setup);
+			if (pin != null){
+				openKeyStore(pin.toCharArray());
+				privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), pin.toCharArray());
+			}
+			else {
+				return null;
+			}
+		}
+        /*
+		else if (this.keystoreStatus == DigitalCertificate.KEYSTORE_ALREADY_LOADED){
+				if (DialogBuilder.showPinNotNeededDialog(this.parentFrame)){
+					openKeyStore(null);
+					privateKey = this.keyStore.getKey(keyStore.aliases().nextElement(), null);
+				}
+				else {
+					return null;
+				}
+		}
+         */
+		else {
+
+            //DialogBuilder.showMessageDialog(this.parentFrame, "Nenhum token/smartcard foi detectado.\nOperação não pôde ser realizada!");
+            DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate001"), this.setup);
+			return null;
+		}
+
+		Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+
+		X509Certificate cert = (X509Certificate)getCert();
+        
+        RecipientId recId = new RecipientId();
+        recId.setSerialNumber(cert.getSerialNumber());
+        recId.setIssuer(cert.getIssuerX500Principal());
+        
+        Properties props = System.getProperties();
+        Session session = Session.getDefaultInstance(props, null);
+        
+        String fullMsg = data.get("body");
+        InputStream is = new ByteArrayInputStream(fullMsg.getBytes("iso-8859-1"));
+        MimeMessage encriptedMsg = new MimeMessage(session, is);
+
+        Provider prov = Security.getProvider(providerName);
+        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+            System.out.println("Serviços do provider "+providerName+ ":\n"+ prov.getInfo());
+            for (Provider.Service service: prov.getServices())
+                System.out.println(service.toString() + ": " + service.getAlgorithm());
+        }
+
+        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+            System.out.println("Email criptografado:\n" + fullMsg);
+        }
+
+        SMIMEEnvelopedParser m = new SMIMEEnvelopedParser(encriptedMsg);
+        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+            System.out.println("Algoritmo de encriptação: " + m.getEncryptionAlgOID());
+        }
+
+        AlgorithmParameters algParams = m.getEncryptionAlgorithmParameters("BC");
+        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+            System.out.println("Parâmetros do algoritmo: " + algParams.toString());
+        }
+
+        RecipientInformationStore recipients = m.getRecipientInfos();
+        RecipientInformation recipient = recipients.get(recId);
+
+        if (recipient != null){
+            MimeBodyPart decriptedBodyPart = SMIMEUtil.toMimeBodyPart(recipient.getContentStream(privateKey, this.providerName));
+            encriptedMsg.setContent(decriptedBodyPart.getContent(), decriptedBodyPart.getContentType());
+            encriptedMsg.saveChanges();
+
+            ByteArrayOutputStream oStream = new ByteArrayOutputStream();
+            encriptedMsg.writeTo(oStream);
+            encriptedMsg = null;
+
+            return oStream.toString("iso-8859-1");
+        }
+        else {
+            //DialogBuilder.showMessageDialog(this.parentFrame, "Não é possível ler este e-mail com o Certificado Digital apresentado!\n" +
+            //        "Motivo: Este e-mail não foi cifrado com a chave pública deste Certificado Digital.");
+            DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMessages", "DigitalCertificate002"), this.setup);
+            return null;
+        }
+    }
+
+	/**
+	 * Pega as credenciais de login do dono do certificado do serviço de verificação de certificados
+	 * @param	pin			pin para acessar o token
+	 * @return	resposta	Array de Strings em que:
+	 * 						Indice 0: código de retorno;
+	 * 						Indice 1: username se código de retorno for 0, senão mensagem de erro;
+	 * 						Indice 2: senha decriptada se código de retorno for 0, senão não existe;
+	 * @throws SSLHandshakeException
+	 * @throws HttpException
+	 * @throws IOException
+	 * @throws GeneralSecurityException
+	 */
+	public String[] getCredentials(String pin) throws SSLHandshakeException, HttpException, IOException, GeneralSecurityException{
+
+		String[] resposta = null;
+
+        if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+            System.out.println("Proxy Configurado no browser: " + System.getProperty("http.proxyHost")
+                    + ":" + System.getProperty("http.proxyPort"));
+        }
+
+		// Registra novo protocolo https, utilizando nova implementação de AuthSSLProtocolSocketFactory
+		Protocol.registerProtocol("https", new Protocol("https",
+				(ProtocolSocketFactory) new AuthSSLProtocolSocketFactory(TRUST_STORES_URLS, TRUST_STORES_PASSWORDS, this.setup),
+				443));
+
+		HttpClient httpclient = new HttpClient();
+		// Define um método post para o link do serviço de verificação de certificados
+        if (System.getProperty("http.proxyHost") != null && System.getProperty("http.proxyPort") != null){
+            httpclient.getHostConfiguration().setProxy(System.getProperty("http.proxyHost"),
+                    Integer.parseInt(System.getProperty("http.proxyPort")));
+        }
+		PostMethod httppost = new PostMethod("https://"+ hostAddress + "/seguranca/vercert.php");
+
+		try {
+			// Adiciona parâmetro certificado no método post, executa o método, pega a resposta do servidor
+			// como uma string com CRLF de separador entre os campos e gera um array de Strings
+			httppost.addParameter("certificado", Base64Utils.der2pem(cert.getEncoded()));
+			httpclient.executeMethod(httppost);
+			resposta = httppost.getResponseBodyAsString().split(CRLF);
+
+			if (resposta.length > 2){
+				if (Integer.parseInt(resposta[0].trim()) == 0){
+					// Se código da resposta for zero, decripta a senha criptografada do usuário
+					resposta[2] = decriptPassword(resposta[2].trim(), pin);
+				}
+			}
+
+		} catch (IOException e){
+			// Se for instância de SSLHandshakeException faz um cast para este tipo e lança a exceção novamente
+			// Isto é usado para diferenciar o tipo de falha, para que a mensagem para o usuário seja mostrada de
+			// acordo.
+			if (e instanceof SSLHandshakeException){
+				throw (SSLHandshakeException) e;
+			}
+			// senão lança novamente a exceção do tipo IOException
+			throw e;
+		} finally {
+			// fecha a conexão
+			httppost.releaseConnection();
+		}
+
+		return resposta;
+	}
+
+	/**
+	 * Decripta a senha criptografada
+	 * @param encodedPassword senha criptografada e codificada em base64 para ser decriptada
+	 * @param pin pin para acessar a KeyStore
+	 * @return decodedPassword
+	 * @throws GeneralSecurityException se algum problema ocorrer na decriptação da senha.
+	 */
+	public String decriptPassword(String encodedPassword, String pin) throws GeneralSecurityException{
+
+		String decodedPassword = new String();
+
+		// Pega a chave privada do primeiro certificado armazenado na KeyStore
+		Enumeration<String> en = this.keyStore.aliases();
+		String certAlias = en.nextElement();
+		Key privateKey = this.keyStore.getKey(certAlias, pin.toCharArray());
+
+		// Inicializa os cipher com os parâmetros corretos para realizar a decriptação
+		Cipher dcipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+		dcipher.init(Cipher.DECRYPT_MODE, privateKey);
+
+		// Decodifica a senha em base64 e a decripta
+		decodedPassword = new String(dcipher.doFinal(Base64Utils.base64Decode(encodedPassword)));
+
+		return decodedPassword.trim();
+
+	}
+
+	/**
+	 * Carrega um novo SecurityProvider
+	 * @param pkcs11Config Linha de configuração do SmartCard ou Token
+	 * @throws KeyStoreException Quando não conseguir iniciar a KeyStore, ou a lib do Token
+	 * 							 ou Smartcard não foi encontrada, ou o usuário não inseriu o Token.
+	 */
+	private void loadKeyStore() throws KeyStoreException{
+
+		//Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(pkcs11Config.getBytes()));
+		//Security.addProvider(pkcs11Provider);
+		this.keyStore = KeyStore.getInstance("PKCS11");
+		this.providerName = keyStore.getProvider().getName();
+
+	}
+
+	/**
+	 *  Abre a keystore passando o pin
+	 *  @param pin pin para acessar o Token
+	 */
+	public void openKeyStore(char[] pin) throws IOException{
+
+		try {
+
+			if (this.keyStore.getType().equals("PKCS11")){
+				this.keyStore.load(null, pin);
+			}
+			else {
+				this.keyStore.load(this.pkcs12Input, pin);
+			}
+
+			this.cert = this.keyStore.getCertificate(this.keyStore.aliases().nextElement());
+
+		} catch (GeneralSecurityException e) {
+            if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+                e.printStackTrace();
+            }
+		}
+
+	}
+
+	/**
+	 * @return the cert
+	 */
+	Certificate getCert() {
+		return this.cert;
+	}
+
+	/**
+	 * @param cert the cert to set
+	 */
+	void setCert(Certificate cert) {
+		this.cert = cert;
+	}
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/Token.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/Token.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/Token.java	(revision 1035)
@@ -0,0 +1,104 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package br.gov.serpro.cert;
+
+import br.gov.serpro.setup.Setup;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.security.Provider;
+import java.security.ProviderException;
+import java.security.Security;
+
+//TODO: Deal with wildcards for environments variables.
+
+/**
+ *
+ * @author esa
+ */
+class Token{
+
+    private final Setup setup;
+    private String name;
+    private String libraryPath;
+    private Provider tokenProvider;
+    private boolean registered = false;
+
+    private Token(final Setup setup) {
+        this.setup = setup;
+    }
+
+    Token(String name, String libraryPath, final Setup setup){
+        this(setup);
+        this.setName(name);
+        this.setLibraryPath(libraryPath);
+    }
+
+    public boolean isRegistered() {
+        return this.registered;
+    }
+
+    public void setLibraryPath(String libraryPath) {
+        this.libraryPath = libraryPath;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    protected void registerToken(){
+        String tokenConfiguration = new String("name = " + name + "\n" +
+            "library = " + libraryPath + "\ndisabledMechanisms = {\n" +
+            "CKM_SHA1_RSA_PKCS\n}");
+
+        try{
+            this.registered = false;
+            if (libraryExists()){
+                Provider pkcs11Provider = new sun.security.pkcs11.SunPKCS11(new ByteArrayInputStream(tokenConfiguration.getBytes()));
+                this.tokenProvider = pkcs11Provider;
+                Security.addProvider(pkcs11Provider);
+                this.registered = true;
+            }
+        }
+        catch (ProviderException e){
+            if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                e.printStackTrace();
+                System.out.println("Não foi possível inicializar o seguinte token: " + tokenConfiguration);
+            }
+        }
+    }
+
+    protected void unregisterToken(){
+        Security.removeProvider(this.tokenProvider.getName());
+    }
+
+/*    public KeyStore getKeystore() throws KeyStoreException {
+
+        return (this.keyStore = KeyStore.getInstance("PKCS11"));
+
+    }
+*/
+    public boolean libraryExists(){
+
+        File libraryFile = new File(libraryPath);
+        if (libraryFile.exists()){
+            if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                System.out.println("Arquivo " + libraryPath + " existe.");
+            }
+            return true;
+        }
+        
+        if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+            System.out.println("Biblioteca do Token/SmartCard " + name + " não foi encontrada: " + libraryPath);
+        }
+        
+        return false;
+    }
+    
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLInitializationError.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLInitializationError.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLInitializationError.java	(revision 1035)
@@ -0,0 +1,70 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+package br.gov.serpro.cert;
+
+/**
+ * <p>
+ * Signals fatal error in initialization of {@link AuthSSLProtocolSocketFactory}.
+ * </p>
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ *
+ * <p>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ */
+
+
+public class AuthSSLInitializationError extends Error {
+
+    /**
+	 *
+	 */
+	private static final long serialVersionUID = 2239180746163317934L;
+
+	/**
+     * Creates a new AuthSSLInitializationError.
+     */
+    public AuthSSLInitializationError() {
+        super();
+    }
+
+    /**
+     * Creates a new AuthSSLInitializationError with the specified message.
+     *
+     * @param message error message
+     */
+    public AuthSSLInitializationError(String message) {
+        super(message);
+    }
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLProtocolSocketFactory.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLProtocolSocketFactory.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLProtocolSocketFactory.java	(revision 1035)
@@ -0,0 +1,460 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package br.gov.serpro.cert;
+
+import br.gov.serpro.setup.Setup;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.URL;
+import java.net.UnknownHostException;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
+import org.apache.commons.httpclient.ConnectTimeoutException;
+import org.apache.commons.httpclient.params.HttpConnectionParams;
+import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * <p>
+ * AuthSSLProtocolSocketFactory can be used to validate the identity of the HTTPS
+ * server against a list of trusted certificates and to authenticate to the HTTPS
+ * server using a private key.
+ * </p>
+ *
+ * <p>
+ * AuthSSLProtocolSocketFactory will enable server authentication when supplied with
+ * a {@link KeyStore truststore} file containg one or several trusted certificates.
+ * The client secure socket will reject the connection during the SSL session handshake
+ * if the target HTTPS server attempts to authenticate itself with a non-trusted
+ * certificate.
+ * </p>
+ *
+ * <p>
+ * Use JDK keytool utility to import a trusted certificate and generate a truststore file:
+ *    <pre>
+ *     keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ *    </pre>
+ * </p>
+ *
+ * <p>
+ * AuthSSLProtocolSocketFactory will enable client authentication when supplied with
+ * a {@link KeyStore keystore} file containg a private key/public certificate pair.
+ * The client secure socket will use the private key to authenticate itself to the target
+ * HTTPS server during the SSL session handshake if requested to do so by the server.
+ * The target HTTPS server will in its turn verify the certificate presented by the client
+ * in order to establish client's authenticity
+ * </p>
+ *
+ * <p>
+ * Use the following sequence of actions to generate a keystore file
+ * </p>
+ *   <ul>
+ *     <li>
+ *      <p>
+ *      Use JDK keytool utility to generate a new key
+ *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ *      For simplicity use the same password for the key as that of the keystore
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *      Issue a certificate signing request (CSR)
+ *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
+ *     </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *      Send the certificate request to the trusted Certificate Authority for signature.
+ *      One may choose to act as her own CA and sign the certificate request using a PKI
+ *      tool, such as OpenSSL.
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Import the trusted CA root certificate
+ *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Import the PKCS#7 file containg the complete certificate chain
+ *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
+ *      </p>
+ *     </li>
+ *     <li>
+ *      <p>
+ *       Verify the content the resultant keystore file
+ *       <pre>keytool -list -v -keystore my.keystore</pre>
+ *      </p>
+ *     </li>
+ *   </ul>
+ * <p>
+ * Example of using custom protocol socket factory for a specific host:
+ *     <pre>
+ *     Protocol authhttps = new Protocol("https",
+ *          new AuthSSLProtocolSocketFactory(
+ *              new URL("file:my.keystore"), "mypassword",
+ *              new URL("file:my.truststore"), "mypassword"), 443);
+ *
+ *     HttpClient client = new HttpClient();
+ *     client.getHostConfiguration().setHost("localhost", 443, authhttps);
+ *     // use relative url only
+ *     GetMethod httpget = new GetMethod("/");
+ *     client.executeMethod(httpget);
+ *     </pre>
+ * </p>
+ * <p>
+ * Example of using custom protocol socket factory per default instead of the standard one:
+ *     <pre>
+ *     Protocol authhttps = new Protocol("https",
+ *          new AuthSSLProtocolSocketFactory(
+ *              new URL("file:my.keystore"), "mypassword",
+ *              new URL("file:my.truststore"), "mypassword"), 443);
+ *     Protocol.registerProtocol("https", authhttps);
+ *
+ *     HttpClient client = new HttpClient();
+ *     GetMethod httpget = new GetMethod("https://localhost/");
+ *     client.executeMethod(httpget);
+ *     </pre>
+ * </p>
+ * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
+ *
+ * <p>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ */
+
+public class AuthSSLProtocolSocketFactory implements
+		SecureProtocolSocketFactory {
+
+    /** Log object for this class. */
+    private static final Log LOG = LogFactory.getLog(AuthSSLProtocolSocketFactory.class);
+
+    private URL[] truststoreUrls = null;
+    private String[] truststorePasswords = null;
+    private SSLContext sslcontext = null;
+    private static Setup setup = null;
+
+    /**
+     * Constructor for AuthSSLProtocolSocketFactory. Either a keystore or truststore file
+     * must be given. Otherwise SSL context initialization error will result.
+     *
+     * @param keystoreUrl URL of the keystore file. May be <tt>null</tt> if HTTPS client
+     *        authentication is not to be used.
+     * @param keystorePassword Password to unlock the keystore. IMPORTANT: this implementation
+     *        assumes that the same password is used to protect the key and the keystore itself.
+     * @param truststoreUrls URL of the truststore file. May be <tt>null</tt> if HTTPS server
+     *        authentication is not to be used.
+     * @param truststorePasswords Password to unlock the truststore.
+     */
+    public AuthSSLProtocolSocketFactory(
+        final URL[] truststoreUrls, final String[] truststorePasswords, final Setup setup)
+    {
+        super();
+        this.truststoreUrls = truststoreUrls;
+        this.truststorePasswords = truststorePasswords;
+        AuthSSLProtocolSocketFactory.setup = setup;
+    }
+
+    // TODO: Usar um mapa de keystores e senhas ou algo como KeystoreCredentialsPair
+    private static KeyStore createKeyStore(final URL[] urls, final String[] passwords)
+        throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException
+    {
+    	KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
+    	keystore.load(null);
+
+        if (urls == null) {
+            throw new IllegalArgumentException("Keystore urls may not be null");
+        }
+
+        if (passwords != null && passwords.length != urls.length){
+        	throw new IllegalArgumentException("Urls and passwords arrays must have the same size");
+        }
+
+        LOG.debug("Initializing key store");
+
+        for (int i = 0; i < urls.length; i++){
+
+        	LOG.debug("Adding " + urls[i].toString() + " to internal keystore");
+	        KeyStore ks  = KeyStore.getInstance("jks");
+	        InputStream is = null;
+	        try {
+	        	is = urls[i].openStream();
+
+	        	if (passwords == null){
+	        		ks.load(is, null);
+	        	}
+	        	else {
+	        		ks.load(is, passwords[i] != null ? passwords[i].toCharArray(): null);
+	        	}
+
+	            for (Enumeration<String> e = ks.aliases(); e.hasMoreElements();){
+	            	X509Certificate cert = (X509Certificate) ks.getCertificate(e.nextElement());
+	            	keystore.setCertificateEntry(cert.getSubjectX500Principal().getName(), cert);
+	            }
+	        } catch (IOException e){
+                if (AuthSSLProtocolSocketFactory.setup.getParameter("debug").equalsIgnoreCase("true")){
+                    System.out.println("Erro ao abrir URL: " + urls[i].toExternalForm());
+                }
+        	} finally {
+	        	if (is != null) is.close();
+	        }
+        }
+        return keystore;
+    }
+
+    private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password)
+        throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException
+    {
+        if (keystore == null) {
+            throw new IllegalArgumentException("Keystore may not be null");
+        }
+        LOG.debug("Initializing key manager");
+        KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(
+            KeyManagerFactory.getDefaultAlgorithm());
+        kmfactory.init(keystore, password != null ? password.toCharArray(): null);
+        return kmfactory.getKeyManagers();
+    }
+
+    private static TrustManager[] createTrustManagers(final KeyStore keystore)
+        throws KeyStoreException, NoSuchAlgorithmException
+    {
+        if (keystore == null) {
+            throw new IllegalArgumentException("Keystore may not be null");
+        }
+        LOG.debug("Initializing trust manager");
+        TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(
+            TrustManagerFactory.getDefaultAlgorithm());
+        tmfactory.init(keystore);
+        TrustManager[] trustmanagers = tmfactory.getTrustManagers();
+        for (int i = 0; i < trustmanagers.length; i++) {
+            if (trustmanagers[i] instanceof X509TrustManager) {
+                trustmanagers[i] = new AuthSSLX509TrustManager(
+                    (X509TrustManager)trustmanagers[i]);
+            }
+        }
+        return trustmanagers;
+    }
+
+    private SSLContext createSSLContext() {
+        try {
+           // KeyManager[] keymanagers = null;
+            TrustManager[] trustmanagers = null;
+            /*
+            if (this.keystoreUrl != null) {
+                KeyStore keystore = createKeyStore(this.keystoreUrl, this.keystorePassword);
+                if (LOG.isDebugEnabled()) {
+                    Enumeration aliases = keystore.aliases();
+                    while (aliases.hasMoreElements()) {
+                        String alias = (String)aliases.nextElement();
+                        Certificate[] certs = keystore.getCertificateChain(alias);
+                        if (certs != null) {
+                            LOG.debug("Certificate chain '" + alias + "':");
+                            for (int c = 0; c < certs.length; c++) {
+                                if (certs[c] instanceof X509Certificate) {
+                                    X509Certificate cert = (X509Certificate)certs[c];
+                                    LOG.debug(" Certificate " + (c + 1) + ":");
+                                    LOG.debug("  Subject DN: " + cert.getSubjectDN());
+                                    LOG.debug("  Signature Algorithm: " + cert.getSigAlgName());
+                                    LOG.debug("  Valid from: " + cert.getNotBefore() );
+                                    LOG.debug("  Valid until: " + cert.getNotAfter());
+                                    LOG.debug("  Issuer: " + cert.getIssuerDN());
+                                }
+                            }
+                        }
+                    }
+                }
+                keymanagers = createKeyManagers(keystore, this.keystorePassword);
+            }
+            */
+            if (this.truststoreUrls != null) {
+                KeyStore keystore = createKeyStore(this.truststoreUrls, this.truststorePasswords);
+                if (LOG.isDebugEnabled()) {
+                    Enumeration aliases = keystore.aliases();
+                    while (aliases.hasMoreElements()) {
+                        String alias = (String)aliases.nextElement();
+                        LOG.debug("Trusted certificate '" + alias + "':");
+                        Certificate trustedcert = keystore.getCertificate(alias);
+                        if (trustedcert != null && trustedcert instanceof X509Certificate) {
+                            X509Certificate cert = (X509Certificate)trustedcert;
+                            LOG.debug("  Subject DN: " + cert.getSubjectDN());
+                            LOG.debug("  Signature Algorithm: " + cert.getSigAlgName());
+                            LOG.debug("  Valid from: " + cert.getNotBefore() );
+                            LOG.debug("  Valid until: " + cert.getNotAfter());
+                            LOG.debug("  Issuer: " + cert.getIssuerDN());
+                        }
+                    }
+                }
+                trustmanagers = createTrustManagers(keystore);
+            }
+            SSLContext sslcontext = SSLContext.getInstance("SSL");
+            sslcontext.init(null, trustmanagers, null);
+            return sslcontext;
+        } catch (NoSuchAlgorithmException e) {
+            LOG.error(e.getMessage(), e);
+            throw new AuthSSLInitializationError("Unsupported algorithm exception: " + e.getMessage());
+        } catch (KeyStoreException e) {
+            LOG.error(e.getMessage(), e);
+            throw new AuthSSLInitializationError("Keystore exception: " + e.getMessage());
+        } catch (GeneralSecurityException e) {
+            LOG.error(e.getMessage(), e);
+            throw new AuthSSLInitializationError("Key management exception: " + e.getMessage());
+        } catch (IOException e) {
+            LOG.error(e.getMessage(), e);
+            throw new AuthSSLInitializationError("I/O error reading keystore/truststore file: " + e.getMessage());
+        }
+    }
+
+    private SSLContext getSSLContext() {
+        if (this.sslcontext == null) {
+            this.sslcontext = createSSLContext();
+        }
+        return this.sslcontext;
+    }
+
+    /**
+     * Attempts to get a new socket connection to the given host within the given time limit.
+     * <p>
+     * To circumvent the limitations of older JREs that do not support connect timeout a
+     * controller thread is executed. The controller thread attempts to create a new socket
+     * within the given limit of time. If socket constructor does not return until the
+     * timeout expires, the controller terminates and throws an {@link ConnectTimeoutException}
+     * </p>
+     *
+     * @param host the host name/IP
+     * @param port the port on the host
+     * @param clientHost the local host name/IP to bind the socket to
+     * @param clientPort the port on the local machine
+     * @param params {@link HttpConnectionParams Http connection parameters}
+     *
+     * @return Socket a new socket
+     *
+     * @throws IOException if an I/O error occurs while creating the socket
+     * @throws UnknownHostException if the IP address of the host cannot be
+     * determined
+     */
+    public Socket createSocket(
+        final String host,
+        final int port,
+        final InetAddress localAddress,
+        final int localPort,
+        final HttpConnectionParams params
+    ) throws IOException, UnknownHostException, ConnectTimeoutException {
+        if (params == null) {
+            throw new IllegalArgumentException("Parameters may not be null");
+        }
+        int timeout = params.getConnectionTimeout();
+        SocketFactory socketfactory = getSSLContext().getSocketFactory();
+        if (timeout == 0) {
+            return socketfactory.createSocket(host, port, localAddress, localPort);
+        } else {
+            Socket socket = socketfactory.createSocket();
+            SocketAddress localaddr = new InetSocketAddress(localAddress, localPort);
+            SocketAddress remoteaddr = new InetSocketAddress(host, port);
+            socket.bind(localaddr);
+            socket.connect(remoteaddr, timeout);
+            return socket;
+        }
+    }
+
+    /**
+     * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int,java.net.InetAddress,int)
+     */
+    public Socket createSocket(
+        String host,
+        int port,
+        InetAddress clientHost,
+        int clientPort)
+        throws IOException, UnknownHostException
+   {
+       return getSSLContext().getSocketFactory().createSocket(
+            host,
+            port,
+            clientHost,
+            clientPort
+        );
+    }
+
+    /**
+     * @see SecureProtocolSocketFactory#createSocket(java.lang.String,int)
+     */
+    public Socket createSocket(String host, int port)
+        throws IOException, UnknownHostException
+    {
+        return getSSLContext().getSocketFactory().createSocket(
+            host,
+            port
+        );
+    }
+
+    /**
+     * @see SecureProtocolSocketFactory#createSocket(java.net.Socket,java.lang.String,int,boolean)
+     */
+    public Socket createSocket(
+        Socket socket,
+        String host,
+        int port,
+        boolean autoClose)
+        throws IOException, UnknownHostException
+    {
+        return getSSLContext().getSocketFactory().createSocket(
+            socket,
+            host,
+            port,
+            autoClose
+        );
+    }
+
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLX509TrustManager.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLX509TrustManager.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/AuthSSLX509TrustManager.java	(revision 1035)
@@ -0,0 +1,142 @@
+/*
+ * $HeadURL$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package br.gov.serpro.cert;
+
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.X509TrustManager;
+import javax.swing.JOptionPane;
+
+import java.security.cert.CertificateException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * <p>
+ * AuthSSLX509TrustManager can be used to extend the default {@link X509TrustManager}
+ * with additional trust decisions.
+ * </p>
+ *
+ * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
+ *
+ * <p>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ */
+
+public class AuthSSLX509TrustManager implements X509TrustManager {
+
+    private X509TrustManager defaultTrustManager = null;
+
+    /** Log object for this class. */
+    private static final Log LOG = LogFactory.getLog(AuthSSLX509TrustManager.class);
+
+    /**
+     * Constructor for AuthSSLX509TrustManager.
+     */
+    public AuthSSLX509TrustManager(final X509TrustManager defaultTrustManager) {
+        super();
+        if (defaultTrustManager == null) {
+            throw new IllegalArgumentException("Trust manager may not be null");
+        }
+        this.defaultTrustManager = defaultTrustManager;
+    }
+
+    /**
+     * @see javax.net.ssl.X509TrustManager#checkClientTrusted(X509Certificate[],String authType)
+     */
+    public void checkClientTrusted(X509Certificate[] certificates,String authType) throws CertificateException {
+        if (LOG.isInfoEnabled() && certificates != null) {
+            for (int c = 0; c < certificates.length; c++) {
+                X509Certificate cert = certificates[c];
+                LOG.info(" Client certificate " + (c + 1) + ":");
+                LOG.info("  Subject DN: " + cert.getSubjectDN());
+                LOG.info("  Signature Algorithm: " + cert.getSigAlgName());
+                LOG.info("  Valid from: " + cert.getNotBefore() );
+                LOG.info("  Valid until: " + cert.getNotAfter());
+                LOG.info("  Issuer: " + cert.getIssuerDN());
+            }
+        }
+        defaultTrustManager.checkClientTrusted(certificates,authType);
+    }
+
+    /**
+     * @see javax.net.ssl.X509TrustManager#checkServerTrusted(X509Certificate[],String authType)
+     */
+    public void checkServerTrusted(X509Certificate[] certificates,String authType) throws CertificateException {
+        if (LOG.isInfoEnabled() && certificates != null) {
+            for (int c = 0; c < certificates.length; c++) {
+                X509Certificate cert = certificates[c];
+                LOG.info(" Server certificate " + (c + 1) + ":");
+                LOG.info("  Subject DN: " + cert.getSubjectDN());
+                LOG.info("  Signature Algorithm: " + cert.getSigAlgName());
+                LOG.info("  Valid from: " + cert.getNotBefore() );
+                LOG.info("  Valid until: " + cert.getNotAfter());
+                LOG.info("  Issuer: " + cert.getIssuerDN());
+            }
+        }
+    	// TODO: Implementar uma caixa de diálogo que pergunta para o usuário se ele quer aceitar o certificado do site
+        // Implementado com try/catch usando JOptionPanel
+
+        try {
+        	defaultTrustManager.checkServerTrusted(certificates,authType);
+        } catch (CertificateException e){
+        	//Object[] options = {"Aceitar Certificado", "Aceitar Permanentemente", "Cancelar"};
+            Object[] options = {"Aceitar Certificado", "Cancelar"};
+        	switch (JOptionPane.showOptionDialog(null, "Falha na validação do seguinte certificado:\n" +
+        			certificates[0].getSubjectX500Principal().getName(),
+        			"\nO que você quer fazer?",
+        			JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, null,
+        			options, options[0]))
+        	{
+        		case 2:
+        			// Rejeita certificado!
+        			throw e;
+        		case 1:
+        			// Aceita certificado permanentemente
+        			// TODO: Adicionar código para inserir o certificado como um certificado confiável
+        			break;
+        			// Aceita certificado para esta sessão
+
+        	}
+        }
+    }
+
+    /**
+     * @see javax.net.ssl.X509TrustManager#getAcceptedIssuers()
+     */
+    public X509Certificate[] getAcceptedIssuers() {
+        return this.defaultTrustManager.getAcceptedIssuers();
+    }
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/CertificateParams.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/CertificateParams.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/CertificateParams.java	(revision 1035)
@@ -0,0 +1,13 @@
+package br.gov.serpro.cert;
+
+import java.util.Properties;
+
+public class CertificateParams {
+
+
+
+	public static void setParam(String param){
+
+	}
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/TokenCollection.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/TokenCollection.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/cert/TokenCollection.java	(revision 1035)
@@ -0,0 +1,50 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package br.gov.serpro.cert;
+
+import br.gov.serpro.setup.Setup;
+import java.util.HashMap;
+
+/**
+ *
+ * @author esa
+ */
+class TokenCollection extends HashMap<String, Token>{
+    
+    private String preferedTokenKey;
+    private final Setup setup;
+
+    public TokenCollection(Setup setup){
+       
+        this.setup = setup;
+        this.addTokens(setup.getParameter("token"));
+
+    }
+
+    public void setPreferedToken(java.lang.String preferedTokenKey){
+        
+    }
+
+    public String getPreferedToken(){
+        return preferedTokenKey;
+    }
+
+    private void addTokens(String tokens){
+        
+        String[] tokensArray = tokens.split(",");
+        for (String tokenString : tokensArray){
+            if (tokenString != null && tokenString.length() > 0){
+                String[] tokenArray = tokenString.split(";");
+                Token token = new Token(tokenArray[0], tokenArray[1], this.setup);
+                token.registerToken();
+                if (token.isRegistered()){
+                    this.put(token.getName(), token);
+                }
+            }
+        }
+    }
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/ui/Setup.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/ui/Setup.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/ui/Setup.java	(revision 1035)
@@ -0,0 +1,182 @@
+package br.gov.serpro.setup;
+import java.applet.Applet;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Properties;
+import java.util.ResourceBundle;
+
+
+public class Setup {
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = -8164125429139606589L;
+
+	private Properties parameters;
+	private Properties preferences;
+    private Map<String, ResourceBundle> langResources;
+    Locale currentLocale;
+	private Applet currentApplet;
+	
+    private static final String PREFERENCES_PATH;
+    private static final String EPASS_2000;
+
+    static {
+
+        //PrintStream ps = new PrintStream(System.out);
+		//System.getProperties().list(System.out);
+
+        if (System.getProperty("os.name").equalsIgnoreCase("linux")){
+			EPASS_2000 = "/usr/lib/libepsng_p11.so";
+		}
+		else {
+			EPASS_2000 = System.getenv("SystemRoot").replaceAll("\\\\", "/")+"/system32/ngp11v211.dll";
+            //EPASS_2000 = System.getenv("ProgramFiles")+"\\Gemplus\\GemSafe Libraries\\BIN\\gclib.dll";
+		}
+
+
+		PREFERENCES_PATH = "TESTE";
+
+	}
+
+	public Setup(Applet applet){
+
+		this.currentApplet = applet;
+		parameters = new Properties();
+		//preferences = Do arquivo apontado por preferences_path
+
+		// Pega os parâmetros da applet
+		for (String[] parameter: getParameterInfo()){
+			String parameterName = parameter[0];
+			String parameterValue = this.currentApplet.getParameter(parameterName);
+
+			//System.out.println("Parameter a ser adicionado - " + parameterName + "= " + parameterValue);
+
+			if (parameterValue != null && !parameterValue.equals("")){
+				parameters.setProperty(parameterName.toLowerCase(), parameterValue);
+                if (parameterName.equalsIgnoreCase("locale")){
+                    System.out.println("Locale recebido.");
+                }
+			}
+            else {
+                //Defaults
+                if (parameterName.equalsIgnoreCase("debug")){
+                    parameters.setProperty(parameterName.toLowerCase(), "false");
+                }
+                if (parameterName.equalsIgnoreCase("token")){
+                    parameters.setProperty(parameterName.toLowerCase(), "Epass2000;"+EPASS_2000);
+                }
+                if (parameterName.equalsIgnoreCase("locale")){
+                    System.out.println("Locale não recebido, definindo valor default.");
+                    parameters.setProperty(parameterName.toLowerCase(), "pt_BR");
+                }
+            }
+		}
+
+		//TODO: Pega as preferências do arquivo de preferências se encontrado;
+
+        // Lang Resources
+        currentLocale = this.buildLocale(parameters.getProperty("locale"));
+        langResources = new HashMap<String, ResourceBundle>(2);
+        langResources.put("ExpressoCertMessages", ResourceBundle.getBundle("ExpressoCertMessages", currentLocale));
+
+	}
+
+	public String[][] getParameterInfo(){
+
+		String[][] info = {
+			{"debug", "boolean", "Habilita mensagens de debug"},
+            {"token", "string", "Lista de tokens suportados. Formato: nome1;caminho1,nome2;caminho2"},
+            {"locale", "string", "Locale do sistema"}
+		};
+
+		return info;
+	}
+
+	public String[][] getPreferencesInfo(){
+
+		String[][] info = {
+			{"preferedToken", "string", "Token preferencial do usuário. Formato: nome;caminho"}
+		};
+
+		return info;
+
+	}
+
+	public String getParameter(String key){
+		return parameters.getProperty(key);
+	}
+
+	public String getPreference(String key){
+		return getPreference(key);
+	}
+
+	//TODO: implementar PreferenceNotRegisteredException
+	public void setPreference(String key, String value){
+
+		boolean exists = false;
+		while (!exists){
+			for (String[] preference: getPreferencesInfo()){
+				if (key.equalsIgnoreCase(preference[1])){
+					exists = true;
+					preferences.setProperty(key, value);
+				}
+			}
+		}
+
+		if (!exists){
+//			 throws PreferenceNotRegisteredException();
+            System.out.println("Preferência não existe!");
+		}
+	}
+
+    Locale buildLocale(String localeCode){
+
+        String[] localeItems = localeCode.split("_");
+        Locale locale;
+        
+        switch (localeItems.length){
+            case 1: locale = new Locale(localeItems[0]);
+                    break;
+            case 2: locale = new Locale(localeItems[0], localeItems[1]);
+                    break;
+            case 3: locale = new Locale(localeItems[0], localeItems[1], localeItems[2]);
+                    break;
+            default: locale = new Locale("pt", "BR");
+                    System.out.println("Locale code error, setting default locale: " + locale.toString());
+        }
+
+        return locale;
+    }
+
+    public void addLanguageResource(String langResource){
+        System.out.println("registrando recusro de linguagem " + langResource);
+        langResources.put(langResource, ResourceBundle.getBundle(langResource, currentLocale));
+    }
+
+    public String getLang(String langResource, String message){
+
+        ResourceBundle resource = langResources.get(langResource);
+
+        String i18nText = new String("????");
+        try {
+            i18nText = resource.getString(message);
+        }
+        catch (MissingResourceException e){
+            e.printStackTrace();
+        }
+
+        return i18nText;
+
+        //return message;
+    }
+
+	// TODO: Not Implemented Yet
+	public boolean savePreferences(){
+		return false;
+	}
+
+}
Index: /trunk/seguranca/ExpressoCert/src/br/gov/serpro/util/Base64Utils.java
===================================================================
--- /trunk/seguranca/ExpressoCert/src/br/gov/serpro/util/Base64Utils.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/src/br/gov/serpro/util/Base64Utils.java	(revision 1035)
@@ -0,0 +1,172 @@
+package br.gov.serpro.util;
+
+public class Base64Utils {
+
+    private static byte[] mBase64EncMap, mBase64DecMap;
+
+    /**
+     * Class initializer. Initializes the Base64 alphabet (specified in RFC-2045).
+     */
+    static {
+        byte[] base64Map = {
+            (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F',
+            (byte)'G', (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L',
+            (byte)'M', (byte)'N', (byte)'O', (byte)'P', (byte)'Q', (byte)'R',
+            (byte)'S', (byte)'T', (byte)'U', (byte)'V', (byte)'W', (byte)'X',
+            (byte)'Y', (byte)'Z',
+            (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f',
+            (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l',
+            (byte)'m', (byte)'n', (byte)'o', (byte)'p', (byte)'q', (byte)'r',
+            (byte)'s', (byte)'t', (byte)'u', (byte)'v', (byte)'w', (byte)'x',
+            (byte)'y', (byte)'z',
+            (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
+            (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/' };
+        mBase64EncMap = base64Map;
+        mBase64DecMap = new byte[128];
+        for (int i=0; i<mBase64EncMap.length; i++)
+            mBase64DecMap[mBase64EncMap[i]] = (byte) i;
+    }
+
+    /**
+     * This class isn't meant to be instantiated.
+     */
+    private Base64Utils() {
+    }
+
+    /**
+     * Encodes the given byte[] using the Base64-encoding,
+     * as specified in RFC-2045 (Section 6.8).
+     *
+     * @param aData the data to be encoded
+     * @return the Base64-encoded <var>aData</var>
+     * @exception IllegalArgumentException if NULL or empty array is passed
+     */
+    public static String base64Encode(byte[] aData) {
+        if ((aData == null) || (aData.length == 0))
+            throw new IllegalArgumentException("Can not encode NULL or empty byte array.");
+
+        byte encodedBuf[] = new byte[((aData.length+2)/3)*4];
+
+        // 3-byte to 4-byte conversion
+        int srcIndex, destIndex;
+        for (srcIndex=0, destIndex=0; srcIndex < aData.length-2; srcIndex += 3) {
+            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex] >>> 2) & 077];
+            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex+1] >>> 4) & 017 |
+                        (aData[srcIndex] << 4) & 077];
+            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex+2] >>> 6) & 003 |
+                        (aData[srcIndex+1] << 2) & 077];
+            encodedBuf[destIndex++] = mBase64EncMap[aData[srcIndex+2] & 077];
+        }
+
+        // Convert the last 1 or 2 bytes
+        if (srcIndex < aData.length) {
+            encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex] >>> 2) & 077];
+            if (srcIndex < aData.length-1) {
+                encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex+1] >>> 4) & 017 |
+                    (aData[srcIndex] << 4) & 077];
+                encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex+1] << 2) & 077];
+            }
+            else {
+                encodedBuf[destIndex++] = mBase64EncMap[(aData[srcIndex] << 4) & 077];
+            }
+        }
+
+        // Add padding to the end of encoded data
+        while (destIndex < encodedBuf.length) {
+            encodedBuf[destIndex] = (byte) '=';
+            destIndex++;
+        }
+
+        String result = new String(encodedBuf);
+        return result;
+    }
+
+
+    /**
+     * Decodes the given Base64-encoded data,
+     * as specified in RFC-2045 (Section 6.8).
+     *
+     * @param aData the Base64-encoded aData.
+     * @return the decoded <var>aData</var>.
+     * @exception IllegalArgumentException if NULL or empty data is passed
+     */
+    public static byte[] base64Decode(String aData) {
+        if ((aData == null) || (aData.length() == 0))
+            throw new IllegalArgumentException("Can not decode NULL or empty string.");
+
+        byte[] data = aData.getBytes();
+
+        // Skip padding from the end of encoded data
+        int tail = data.length;
+        while (data[tail-1] == '=')
+            tail--;
+
+        byte decodedBuf[] = new byte[tail - data.length/4];
+
+        // ASCII-printable to 0-63 conversion
+        for (int i = 0; i < data.length; i++)
+            data[i] = mBase64DecMap[data[i]];
+
+        // 4-byte to 3-byte conversion
+        int srcIndex, destIndex;
+        for (srcIndex = 0, destIndex=0; destIndex < decodedBuf.length-2;
+                srcIndex += 4, destIndex += 3) {
+            decodedBuf[destIndex] = (byte) ( ((data[srcIndex] << 2) & 255) |
+                ((data[srcIndex+1] >>> 4) & 003) );
+            decodedBuf[destIndex+1] = (byte) ( ((data[srcIndex+1] << 4) & 255) |
+                ((data[srcIndex+2] >>> 2) & 017) );
+            decodedBuf[destIndex+2] = (byte) ( ((data[srcIndex+2] << 6) & 255) |
+                (data[srcIndex+3] & 077) );
+        }
+
+        // Handle last 1 or 2 bytes
+        if (destIndex < decodedBuf.length)
+            decodedBuf[destIndex] = (byte) ( ((data[srcIndex] << 2) & 255) |
+                ((data[srcIndex+1] >>> 4) & 003) );
+        if (++destIndex < decodedBuf.length)
+            decodedBuf[destIndex] = (byte) ( ((data[srcIndex+1] << 4) & 255) |
+                ((data[srcIndex+2] >>> 2) & 017) );
+
+        return decodedBuf;
+    }
+
+    public static String der2pem(byte[] der){
+
+    	int begin = 0;
+    	int lineSize = 64;
+    	int end = lineSize;
+    	int bytesWriten = 0;
+
+
+    	String LF = "\n";
+    	String beginCertificate = "-----BEGIN CERTIFICATE-----" +LF;
+    	String endCertificate = "-----END CERTIFICATE-----";
+
+    	String base64encoded = Base64Utils.base64Encode(der);
+
+    	StringBuilder sb = new StringBuilder();
+    	sb.append(beginCertificate);
+
+
+    	do {
+
+    		if (base64encoded.length() - begin < end - begin){
+    			end = base64encoded.length();
+    		}
+
+    		String subs = base64encoded.substring(begin, end);
+    		sb.append(subs + LF);
+    		bytesWriten += end - begin;
+    		begin = end;
+    		end += lineSize;
+
+    	} while (bytesWriten != base64encoded.length());
+
+    	sb.append(endCertificate);
+
+    	return sb.toString();
+
+
+    }
+
+}
Index: /trunk/seguranca/ExpressoCert/build.xml
===================================================================
--- /trunk/seguranca/ExpressoCert/build.xml	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/build.xml	(revision 1035)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="ExpressoCert_trunk" default="default" basedir=".">
+    <description>Builds, tests, and runs the project ExpressoCert_trunk.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="ExpressoCert_trunk-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
Index: /trunk/seguranca/ExpressoCert/nbbuild.xml
===================================================================
--- /trunk/seguranca/ExpressoCert/nbbuild.xml	(revision 1035)
+++ /trunk/seguranca/ExpressoCert/nbbuild.xml	(revision 1035)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="ExpressoCert_trunk" default="default" basedir=".">
+    <description>Builds, tests, and runs the project ExpressoCert_trunk.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="ExpressoCert_trunk-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
Index: /trunk/seguranca/certs_xml.php
===================================================================
--- /trunk/seguranca/certs_xml.php	(revision 1035)
+++ /trunk/seguranca/certs_xml.php	(revision 1035)
@@ -0,0 +1,72 @@
+<?php
+	require_once('classes/CertificadoB.php');
+	// pega caminho completo do arquivo de CAS..
+	$path3 =$GLOBALS['CAs'];
+        // se não pude acessar o arquivo com certificados retornar .....
+	if(!is_file($path3)) exit();
+	$xml  = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+	$todos_certificados = ler_certificados_CAS($path3);
+	$CB = new CertificadoB();
+	if($_REQUEST['id'])
+		{
+			if($_REQUEST['id'] != 'A')
+				{
+				        // id indica o certificado solicitado ....
+					$aux = explode('-',$_REQUEST['id']);
+					if(count($aux) > 1)
+						{
+							$id =$aux[0];
+							$id = $id -1;
+						}
+					else
+						{
+							$id = 0;
+						}
+					// Pega o certificado solicitado ...
+					$certificado = $todos_certificados[$id];
+					// Vai parsear, e gerar o xml ...
+					$CB -> certificado($certificado);
+					// Pega o xml com os dados do certificado ..
+					$xml .= $CB -> dados_xml;
+				}
+			else
+				{
+					// Requisitado todo o conteudo do arquivo de CAs ..
+					$item = 1;
+					$xml .= "<certs>";
+					foreach($todos_certificados as $certificado)
+						{
+							$CB -> certificado($certificado);
+							$df = $CB -> dados['FIM_VALIDADE'];
+							$xml .= '<certs>';
+							$xml .= '  <nome>' . 
+											$item++ . ' - ' . 
+											$CB->dados['SUBJECT']['CN'] .
+											'  ( Expira Em: ;' . substr($df,0,4) . 
+											'/' . 
+											substr($df,4,2) . 
+											'/' . 
+											substr($df,6,2) . 
+											'  -  ' . 
+											substr($df,8,2) . 
+											':' . 
+											substr($df,10,2) . 
+											':' . 
+											substr($df,12,2) . 
+											' GMT )' . 
+									'</nome>'; 
+							$xml .= '</certs>';
+						}
+					$xml .= "</certs>"; 
+				}
+		}
+	else 
+		{
+			exit();	
+		}
+        # Fecha o processamento de geracao do xml  com um CABEÇALHO
+	Header('Content-type: application/xml; charset=utf-8'); 
+	echo $xml;
+    ?>
+  
+  
Index: /trunk/seguranca/crl_admin/crl_admin.py
===================================================================
--- /trunk/seguranca/crl_admin/crl_admin.py	(revision 1035)
+++ /trunk/seguranca/crl_admin/crl_admin.py	(revision 1035)
@@ -0,0 +1,112 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import os, popen2, fcntl, select, time
+from string import replace
+
+theOutput = [] 
+
+def fazlog(dados):
+	for i in dados:
+		aux = i.split('\n')
+		for x in aux:
+			logging.info(x)
+
+def makeNonBlocking(fd): 
+     fl = fcntl.fcntl(fd, fcntl.F_GETFL) 
+     try: 
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NDELAY) 
+     except AttributeError: 
+        fcntl.fcntl(fd, fcntl.F_SETFL, fl | fcntl.FNDELAY) 
+  
+def ExeCmd(command): 
+    theOutput = [] 
+    child = popen2.Popen3(command, 1)      	# Captura a stdout e a stderr do comando... 
+    child.tochild.close()                             	# NÃ£o estamos "falando(escrevendo para a stdin do comando) com o processo filho... 
+    outfile = child.fromchild 
+    outfd = outfile.fileno() 
+    errfile = child.childerr 
+    errfd = errfile.fileno() 
+    makeNonBlocking(outfd)                          	# NÃ£o queremos um deadlock !!!!( Dica do Python Cookbook v1)
+    makeNonBlocking(errfd) 
+    outdata = errdata = '' 
+    outeof = erreof = 0 
+    while 1: 
+        ready = select.select([outfd,errfd],[],[]) # Aguarda a entrada(saida do comando) 
+        if outfd in ready[0]: 
+           outchunk = outfile.read() 
+           if outchunk == '': outeof = 1 
+           outdata = outdata + outchunk 
+        if errfd in ready[0]: 
+           errchunk = errfile.read() 
+           if errchunk == '': erreof = 1 
+           errdata = errdata + errchunk 
+        if outeof and erreof: break 
+        select.select([],[],[],.1)                         	#Da um tempo para os buffers serem preenchidosl 
+    err = child.wait() 
+    #if err != 0: 
+    #   raise RuntimeError, '%s failed w/ exit code %d\n%s' % (command, err, errdata) 
+    theOutput.append(outdata) 
+    theOutput.append(errdata) 
+    return theOutput 
+
+# No arquivo crl_admin_confg esta o path (arquivo) que aponta para a configuracao das urls(CRL_urls) das crls que devem ser obtidas.
+# Este arquivo tambem informa o arquivo onde sera gravada a log(log), e o arquivo contendo 
+# a cadeia de certificados para verificar as crls(CAfile).
+# Apos o import, executar a funcao ler_conf() .....
+from crl_admin_confg import *
+
+import logging
+
+# Configura como sera a log .....
+logging.basicConfig(level=logging.INFO,
+                    format='%(asctime)s %(levelname)s %(message)s',
+                    filename=log,
+                    filemode='a')
+
+# A execucao da funcao a seguir carrega a lista das CRLs (CRL_urls) que devem ser processadas...
+ler_conf()
+
+for crl in CRL_urls:
+        arquivo = crl[1] + os.path.split(crl[0])[1]
+	url = crl[0] 
+
+        # Obtendo o arquivo com wget ... 
+	logging.info('Buscando a CRL: ' + url)
+	saida_wget = ExeCmd("wget " + url + " -O " + arquivo)
+
+	# Abaixo estamos comandando a execucao "openssl crl" passando o arquivo crl .
+	# O resultado esta em saida. Tem de ser 'verify OK' .
+	if os.path.exists(arquivo) and os.path.getsize(arquivo) > 0:
+		logging.info('Verificando ' + arquivo + '(' + str(os.path.getsize(arquivo)) + ' Bytes)')
+		saida = ExeCmd('openssl crl -CAfile ' + CAfile + '  -in ' + arquivo + ' -inform DER -noout')
+		# usa a funcao fazlog porque saida he um array.....
+		fazlog(saida)
+		try:
+			aux1 = replace(saida[1],'\n','')
+			if not aux1 == 'verify OK':
+				logging.critical('Erro verificando a CRL ' + arquivo + '\n')
+				try:
+					os.remove(arquivo)
+				except:
+					pass
+				continue
+                        # A crl foi verificada e est OK.... 
+			# Atuaiza a data do arquivo...
+			saida = ExeCmd('touch ' + arquivo)
+		except:
+			logging.critical('Erro processando o status da verificacao da CRL ' + arquivo + '\n')
+			try:
+				os.remove(arquivo)
+			except:
+				pass
+			continue
+	else:
+		# usa a funcao fazlog porque saida_wget he um array.....
+                fazlog(saida_wget) 
+		logging.critical('Nao foi possivel obter a CRL ' + url + '\n')
+		try:
+			os.remove(arquivo)
+		except:
+			pass
+
Index: /trunk/seguranca/crl_admin/crl_admin_confg.py
===================================================================
--- /trunk/seguranca/crl_admin/crl_admin_confg.py	(revision 1035)
+++ /trunk/seguranca/crl_admin/crl_admin_confg.py	(revision 1035)
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+# Lista com as urls das CRLs, e onde colocar(path) os arquivos obtidos ....
+CRL_urls = []
+
+# arquivo : path para o arquivo de configuracao contendo urls das crls e paths onde serao baixadas...
+arquivo = '/var/www/expresso/seguranca/crl_admin/crl_admin.conf'
+		   
+# Arquivo onde sera grada log de execucao da qtualizacao/verificacao das crls.
+log = '/var/www/expresso/logs/arquivo_crls.log'
+
+# Deixe 'log' igual a vazio para ver as msgs de execuÃ§Ã£o no terminal.......
+#log = ''
+
+# Arquivo com cadeia dos certificados das CAs, para verificacao das CRLs.
+CAfile = '/var/www/expresso/seguranca/cas/todos.cer'
+
+def ler_conf():
+        # Esta funcao le o arquivo passado como parametro e gera a lista CRL_urls.
+        # O arquivo he esperado no formato:
+	# url;path       ( url = aponta onde buscar a crl,  e path aponta onde salvar a crl obtida. 
+	e = open(arquivo)
+	r = e.read()
+	aux1 = r.split('\n')
+	for linha in aux1:
+		if linha[0:1] != '#':
+			aux2 = linha.split(';')
+			if aux2[0] != '':
+				CRL_urls.append(aux2)
+	return
Index: /trunk/seguranca/crl_admin/crl_admin.conf
===================================================================
--- /trunk/seguranca/crl_admin/crl_admin.conf	(revision 1035)
+++ /trunk/seguranca/crl_admin/crl_admin.conf	(revision 1035)
@@ -0,0 +1,21 @@
+# Lista das urls apontando CRLs, e onde colocar(path) os arquivos obtidos ....
+# Formato:
+# url;path   ( o path deve terminar com uma / )
+http://ccd.serpro.gov.br/lcr/serproacfv1.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/serproacfv2.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/ACPRv1.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/ACPRv2.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/ACSERPRORFB.crl;/var/www/expresso/seguranca/crls/
+http://acraiz.icpbrasil.gov.br/LCRacraizv1.crl;/var/www/expresso/seguranca/crls/
+http://acraiz.icpbrasil.gov.br/LCRacraiz.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/acserpro.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/acserprojus.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/acserprorfb.crl;/var/www/expresso/seguranca/crls/
+http://ccd.serpro.gov.br/lcr/acserprosrf.crl;/var/www/expresso/seguranca/crls/
+http://icp.caixa.gov.br/repositorio/ACCAIXA1.crl;/var/www/expresso/seguranca/crls/
+http://icp.caixa.gov.br/repositorio/ACCAIXAPF1.crl;/var/www/expresso/seguranca/crls/
+http://icp.caixa.gov.br/repositorio/ACCAIXAPJ1.crl;/var/www/expresso/seguranca/crls/
+http://icp.caixa.gov.br/repositorio/ACCAIXAJUS.crl;/var/www/expresso/seguranca/crls/
+http://ccdhom.serpro.gov.br/lcr/homacraizv2.crl;/var/www/expresso/seguranca/crls/
+http://ccdhom.serpro.gov.br/lcr/homserprov2.crl;/var/www/expresso/seguranca/crls/
+http://ccdhom.serpro.gov.br/lcr/acserprorfbv1.crl;/var/www/expresso/seguranca/crls/
Index: /trunk/seguranca/ExpressoCertMail/manifest.mf
===================================================================
--- /trunk/seguranca/ExpressoCertMail/manifest.mf	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/manifest.mf	(revision 1035)
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
Index: /trunk/seguranca/ExpressoCertMail/src/br/gov/serpro/js/ParamReaderThread.java
===================================================================
--- /trunk/seguranca/ExpressoCertMail/src/br/gov/serpro/js/ParamReaderThread.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/src/br/gov/serpro/js/ParamReaderThread.java	(revision 1035)
@@ -0,0 +1,216 @@
+package br.gov.serpro.js;
+
+import java.awt.Frame;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+import java.security.ProviderException;
+import java.util.Map;
+
+import javax.mail.MessagingException;
+
+import org.bouncycastle.mail.smime.SMIMEException;
+import br.gov.serpro.cert.DigitalCertificate;
+import br.gov.serpro.setup.Setup;
+import br.gov.serpro.ui.DialogBuilder;
+import br.gov.serpro.util.Base64Utils;
+
+import netscape.javascript.JSObject;
+import org.bouncycastle.cms.CMSException;
+
+
+public class ParamReaderThread extends Thread {
+
+	JSObject page;
+	Javascript2AppletPassingData data;
+	Setup setup;
+	Frame parentFrame;
+
+	public ParamReaderThread(JSObject page, Javascript2AppletPassingData data, Setup setup, Frame parent) {
+	//public ParamReaderThread(JSObject page, Javascript2AppletPassingData data, Setup setup) {
+		super();
+		this.page = page;
+		this.data = data;
+		this.setup = setup;
+		this.parentFrame = parent;
+	}
+
+	@Override
+	public void run() {
+		// TODO Stub de método gerado automaticamente
+		super.run();
+
+        while (true){
+			if (setup.getParameter("debug").equalsIgnoreCase("true")){
+				System.out.println("Classe ParamReaderThread: pegando resultado.");
+			}
+            
+            // processa o smime. Método sign implementado na classe DigitalCertificate
+            String smime = null;
+            DigitalCertificate dc = null;
+
+            try {
+
+                //Map<String, String> parsedData = parseData(resultado);
+                Map<String, String> parsedData = data.getMap();
+
+                dc = new DigitalCertificate(this.parentFrame, this.setup);
+                dc.init();
+
+                // Testa a operação e se for
+                if (parsedData.get("operation").equals("sign")){
+
+                    smime = dc.signMail(parsedData);
+                    if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                        System.out.println("\nMensagem assinada: " + smime);
+                    }
+
+                }
+              else if (parsedData.get("operation").equals("decript")){
+                    String decryptedMsg = dc.cipherMail(parsedData);
+                    if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                        System.out.println("Mensagem decifrada: " + decryptedMsg);
+                    }
+                    if (decryptedMsg == null){
+                        smime = null;
+                    } else {
+                        smime = Base64Utils.base64Encode(decryptedMsg.getBytes());
+                    }
+                    
+                }
+                else {
+                    throw new UnsupportedOperationException("Operation not supported: " + parsedData.get("operation"));
+                    // Lança
+                }
+
+                // Retorna para a página
+                // se smime = null, a assinatura não funcionou
+                if (smime != null){
+                    page.call("appletReturn", new String[] {smime, parsedData.get("ID"), parsedData.get("operation"), parsedData.get("folder")});
+                }
+
+            } catch (IOException e) {
+                //DialogBuilder.showMessageDialog(this.parentFrame, "Não foi possível carregar Token/SmartCard: senha incorreta", this.setup);
+                DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMailMessages", "ParamReaderThread001"), this.setup);
+                //JOptionPane.showMessageDialog(this.parentFrame, "Não foi possível carregar Token/SmartCard: senha incorreta",
+                //        "Aviso", JOptionPane.INFORMATION_MESSAGE);
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            } catch (GeneralSecurityException e) {
+                if (e.getCause() != null){
+                    DialogBuilder.showMessageDialog(this.parentFrame, "GeneralSecurityException: " + e.getCause().getMessage(), this.setup);
+                    //JOptionPane.showMessageDialog(this.parentFrame, "GeneralSecurityException: " + e.getCause().getMessage(),
+                    //        "Aviso", JOptionPane.INFORMATION_MESSAGE);
+                }
+                else {
+                    DialogBuilder.showMessageDialog(this.parentFrame, "GeneralSecurityException: " + e.getMessage(), this.setup);
+                    //JOptionPane.showMessageDialog(this.parentFrame, "GeneralSecurityException: " + e.getMessage(),
+                    //        "Aviso", JOptionPane.INFORMATION_MESSAGE);
+                }
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            } catch (SMIMEException e) {
+                //DialogBuilder.showMessageDialog(this.parentFrame, "Erro no processamento da assinatura: " + e.getMessage(), this.setup);
+                DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMailMessages", "ParamReaderThread002"), this.setup);
+                //JOptionPane.showMessageDialog(this.parentFrame, "Erro no processamento da assinatura: " + e.getMessage(),
+                //        "Aviso", JOptionPane.INFORMATION_MESSAGE);
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            } catch (MessagingException e) {
+                //DialogBuilder.showMessageDialog(this.parentFrame, "Erro no processamento da mensagem: " + e.getMessage(), this.setup);
+                DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMailMessages", "ParamReaderThread003"), this.setup);
+                //JOptionPane.showMessageDialog(this.parentFrame, "Erro no processamento da mensagem: " + e.getMessage(),
+                //        "Aviso", JOptionPane.INFORMATION_MESSAGE);
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            }
+            catch (CMSException e){
+                //DialogBuilder.showMessageDialog(this.parentFrame, "Erro ao decifrar mensagem: Detectado problema na integridade da mensagem cifrada!", this.setup);
+                DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMailMessages", "ParamReaderThread004"), this.setup);
+                //if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                Throwable cause = e.getCause();
+                System.out.println(e.getClass().getCanonicalName() + ": " + e.getMessage());
+                if (cause != null){
+                    System.out.println(cause.getClass().getCanonicalName() + ": " + cause.getMessage());
+                }
+                e.printStackTrace();
+                //}
+            }
+            catch (ProviderException e){
+                //DialogBuilder.showMessageDialog(this.parentFrame, "Problema no acesso às informações do Token: " + e.getMessage(), this.setup);
+                DialogBuilder.showMessageDialog(this.parentFrame, setup.getLang("ExpressoCertMailMessages", "ParamReaderThread005"), this.setup);
+                //JOptionPane.showMessageDialog(this.parentFrame, "Problema no acesso às informações do Token: " + e.getMessage(),
+                //        "Aviso", JOptionPane.INFORMATION_MESSAGE);
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            }
+            catch (UnsupportedOperationException e){
+                // DialogBuilder.showMessageDialog(this.parentFrame, e.getMessage());
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            }
+            catch (IllegalArgumentException e){
+                //DialogBuilder.showMessageDialog(this.parentFrame, e.getMessage());
+                if (setup.getParameter("debug").equalsIgnoreCase("true")) {
+                    e.printStackTrace();
+                }
+            }
+            catch (InterruptedException e){
+                if (setup.getParameter("debug").equalsIgnoreCase("true")){
+                    System.out.println("Classe ParamReaderThread: Thread has been interrupted! Break.");
+                    e.printStackTrace();
+                }
+                break;
+            }
+
+			dc.destroy();
+			dc = null;
+			System.gc();
+            Thread.yield();
+
+        }
+	}
+
+	//TODO: Documentar o que recebe!!!
+	/*private Map<String, String> parseData(String expressoMailData){
+
+        if ((expressoMailData == null) || (expressoMailData.length() == 0)){
+            throw new IllegalArgumentException("Can't unserialize NULL or empty value!");
+        }
+
+		Map<String, String> parsedData = new HashMap<String, String> ();
+		//Map<String, String> headersData = new HashMap<String, String>();
+
+		for (String paramsArray : expressoMailData.split(";")){
+
+			if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+				System.out.println("sendo parseado: " + paramsArray);
+			}
+			String[] param = paramsArray.split(":");
+			//if (temp[0].equals("headers")){
+			//	String[] headersArray = new String(Base64Utils.base64Decode(temp[1])).split(";");
+			//	for (String header: headersArray){
+			//		String[] keyValueType = header.split(":");
+			//		headersData.put(keyValueType[0], keyValueType[1]);
+			//	}
+			//}
+			//else{
+			parsedData.put(param[0], new String(Base64Utils.base64Decode(param[1])));
+			//}
+
+		}
+
+		return parsedData;
+	}
+
+	static private String processReturn(Map smimeData){
+
+		return new String();
+	}
+*/
+}
Index: /trunk/seguranca/ExpressoCertMail/src/br/gov/serpro/js/Javascript2AppletPassingData.java
===================================================================
--- /trunk/seguranca/ExpressoCertMail/src/br/gov/serpro/js/Javascript2AppletPassingData.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/src/br/gov/serpro/js/Javascript2AppletPassingData.java	(revision 1035)
@@ -0,0 +1,67 @@
+package br.gov.serpro.js;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class Javascript2AppletPassingData {
+
+	private boolean locked = true;
+	private String data = null;
+    private Map<String, String> mapData = null;
+
+	public synchronized String getData() throws InterruptedException{
+		if (isLocked()){
+			data = null;
+            wait();
+		}
+		lock();
+		//notifyAll();
+		return this.data;
+	}
+
+	public synchronized Map<String, String> getMap() throws InterruptedException{
+		if (isLocked()){
+			mapData = null;
+            wait();
+		}
+		lock();
+		//notifyAll();
+		return this.mapData;
+	}
+
+	public synchronized void setData(String data){
+		//flag = true;
+		this.data = data;
+		unlock();
+	}
+
+    public synchronized void setData(String operation, String id, String body){
+		//flag = true;
+        if (this.mapData == null) {
+            this.mapData = new HashMap<String, String>();
+        }
+		this.mapData.put("operation", operation);
+        this.mapData.put("ID", id);
+        this.mapData.put("body", body);
+		unlock();
+	}
+
+    public synchronized void setData(String operation, String id, String body, String folder){
+        this.mapData = new HashMap<String, String>();
+        this.mapData.put("folder", folder);
+        this.setData(operation, id, body);
+    }
+
+	public synchronized void unlock(){
+		locked = false;
+		notifyAll();
+	}
+
+	private synchronized void lock(){
+		locked = true;
+	}
+
+	public synchronized boolean isLocked(){
+		return locked;
+	}
+}
Index: /trunk/seguranca/ExpressoCertMail/src/Main.java
===================================================================
--- /trunk/seguranca/ExpressoCertMail/src/Main.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/src/Main.java	(revision 1035)
@@ -0,0 +1,82 @@
+import java.applet.Applet;
+
+import netscape.javascript.JSObject;
+
+import br.gov.serpro.cert.DigitalCertificate;
+import br.gov.serpro.setup.Setup;
+
+
+public class Main extends Applet{
+
+	//private DigitalCertificate teste;
+	private Thread executaTeste;
+	private DataReader dataReader;
+	private JSObject page;
+	private Setup setup;
+
+	/**
+	 *
+	 */
+	private static final long serialVersionUID = 1726731542858100340L;
+
+	/**
+	 *
+	 */
+	public void start() {
+		this.setup = new Setup(this);
+		//this.teste = new DigitalCertificate();
+		this.dataReader = new DataReader();
+		//this.data.setResultado(this.teste.init());
+		this.executaTeste = new Leitor(dataReader, JSObject.getWindow(this), setup);
+		this.executaTeste.start();
+
+		//this.page = JSObject.getWindow(this);
+		/*try{
+			SwingUtilities.invokeAndWait(new Runnable(){
+
+				public void run() {
+					// TODO Auto-generated method stub
+					int resultado = teste.init();
+					System.out.println("Event Dispatching Thread: Resultado apÃ³s leitura do token" + resultado);
+					dataReader.setResultado(resultado);
+				}
+
+			});
+		}
+		catch (InterruptedException e){
+			e.printStackTrace();
+		}
+		catch (InvocationTargetException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		*/
+	}
+
+	//TODO: Testar a passagem de parÃ¢metros do javascript para a applet
+	/**
+	 * @param args
+	 */
+	public void doButtonClickAction(String resultado){
+		dataReader.setResultado(resultado);
+		dataReader.unlock();
+		//return "cert";
+	}
+
+	//public class Executor extends Thread {
+		//
+	//	@Override
+	//	public void run() {
+	//		// TODO Auto-generated method stub
+	//		super.run();
+//
+	//		// chamar funÃ§Ã£o no javascript
+	//		System.out.println("Classe executor: pegando resultado.");
+	//		int resultado = dataReader.getResultado();
+	//		page.call("mostraResultado", new String[] {Integer.toString(resultado)});
+
+	//	}
+
+	//}
+
+}
Index: /trunk/seguranca/ExpressoCertMail/src/ExpressoSmimeApplet.java
===================================================================
--- /trunk/seguranca/ExpressoCertMail/src/ExpressoSmimeApplet.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/src/ExpressoSmimeApplet.java	(revision 1035)
@@ -0,0 +1,90 @@
+import java.awt.Frame;
+
+import javax.swing.JApplet;
+import javax.swing.SwingUtilities;
+
+import netscape.javascript.JSObject;
+
+import br.gov.serpro.js.Javascript2AppletPassingData;
+import br.gov.serpro.js.ParamReaderThread;
+import br.gov.serpro.setup.Setup;
+
+//TODO: Logs de depuração e interface para usuário reportar problemas.
+
+public class ExpressoSmimeApplet extends JApplet {
+
+	/**
+	 * Variáveis de instância
+	 */
+	private Setup setup;
+	private Javascript2AppletPassingData dataReader;
+	private Thread paramReaderThread;
+
+	/**
+	 * Variáveis de classe
+	 */
+	private static final long serialVersionUID = 4797603392324194391L;
+
+	@Override
+	public void init() {
+		super.init();
+		this.setSize(1, 1);
+		this.setup = new Setup(this);
+        this.setup.addLanguageResource("ExpressoCertMailMessages");
+		this.dataReader = new Javascript2AppletPassingData();
+		// this.paramReaderThread = new ParamReaderThread(JSObject.getWindow(this), dataReader, setup);
+		this.paramReaderThread = new ParamReaderThread(JSObject.getWindow(this), dataReader,
+				setup, (Frame) SwingUtilities.getAncestorOfClass(Frame.class, this));
+		this.paramReaderThread.start();
+	}
+
+	@Override
+    /**
+     * Retorna Informações sobre os parâmetros que essa applet aceita
+     * @author Mário César Kolling <mario.kolling@serpro.gov.br>
+     * @return String[][] Uma matriz de Strings relacionando cada parâmetro à sua descrição
+     */
+	public String[][] getParameterInfo() {
+		return setup.getParameterInfo();
+	}
+
+	@Override
+	public void start() {
+		super.start();
+
+	}
+
+	@Override
+	public void stop() {
+		super.stop();
+		//dataReader.unlock();
+
+        if (this.paramReaderThread.isAlive()){
+            if (setup.getParameter("debug").equalsIgnoreCase("true")){
+                System.out.println("Interrompendo Applet paramReaderThread");
+            }
+            this.paramReaderThread.interrupt();
+        }
+	}
+
+	/**
+     * Método da Applet chamado pela página (js) ao assinar ou decifrar um e-mail
+	 * @param resultado Dados serializados passados pela Applet
+	 */
+	public void doButtonClickAction(String resultado){
+		dataReader.setData(resultado);
+		dataReader.unlock();
+		//return "cert";
+	}
+
+    public void doButtonClickAction(String operation, String id, String body){
+        dataReader.setData(operation, id, body);
+        //dataReader.unlock();
+    }
+
+    public void doButtonClickAction(String operation, String id, String body, String folder){
+        dataReader.setData(operation, id, body, folder);
+        //dataReader.unlock();
+    }
+
+}
Index: /trunk/seguranca/ExpressoCertMail/src/DataReader.java
===================================================================
--- /trunk/seguranca/ExpressoCertMail/src/DataReader.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/src/DataReader.java	(revision 1035)
@@ -0,0 +1,33 @@
+
+public class DataReader {
+
+	private boolean flag = false;
+	private String resultado;
+
+	public synchronized String getResultado(){
+		lock();
+		//notifyAll();
+		return this.resultado;
+	}
+
+	public synchronized void setResultado(String resultado){
+		//flag = true;
+		this.resultado = resultado;
+	}
+
+	public synchronized void unlock(){
+		flag = true;
+		notifyAll();
+	}
+
+	private synchronized void lock(){
+		while (!flag){
+			try{
+				wait();
+			}
+			catch (InterruptedException e){}
+		}
+		flag = false;
+	}
+
+}
Index: /trunk/seguranca/ExpressoCertMail/src/Leitor.java
===================================================================
--- /trunk/seguranca/ExpressoCertMail/src/Leitor.java	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/src/Leitor.java	(revision 1035)
@@ -0,0 +1,37 @@
+import br.gov.serpro.setup.Setup;
+import netscape.javascript.JSObject;
+
+
+class Leitor extends Thread {
+
+	private DataReader dataReader;
+	private JSObject page;
+	private Setup setup;
+
+	public Leitor(DataReader dataReader, JSObject page, Setup setup){
+		this.dataReader = dataReader;
+		this.page = page;
+		this.setup = setup;
+	}
+
+	public void run() {
+		// TODO Auto-generated method stub
+		super.run();
+		// chamar funÃ§Ã£o no javascript
+		while (true){
+			if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+				System.out.println("Classe executor: pegando resultado.");
+			}
+
+			String resultado = dataReader.getResultado();
+			if (this.setup.getParameter("debug").equalsIgnoreCase("true")){
+				System.out.println("Classe Executor: chamando funÃ§Ã£o appletReturn() no javascript");
+				System.out.println("Classe Executor: valor de retorno: " + resultado);
+			}
+
+			page.call("appletReturn", new String[] {resultado});
+
+		}
+	}
+
+}
Index: /trunk/seguranca/ExpressoCertMail/testapplet.html
===================================================================
--- /trunk/seguranca/ExpressoCertMail/testapplet.html	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/testapplet.html	(revision 1035)
@@ -0,0 +1,39 @@
+<html>
+	<head>
+		<title>Applet de Teste para Criptografia</title>
+	</head>
+	<body>
+
+		<form id="form1">
+		<script language="Javascript">
+			if (navigator.userAgent.match('MSIE')){
+				document.write('<object style="display:yes" id="cert_applet"' +
+					'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" width="300" height="125">' +
+					'<param name="type" value="application/x-java-applet;version=1.5">' +
+					'<param name="code" value="Main.class">' +
+					'<param name="mayscript" value="true">' +
+					'<param name="archive" value="ExpressoCertMail.jar,bcmail-jdk15-140.jar">');
+			}
+			else {
+				document.write('<embed id="cert_applet" code="Main.class" archive="ExpressoCertMail.jar,bcmail-jdk15-140.jar"' +
+					'type="application/x-java-applet;version=1.5" width="300" height="125" mayscript >' +
+					'<noembed>' +
+					'No Java Support.' +
+					'</noembed>' +
+					'</embed>');
+			}
+		</script>
+		<input type="button" id="botao" value="Mostra" onclick="buttonClick();"/>
+		</form>
+		<script language="javascript">
+			function buttonClick(){
+				var applet = document.getElementById('cert_applet');
+				applet.doButtonClickAction();
+			}
+
+			function mostraResultado(resultado){
+				alert(resultado);
+			}
+		</script>
+	</body>
+</html>
Index: /trunk/seguranca/ExpressoCertMail/build.xml
===================================================================
--- /trunk/seguranca/ExpressoCertMail/build.xml	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/build.xml	(revision 1035)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="ExpressoCertMail_trunk" default="default" basedir=".">
+    <description>Builds, tests, and runs the project ExpressoCertMail_trunk.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="ExpressoCertMail_trunk-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
Index: /trunk/seguranca/ExpressoCertMail/nbbuild.xml
===================================================================
--- /trunk/seguranca/ExpressoCertMail/nbbuild.xml	(revision 1035)
+++ /trunk/seguranca/ExpressoCertMail/nbbuild.xml	(revision 1035)
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="ExpressoCertMail_trunk" default="default" basedir=".">
+    <description>Builds, tests, and runs the project ExpressoCertMail_trunk.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="ExpressoCertMail_trunk-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
Index: /trunk/seguranca/captcha.php
===================================================================
--- /trunk/seguranca/captcha.php	(revision 1035)
+++ /trunk/seguranca/captcha.php	(revision 1035)
@@ -0,0 +1,115 @@
+<?php
+ /******************************************************************
+   Projectname:   CAPTCHA class
+   Version:       1.1
+   Author:        Pascal Rehfeldt <Pascal@Pascal-Rehfeldt.com>
+   Last modified: 15. March 2004
+   Copyright (C): 2003, 2004 Pascal Rehfeldt, all rights reserved
+
+   * GNU General Public License (Version 2, June 1991)
+   *
+   * This program is free software; you can redistribute
+   * it and/or modify it under the terms of the GNU
+   * General Public License as published by the Free
+   * Software Foundation; either version 2 of the License,
+   * or (at your option) any later version.
+   *
+   * This program is distributed in the hope that it will
+   * be useful, but WITHOUT ANY WARRANTY; without even the
+   * implied warranty of MERCHANTABILITY or FITNESS FOR A
+   * PARTICULAR PURPOSE. See the GNU General Public License
+   * for more details.
+
+   Description:
+   This class can generate CAPTCHAs, see README for more details!
+
+   Get the "Hurry up!" Font for the Captcha and
+   save it in the same directory as this file.
+
+   "Hurry up!" Font (c) by Andi
+   See http://www.1001fonts.com/font_details.html?font_id=2366
+  ******************************************************************/
+
+  class captcha
+  {
+
+    var $Length;
+    var $CaptchaString;
+    var $ImageType;
+    var $Font;
+    var $CharWidth;
+
+    function captcha ($length = 5, $type = 'png')
+    {
+      $this->Length    = $length;
+      $this->ImageType = $type;
+      $this->Font      = './hurryup.ttf';      
+      $this->CharWidth = 27;
+      $this->StringGen();
+    }
+
+    function Showcaptcha()
+    {
+      $this->SendHeader();
+      $this->MakeCaptcha();   
+    }
+
+    function StringGen ()
+    {
+      $uppercase  = range('A', 'Z');
+      $numeric    = range(0, 9);
+      $CharPool   = array_merge($uppercase, $numeric);
+      $PoolLength = count($CharPool) - 1;
+      for ($i = 0; $i < $this->Length; $i++)
+      {
+        $this->CaptchaString .= $CharPool[mt_rand(0, $PoolLength)];
+      }
+    }
+
+    function SendHeader ()
+    {
+      switch ($this->ImageType)
+      {
+        case 'jpeg': header('Content-type: image/jpeg'); break;
+        case 'png':  header('Content-type: image/png');  break;
+        default:     header('Content-type: image/png');  break;
+      }
+    }
+
+    function MakeCaptcha ()
+    {
+      $imagelength = $this->Length * $this->CharWidth + 16;
+      $imageheight = 37;
+      $image       = imagecreate($imagelength, $imageheight);
+      $bgcolor     = imagecolorallocate($image, 255, 255, 255);
+      $stringcolor = imagecolorallocate($image, 0, 0, 155);
+      $linecolor   = imagecolorallocate($image, 0, 0, 0);
+      imagettftext($image, 25, -4, 8, 25,
+                   $stringcolor,
+                   $this->Font,
+                   $this->CaptchaString);
+      switch ($this->ImageType)
+      {
+        case 'jpeg': imagejpeg($image); break;
+        case 'png':  imagepng($image);  break;
+        default:     imagepng($image);  break;
+      }
+    }
+
+    function GetCaptchaString ()
+    {
+      return $this->CaptchaString;
+    }
+    
+  }
+ 
+ // ************  Fim da Classe  *************************
+ 
+ 
+  //Cria o CAPTCHA( gera o string e a imagem ...
+  $GLOBALS['captcha'] = new captcha;
+  // Guarda o string do captcha na session...
+  $_SESSION['CAPTCHAString'] = $GLOBALS['captcha'] ->GetCaptchaString();
+  // Vai exibir a imagem do captcha...
+  $GLOBALS['captcha'] ->Showcaptcha();
+?>
Index: /trunk/seguranca/classes_BKP/Verifica_Certificado_conf.php
===================================================================
--- /trunk/seguranca/classes_BKP/Verifica_Certificado_conf.php	(revision 1035)
+++ /trunk/seguranca/classes_BKP/Verifica_Certificado_conf.php	(revision 1035)
@@ -0,0 +1,5 @@
+<?php
+$GLOBALS['dirtemp']  =   '/var/www/expresso/seguranca/temp'; 
+$GLOBALS['CAs']  =         '/var/www/expresso/seguranca/cas/todos.cer';
+$GLOBALS['CRLs']  =       '/var/www/expresso/seguranca/crls/'; 
+?>
Index: /trunk/seguranca/classes_BKP/CertificadoB.php
===================================================================
--- /trunk/seguranca/classes_BKP/CertificadoB.php	(revision 1035)
+++ /trunk/seguranca/classes_BKP/CertificadoB.php	(revision 1035)
@@ -0,0 +1,300 @@
+<?php
+require_once('funcoes_auxiliares.php');
+require_once('Verifica_Certificado_conf.php');
+require_once('Verifica_Certificado.php');
+
+//  Pre-requisito: A extensao openssl deve estar disponivel no PHP ....
+class certificadoB
+{
+
+  public $dados = array();        # Area para armazenar os dados recuperados do certificado.
+  public $apresentado =false;    # Deve ser testado para verificar se no certificado processado foi localizado o CPF
+  public $erros_ssl = array(); 
+  public $cert_assinante = '';	
+  public $msg_sem_assinatura = '';  #conteï¿œdo da mensagem sem assinatura, que retorna da funï¿œï¿œo verify do openssl
+  public $arquivos_para_deletar = array();
+  
+  public function __construct()
+  {
+    if(!extension_loaded('openssl'))
+    {
+      #PHP sem suporte ao openssl.....
+      return false;
+    }
+  }
+
+  public function __destruct()
+  {
+    #Remover arquivos temporarios.....	
+    deleta_arquivos_temporarios($this->arquivos_para_deletar);
+  }
+
+
+#--------------------------------------------------------------------------------------------------------------------------------------------------------
+#--------------------------------------------------------------------------------------------------------------------------------------------------------
+# Recupera dados de um certificado no formato pem 
+#--------------------------------------------------------------------------------------------------------------------------------------------------------    
+  function certificado($certificado_pem)
+  {		
+  
+    if (!$certificado_pem) 
+    {
+        $this->apresentado = False;
+        return False;    # Sem parametro ...
+    }
+
+   $this->dados = recupera_dados_do_ceritificado_digital($certificado_pem);
+   
+  # Certificado foi processado, as informacoes obtidas estao em $this->dados. 
+
+  $this->apresentado = true;  
+
+  }
+
+#--------------------------------------------------------------------------------------------------------------------------------------------------------
+#--------------------------------------------------------------------------------------------------------------------------------------------------------
+# Encriptar uma msg($m) para o(s) destinatario(s) $c(array com certificados)com os headers passados em $h.
+#--------------------------------------------------------------------------------------------------------------------------------------------------------    
+	public function encriptar($m,$c,$h)
+	{
+		if($m == '')	return false;
+			
+		if(!is_array($c))	return false;
+		
+		$aux = count($c);
+		if($aux < 1)	return false;		
+
+		if(!is_array($h) )	return false;
+		
+		# Tem de verificar todos os certificados que serao utilizados para criptografar a msg..
+		# Inserir a rotina aqui....
+		
+		$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $m_arquivo_temporario.'<br>';
+
+		if(!grava_arquivo($m_arquivo_temporario,$m))
+		{
+			return false;
+		}
+
+		$enc_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $enc_arquivo_temporario.'<br>';
+		
+		// LIMPA ERROS ... Pode ser um problema para outras aplicacoes que usam openssl(fonte de erros unica).
+		while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
+		$this->erros_ssl = array();
+		$resultado = openssl_pkcs7_encrypt($m_arquivo_temporario,$enc_arquivo_temporario,$c,$h);
+		if(!$resultado)
+		{
+			// Guarda msgs de erro ...
+			while ($erro = openssl_error_string()) 
+			{ 
+				$this->erros_ssl[] = $erro;
+			}
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return false;
+		}
+                # Recupera a msg criptada......		
+		$retorno = file_get_contents($enc_arquivo_temporario);
+		//$aux = explode(chr(0x0A),file_get_contents($enc_arquivo_temporario));
+		//$retorno='';
+		/*
+		$flag = false;
+		for ($i = 0; $i < count($aux); $i++) 
+		{
+			if(!$aux[$i]) 
+			{
+				if(!$flag)
+					{
+						//$retorno .= '-----BEGIN PKCS7-----'.chr(0x0A);
+						$flag = true;
+					}
+			}
+			else
+			{
+				$retorno .= $aux[$i].chr(0x0A);
+			}
+		}
+		//$retorno .= '-----END PKCS7-----'.chr(0x0A);
+		*/
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+		
+		return $retorno;
+	}
+
+#--------------------------------------------------------------------------------------------------------------------------------------------------------
+#--------------------------------------------------------------------------------------------------------------------------------------------------------
+# Verifica uma msg($m) assinada... 
+#--------------------------------------------------------------------------------------------------------------------------------------------------------    
+	public function verificar($m)
+	{
+		if($m == '') return false;
+
+		$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+
+		if(!grava_arquivo($m_arquivo_temporario,$m))
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return false;
+		}
+
+		$vrf_cert_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+	
+		$vrf_msg_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+	
+		// LIMPA ERROS ... Pode ser um problema para outras aplicacoes que usam openssl(fonte de erros unica).
+		while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
+		$this->erros_ssl = array();
+		$resultado = openssl_pkcs7_verify($m_arquivo_temporario,0, $vrf_cert_arquivo_temporario,array($GLOBALS['CAs']),$GLOBALS['CAs'],$vrf_msg_arquivo_temporario);
+                $retorno = true; 
+		if(!$resultado)
+		{
+		        # Indica ocorrencia de erro ... 
+		        $retorno = false;
+			// Guarda msgs de erro ...
+			while ($erro = openssl_error_string()) 
+			{ 
+				$this->erros_ssl[] = $erro;
+			}
+			# Reexecuta o comando com um nivel menor de criticas.
+			$this->cert_assinante = $this->extrai_certificado_da_msg_assinada($m);
+			if(!$this->cert_assinante)
+			{
+				# Se nao foi possivel obter o certificado retorna com falso .....
+				deleta_arquivos_temporarios($this->arquivos_para_deletar);
+				$this->arquivos_para_deletar = array();
+				return false;
+			}
+		}
+		else
+		{
+			# Guarda o certificado usado para assinar a msg
+			$this->cert_assinante  =   file_get_contents($vrf_cert_arquivo_temporario);
+                 }
+		 
+		$this->msg_sem_assinatura =  file_get_contents($vrf_msg_arquivo_temporario);
+
+		$this->certificado($this->cert_assinante);
+
+		if (!$this->apresentado)
+		{
+			$this->erros_ssl[] = 'Certificado da Msg nao pode ser tratado.';
+			$retorno = false;
+		}
+		else
+		{
+			while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
+			# Certificado poderia ter assinado um email?? 
+			if(!openssl_x509_checkpurpose($vrf_cert_arquivo_temporario,X509_PURPOSE_SMIME_SIGN))
+			{
+				$this->erros_ssl[] = 'Certificado nao poderia ter sido utilizado para assinar email.';
+				while ($erro = openssl_error_string()) 
+					{ 
+						$this->erros_ssl[] = $erro;
+					}
+				$retorno = false;
+			}
+			// Isto esta codificado assim antecipando nova versao do parseador....
+			$this->dados['KEYUSAGE']['digitalSignature'] =TRUE;
+			$this->dados['EXTKEYUSAGE']['emailProtection'] = '1.3.6.1.5.5.7.3.4';
+
+			//testa se certificado revogado
+			$revogado = new Verifica_Certificado($this->dados,$this->cert_assinante);
+			$this->dados['REVOGADO'] = false;
+  			if(!$revogado->status){
+   				$this->erros_ssl[] = $revogado->msgerro;
+				foreach ($revogado->erros_ssl as $item)
+					{
+						$this->erros_ssl[] = $item;
+					}
+				if ($revogado->revogado)
+					$this->dados['REVOGADO'] = true;
+   				$retorno  = false;
+   			}
+		}
+
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();	
+		return $retorno;
+	}	
+
+
+	public function extrai_certificado_da_msg_assinada($m)
+	{
+	        $retorno = false;
+		
+	        if(!$m)
+		{
+			return $retorno;
+		}
+
+		$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+
+		if(!grava_arquivo($m_arquivo_temporario,$m))
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return $retorno;
+		}
+		
+		$w='';
+		$saida = array();
+		$w = exec('cat ' . $m_arquivo_temporario . ' | openssl smime -pk7out | openssl pkcs7 -print_certs',$saida);
+		if(!$w=='')
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return $retorno;
+		}
+		
+		$aux1 = '';
+                // gera uma unica string com o conteudo retornado pelo comando...
+		foreach($saida as $linha)
+		{
+			$aux1 .= $linha.chr(0x0A);
+		}
+
+                // cria um array com os certificados retornados..
+		$aux2 = explode('-----BEGIN CERTIFICATE-----',$aux1);
+		array_shift($aux2);
+
+		// isolando certificados..
+		$aux5 = array();
+		foreach($aux2 as $item)
+		{
+			$aux3 = explode('-----END CERTIFICATE-----',$item);
+			$aux4 = '-----BEGIN CERTIFICATE-----' . $aux3[0] . '-----END CERTIFICATE-----';
+			$aux5[] = $aux4;
+		}
+
+
+		// Gera array com as CAs que assinaram os certificados encontrados na msg....
+		$aux5_ACs = array();		
+		foreach($aux5 as $item)
+		{
+			$cert = openssl_x509_parse($item);
+			$aux5_ACs[$cert[issuer][CN]] =  $cert[issuer][CN];
+		}
+
+		// Verifica qual certificado tem no subject um CN que nao he uma CA.
+		foreach($aux5 as $item)
+		{
+			$cert = openssl_x509_parse($item);
+			if(!$aux5_ACs[$cert[subject][CN]])
+				{
+					$retorno = $item;
+					break;
+				}
+		}
+		
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+		
+		return $retorno;
+	}
+}
+
+?>
Index: /trunk/seguranca/classes_BKP/Verifica_Certificado.php
===================================================================
--- /trunk/seguranca/classes_BKP/Verifica_Certificado.php	(revision 1035)
+++ /trunk/seguranca/classes_BKP/Verifica_Certificado.php	(revision 1035)
@@ -0,0 +1,157 @@
+<?php
+require_once('Verifica_Certificado_conf.php');
+require_once('funcoes_auxiliares.php');
+
+class Verifica_Certificado 
+{
+	public $msgerro = '';
+	public $revogado = false;
+	public $status = false;
+	public $certificado = '';
+	public $CRL = '';
+        public $erros_ssl = array();
+	public $arquivos_para_deletar = array();
+	
+	
+	public function __construct($parametro1,$parametro2)
+	{	
+		//include('Verifica_Certificado_conf.php');
+	        # $parametro1 = array com dados do certificado... 
+		# $parametro2 = certificado no formato PEM ...
+		$this->status = false;
+		if(!verificaopenssl())
+		{
+			$this->msgerro = 'MSG005i - Modulo openssl nao disponivel no PHP.';
+			return false;
+		}
+		If(!$parametro2)
+		 {
+			$this->msgerro = 'MSG005 - Certificado nao informado.';
+			return false;		
+		 }
+		$this->certificado = $parametro2; 
+		$aux = explode('/',$parametro1['CRLDISTRIBUTIONPOINTS']);
+		$this->CRL = $aux[count($aux)-1];	
+		
+		if(!$this->cmd_openssl_verify($this->certificado))
+		 {
+			$this->msgerro = 'MSG010- Erro verificando Expiracao/CAs do certificado.';
+			return false;		 
+		 }
+		 
+		if($this->Testa_se_Certificado_Revogado(trim($GLOBALS['CRLs'].$this->CRL),$parametro1['SERIALNUMBER']))
+		 {
+			$this->msgerro = 'MSG011- Ocorreu erro validando o certificado.';
+			return false;		 
+		 }		 
+		
+		$this->status = true;
+	}
+	
+  public function __destruct()
+  {
+		#Remover arquivos temporarios.....	
+		deleta_arquivos_temporarios(&$this->arquivos_para_deletar);
+  }
+  
+   private function cmd_openssl_verify($ZXZ)
+	{
+		$this->erros_ssl = array();
+		
+		if(!is_file($GLOBALS['CAs']))
+		{
+			# Se arquivo com cas nao existe, assume certificado invalido..
+			$this->erros_ssl[]= 'Autoridade certificadora desconhecida.(CA-01)';  //'Arquivo CAs nao localizado.';
+			return false;
+		}
+		
+		$arq = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		if(!$arq)
+		 {
+			#Nao foi possivel gerar path(nome) para arquivo temporario...
+			$this->erros_ssl[]= 'Autoridade certificadora desconhecida.(CA-02)';  //'Arquivo CAs nao localizado.';
+			return false;
+		 }
+		 
+		$ret = grava_arquivo($arq,$this->certificado);
+		
+		$saida = array();
+
+		$w = exec('openssl verify -CAfile '.$GLOBALS['CAs'].' '.$arq,$saida);
+		deleta_arquivos_temporarios(&$this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+		//echo 'w= '.$w.'<br>';
+		//echo '<pre>';
+		//print_r($saida);
+		//echo '</pre>';
+		$aux = explode(' ',$w);	
+		if($aux[1] != 'OK')   // OK no primeiro item do array significa que o comando executaou OK... mas tem erro no certificado...
+		{
+
+			foreach($saida as $item)
+			{
+			        $aux = explode(':',$item);
+				if(isset($aux[1]))
+				{
+					$this->erros_ssl[] = trim($aux[1]);
+				}
+			}			
+			return false;
+		}
+		return true;
+	}
+	
+	private function Testa_se_Certificado_Revogado($pcrl,$serial)
+	{
+		$this->erros_ssl = array();
+		
+		if(!file_exists($pcrl))
+			{
+				# Se arquivo com crls nao existe, assume certificado revogado..
+				$this->erros_ssl[]= 'Nao foi possivel verificar se o certificado esta revogado.(CD-01)';  //'Arquivo CRL nao localizado.';
+				return true;
+			}	
+			
+			if(!is_file($pcrl))
+			{
+				# Se nao for um arquivo, assume certificado revogado..
+				$this->erros_ssl[]= 'Nao foi possivel verificar se o certificado esta revogado.(CD-01)';  //'Arquivo CRL nao localizado.';
+				return true;
+			}
+
+
+		$crl = file_get_contents($pcrl,true);
+		$cert_data = Crl_parseASN($crl);
+
+                # testa se crl expirada....	
+		if(gmdate('YmdHis') >= data_hora($cert_data[1][0][1][4][1]))
+		{
+			# Se crl expirada, assume certificado revogado..
+			$this->erros_ssl[]= 'Nao foi possivel verificar se o certificado esta revogado.(CD-02)';  //'Arquivo CRL expirado.';
+			return true;
+		}
+		
+		if (!is_array($cert_data) || ($cert_data[0] == 'UNKNOWN')) 
+		{
+			# Se o primeiro parametro aponta uma crl invalida retorna como certificado revogado...
+			$this->erros_ssl[]='Nao foi possivel verificar se o certificado esta revogado.(CD-03)'; //Arquivo CRL invalido.
+			return true;
+		}
+
+		foreach($cert_data[1][0][1][5][1] as $item)
+		{
+			if($serial === $item[1][0][1])
+			{
+			#Certificado esta revogado mesmo !!!!! 
+			$this->erros_ssl[]=lang('REVOKED Certificate.');
+			$this->revogado = true;
+			return true;				
+			}
+		}
+
+		return false;
+	}	
+ 
+}	
+
+?>
Index: /trunk/seguranca/classes_BKP/funcoes_auxiliares.php
===================================================================
--- /trunk/seguranca/classes_BKP/funcoes_auxiliares.php	(revision 1035)
+++ /trunk/seguranca/classes_BKP/funcoes_auxiliares.php	(revision 1035)
@@ -0,0 +1,758 @@
+<?php
+//  Conjunto de funcoes de apoio as Classes de tratamento do certificado digital.
+		
+	function data_hora ($valor) 
+	{
+		$year  = substr($valor, 0, 2);
+		$month = substr($valor, 2, 2);
+		$day   = substr($valor, 4, 2);
+		$hour  = substr($valor, 6, 2);
+		$min   = substr($valor, 8, 2);
+		$sec   = substr($valor, 10, 2);
+		return gmdate('YmdHis',gmmktime($hour, $min, $sec, $month, $day, $year));
+	}
+
+	function gera_nome_arquivo_temporario($tab_arqs)
+	{
+		//include('Verifica_Certificado_conf.php');
+		if(!is_dir($GLOBALS['dirtemp']))
+		{
+			#Se nao existe uma area de trabalho aborta a funcao..
+			return false;
+		}
+		$lista = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
+		$N = $lista[rand(0,count($lista)-1)].date('U').$lista[rand(0,count($lista)-1)].RAND(12345,9999999999).$lista[rand(0,count($lista)-1)].$lista[rand(0,count($lista)-1)].RAND(12345,9999999999).'.tmp';
+		$aux = $GLOBALS['dirtemp'].'/'.$N;;
+	        array_push($tab_arqs ,$aux); 
+		return  $aux;		
+	}
+	
+	function grava_arquivo($arquivo,$dados)
+	{
+		$ret = file_put_contents($arquivo,$dados);
+		if(!$ret)
+		{
+			return false;
+		}
+		else
+			return $ret;
+	}
+	
+	
+	function deleta_arquivos_temporarios($tab_arqs)
+	{
+		foreach($tab_arqs as $arquivo ){ unlink($arquivo); }	
+	}
+
+       	function verificaopenssl()
+	{
+		if(extension_loaded('openssl'))
+		{
+			return true;
+		}
+		else
+			return false;
+	}
+   
+        function Crl_parseASN($data)
+	{  
+		$_oids = array(
+			'2.5.4.3' => 'CN',
+			'2.5.4.4' => 'Surname',
+			'2.5.4.6' => 'C',
+			'2.5.4.7' => 'StateOrProvince',
+			'2.5.4.8' => 'Location',
+			'2.5.4.9' => 'StreetAddress',
+			'2.5.4.10' => 'O',
+			'2.5.4.11' => 'OU',
+			'2.5.4.12' => 'Title',
+			'2.5.4.20' => 'TelephoneNumber',
+			'2.5.4.42' => 'GivenName',
+			'2.5.29.14' => 'id-ce-subjectKeyIdentifier',
+			'2.5.29.15' => 'id-ce-keyUsage',
+			'2.5.29.17' => 'id-ce-subjectAltName',
+			'2.5.29.19' => 'id-ce-basicConstraints',
+			'2.5.29.20' => 'id-ce-cRLNumber',
+			'2.5.29.31' => 'id-ce-CRLDistributionPoints',
+			'2.5.29.32' => 'id-ce-certificatePolicies',
+			'2.5.29.35' => 'id-ce-authorityKeyIdentifier',
+			'2.5.29.37' => 'id-ce-extKeyUsage',
+			'1.2.840.113549.1.9.1' => 'Email',
+			'1.2.840.113549.1.1.1' => 'RSAEncryption',
+			'1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
+			'1.2.840.113549.1.1.4' => 'md5withRSAEncryption',
+			'1.2.840.113549.1.1.5' => 'SHA-1WithRSAEncryption',
+			'1.2.840.10040.4.3' => 'id-dsa-with-sha-1',
+			'1.3.6.1.5.5.7.3.2' => 'id_kp_clientAuth',
+			'1.3.6.1.5.5.7.3.4' => 'id_kp_securityemail',	
+			'1.3.6.1.5.5.7.2.1' => 'id_certificatePolicies',
+			'2.16.840.1.113730.1.1' => 'netscape-cert-type',
+			'2.16.840.1.113730.1.2' => 'netscape-base-url',
+			'2.16.840.1.113730.1.3' => 'netscape-revocation-url',
+			'2.16.840.1.113730.1.4' => 'netscape-ca-revocation-url',
+			'2.16.840.1.113730.1.7' => 'netscape-cert-renewal-url',
+			'2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
+			'2.16.840.1.113730.1.12' => 'netscape-ssl-server-name',
+			'2.16.840.1.113730.1.13' => 'netscape-comment',
+			'2.16.76.1.2.1' => 'A1',	
+			'2.16.76.1.2.3' => 'A3',	
+			'2.16.76.1.2.1.16' => 'Certification Practice Statement pointer',
+			'2.16.76.1.3.1' => 'Dados do cert parte 1',
+			'2.16.76.1.3.5' => 'Dados do cert parte 2',
+			'2.16.76.1.3.6' => 'Dados do cert parte 3',	
+				);
+    
+		$result = array();
+		$rxyz = array();
+		
+		while (strlen($data) > 1) 
+		{
+			$class = ord($data[0]);
+			switch ($class) 
+			{
+			case 0x30:
+				// Sequence
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				
+				$sequence_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+
+				$values = Crl_parseASN($sequence_data);
+				if (!is_array($values) || is_string($values[0])) 
+				{
+					$values = array($values);
+				}
+				$sequence_values = array();
+				$i = 0;
+				foreach ($values as $val) 
+				{
+					if ($val[0] == 'extension') 
+					{
+						$sequence_values['extensions'][] = $val;
+					} 
+					else 
+					{
+						$sequence_values[$i++] = $val;
+					}
+				}
+				$result[] = array('sequence', $sequence_values);
+				break;
+
+			case 0x31:
+				// Set of
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$sequence_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				$result[] = array('set', Crl_parseASN($sequence_data));
+				break;
+
+			case 0x01:
+				// Boolean type
+				$boolean_value = (ord($data[2]) == 0xff);
+				$data = substr($data, 3);
+				$result[] = array('boolean', $boolean_value);
+				break;
+			
+			case 0x02:
+				// Integer type
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+
+				$integer_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				if($len == 16)
+				{
+					$result[] = array('integer(' . $len . ')', $integer_data);
+					break;
+				}
+				else
+				{
+								$value = 0;
+				if ($len <= 4) 
+				{
+					// Method works fine for small integers
+					for ($i = 0; $i < strlen($integer_data); $i++) 
+					{
+						$value = ($value << 8) | ord($integer_data[$i]);
+					}
+				} 
+				else 
+				{
+					// Method works for arbitrary length integers 
+					if (extension_loaded('bcmath')) 
+					{
+						for ($i = 0; $i < strlen($integer_data); $i++) 
+						{
+							$value = bcadd(bcmul($value, 256), ord($integer_data[$i]));
+						}
+					} 
+					else 
+					{
+						$value = -1;
+					}
+				}
+				$result[] = array('integer(' . $len . ')', $value);
+				break;
+				}
+			/*
+			case 0x02:
+				// Integer type
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+
+				$integer_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+
+				$value = 0;
+				if ($len <= 4) 
+				{
+					// Method works fine for small integers
+					for ($i = 0; $i < strlen($integer_data); $i++) 
+					{
+						$value = ($value << 8) | ord($integer_data[$i]);
+					}
+				} 
+				else 
+				{
+					// Method works for arbitrary length integers 
+					if (extension_loaded('bcmath')) 
+					{
+						for ($i = 0; $i < strlen($integer_data); $i++) 
+						{
+							$value = bcadd(bcmul($value, 256), ord($integer_data[$i]));
+						}
+					} 
+					else 
+					{
+						$value = -1;
+					}
+				}
+				$result[] = array('integer(' . $len . ')', $value);
+				break;
+		        */  
+			case 0x03:
+				// Bitstring type
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$bitstring_data = substr($data, 3 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				$result[] = array('bit string',$bitstring_data);
+				break;
+
+			case 0x04:
+				// Octetstring type
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$octectstring_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				$result[] = array('octet string', $octectstring_data);
+				break;
+
+			case 0x05:
+				// Null type
+				$data = substr($data, 2);
+				$result[] = array('null', null);
+				break;
+
+			case 0x06:
+				// Object identifier type
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$oid_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+
+				// Unpack the OID
+				$plain  = floor(ord($oid_data[0]) / 40);
+				$plain .= '.' . ord($oid_data[0]) % 40;
+
+				$value = 0;
+				$i = 1;
+				while ($i < strlen($oid_data)) 
+				{
+					$value = $value << 7;
+					$value = $value | (ord($oid_data[$i]) & 0x7f);
+
+					if (!(ord($oid_data[$i]) & 0x80)) 
+					{
+						$plain .= '.' . $value;
+						$value = 0;
+					}
+					$i++;
+				}
+				//echo $plain.' === '.$_oids[$plain].'<br>';
+				if (isset($_oids[$plain])) 
+				{
+					$result[] = array('oid', $_oids[$plain]);
+				} 
+				else 
+				{
+					$result[] = array('oid', $plain);
+				}
+				break;
+
+			case 0x12:
+			case 0x13:
+			case 0x14:
+			case 0x15:
+			case 0x16:
+			case 0x81:
+			case 0x80:
+				// Character string type
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$string_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				$result[] = array('string', $string_data);
+				break;
+
+			case 0x17:
+				// Time types
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$time_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				$result[] = array('utctime', $time_data);
+				break;
+
+			case 0x82:
+				// X509v3 extensions?
+				$len = ord($data[1]);
+				$bytes = 0;
+				if ($len & 0x80) 
+				{
+					$bytes = $len & 0x0f;
+					$len = 0;
+					for ($i = 0; $i < $bytes; $i++) 
+					{
+						$len = ($len << 8) | ord($data[$i + 2]);
+					}
+				}
+				$sequence_data = substr($data, 2 + $bytes, $len);
+				$data = substr($data, 2 + $bytes + $len);
+				$result[] = array('extension', 'X509v3 extensions');
+				$result[] = Crl_parseASN($sequence_data);
+				break;
+
+			case 0xa0:
+			case 0xa3:
+				// Extensions
+				$extension_data = substr($data, 0, 2);
+				$data = substr($data, 2);
+				$result[] = array('extension', dechex($extension_data));
+				break;
+
+			case 0xe6:
+				$extension_data = substr($data, 0, 1);
+				$data = substr($data, 1);
+				$result[] = array('extension', dechex($extension_data));
+				break;
+
+			case 0xa1:
+				$extension_data = substr($data, 0, 1);
+				$data = substr($data, 6);
+				$result[] = array('extension', dechex($extension_data));
+				break;
+
+			default:
+				// Unknown
+				$result[] = array('UNKNOWN', dechex($data));
+				$data = '';
+				break;
+			}
+        }
+
+        return (count($result) > 1) ? $result : array_pop($result);
+
+   }
+   
+   function openssl_to_timestamp ($in) 
+   {
+	$year  = substr($in, 0, 4); /* NOTE: Yes, this returns a two digit year */
+        $month = substr($in, 4, 2);
+        $day   = substr($in, 6, 2);
+        $hour  = substr($in, 8, 2);
+        $min   = substr($in, 10, 2);
+        $sec   = substr($in, 12, 2);
+    
+        return gmmktime($hour, $min, $sec, $month, $day, $year);
+	}
+
+#============================================================================================
+#============================================================================================
+#============================================================================================
+
+# Transforma o certificado do formato PEM para o formato DER ...
+function pem2der($pem_data) 
+	{
+		$begin = "CERTIFICATE-----";
+		$end   = "-----END";
+		$pem_data = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));    
+		$pem_data = substr($pem_data, 0, strpos($pem_data, $end));
+		$der = base64_decode($pem_data);
+		return $der;
+	}
+
+# Recupera dados da oid passada como parametro.....
+function parse($oid,$valor)
+	{
+		$oids = array('1.3.1' => array('1'=>array('NASCIMENTO',8),
+		                                               '2'=>array('CPF',11),
+							       '3'=>array('NIS',11),
+							       '4'=>array('RG',15),
+							       '5'=>array('ORGAOUF',6)),
+				     '1.3.5' => array('1'=>array('TITULO',12),
+				                              '2'=>array('ZONA',3),
+							      '3'=>array('SECAO',4),
+							      '4'=>array('TITULO_CIDADE_UF',0)),
+				     '1.3.6' => array('1'=>array('CADINSS',12))); 
+				     
+		$resultado = array(); 
+		$esta_oid = $oids[$oid];
+		$X = intval(substr($oid,4,1));
+		$p = 0;
+		for($i=1;$i < count($esta_oid) + 1; $i++)
+			{
+				if($esta_oid[$i][1] == 0)
+					{
+						# se igual a zero, então esta apontando um ultimo elemento, iniciando em $p, até o fim dos dados
+						$tamanho = strlen($valor) - $p;
+					}
+				else
+					{
+						$tamanho = $esta_oid[$i][1];
+					} 
+				$resultado[$esta_oid[$i][0]] = substr($valor,$p,$tamanho);
+				$p = $p + $esta_oid[$i][1];
+			}
+		return $resultado;
+	}  
+
+function subjectAltName($cert_data,$KK)
+	{
+	        $dados = array();
+		$AUX = Crl_parseASN( $cert_data[1][0][1][$KK][1][1][1]);
+		$P1 = $AUX[1][1][1];
+		$P2 = $AUX[1][3][1];
+		$P3 = $AUX[1][5][1];
+		$P4 = $AUX[1][6][1];	
+		$dados = array_merge(parse('1.3.1',$P1),
+					parse('1.3.5',$P2),
+					parse('1.3.6',$P3),$dados);
+		$dados['EMAIL'] = $P4;
+		
+		return $dados;
+	}
+	
+function subjectAltName_B($cert_data,$KK)
+	{
+	        $dados = array();
+		$AUX = Crl_parseASN($KK);
+		//echo '<pre>';
+		//print_r($AUX);
+		//echo '</pre>';
+		if(is_array($AUX[0]))
+		{
+			$AUXx = $AUX[0];
+			$AUX = $AUXx;
+		}
+		$P1 = $AUX[1][1][1];
+		$P2 = $AUX[1][3][1];
+		$P3 = $AUX[1][5][1];
+		$P4 = $AUX[1][6][1];	
+		$dados = array_merge(parse('1.3.1',$P1),
+					parse('1.3.5',$P2),
+					parse('1.3.6',$P3),$dados);
+		if($P4 != '1.3.6.1.4.1.311.20.2.3')   // esta oid indica domínio de login em estações de trabalho . Pegar o 2. item como email.
+			{
+				$dados['EMAIL'] = $P4;
+			}
+		else
+			{
+				$dados['EMAIL'] = $AUX[1][8][1];			
+			}
+			
+		return $dados;
+	}
+
+function CRLDistributionPoints($cert_data,$KK)
+	{
+		$dados = array();
+		$AUX = explode('http:',$cert_data[1][0][1][$KK][1][1][1]);
+		if($AUX[1])
+			{
+				$dados['CRLDISTRIBUTIONPOINTS'] = 'http:' . $AUX[1];
+			}
+		else
+			{
+				$dados['CRLDISTRIBUTIONPOINTS'] = '';
+			}
+			
+		return $dados;		
+	}	
+	
+function SERIALNUMBER($cert_data,$KK)
+	{
+		$dados = array();
+		$dados['SERIALNUMBER'] = $cert_data[1][0][1][$KK][1];
+
+		return $dados;			
+	}
+	
+function SUBJECT($cert_data,$KK)
+	{
+		$dados = array();
+		$AUX1 = '/';
+		foreach($cert_data[1][0][1][$KK][1] as $AUX2)
+			{
+				$AUX1 .= $AUX2[1][1][0][1] . '=' . $AUX2[1][1][1][1] . '/';
+			}
+		$dados['SUBJECT'] = substr($AUX1,0,strlen($AUX1)-1);
+		$AUX1 = explode('CN=',$dados['SUBJECT']);
+		$AUX2 = explode('/',$AUX1[1]);
+		$AUX3 = explode(':',$AUX2[0]);
+		$dados['NOME'] = $AUX3[0];
+		return $dados;			
+	}
+		
+function ISSUER($cert_data,$KK)		
+	{
+		$dados = array();	
+		$AUX1 = '/';
+		foreach($cert_data[1][0][1][$KK][1] as $AUX2)
+			{
+				$AUX1 .= $AUX2[1][1][0][1] . '=' . $AUX2[1][1][1][1] . '/';
+			}
+		$AUX1 = explode('CN=',substr($AUX1,0,strlen($AUX1)-1));
+		$AUX2 = explode('/',$AUX1[1]);
+		$dados['EMISSOR'] = $AUX2[0];
+		
+		return $dados;	
+		
+		}		
+
+function BEFOREAFTER($cert_data,$KK)
+	{
+		$dados = array();
+		$dados['INICIO_VALIDADE'] = data_hora($cert_data[1][0][1][$KK][1][0][1]);
+		$dados['FIM_VALIDADE'] = data_hora($cert_data[1][0][1][$KK][1][1][1]);
+		$agora = date('YmdHis');
+		if(($agora < $dados['INICIO_VALIDADE']) || ($agora > $dados['FIM_VALIDADE']))
+			{
+				$dados['EXPIRADO'] = true;
+			}
+		else
+			{
+				$dados['EXPIRADO'] = false;
+			}	
+		return $dados;		
+		}	
+
+function AUTHORITYKEYIDENTIFIER($cert_data,$KK)
+	{
+		$dados = array();
+		$aux1 = Crl_parseASN( $cert_data[1][0][1][$KK][1][1][1]);
+		$aux2='';
+		if (isset($aux1[1][0][1]))
+		{
+			$tab_val = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 
+			for($A=0;$A<strlen($aux1[1][0][1]);$A++)
+				{
+					$aux_parte_numerica =ord(substr($aux1[1][0][1],$A,1)) % 16;
+					$aux_parte_zona = (ord(substr($aux1[1][0][1],$A,1)) - $aux_parte_numerica) / 16;
+					$parte_numerica = $tab_val[$aux_parte_numerica];
+					$parte_zona = $tab_val[$aux_parte_zona];
+					$aux2 .=  $parte_zona.$parte_numerica;
+				}
+			$dados['AUTHORITYKEYIDENTIFIER'] = $aux2;
+		}
+		else
+			{
+				$dados['AUTHORITYKEYIDENTIFIER'] = "auto-assinado";
+			}
+		return $dados;			
+	}
+	
+function AUTHORITYKEYIDENTIFIER_B($cert_data,$KK)
+	{
+		$dados = array();
+		$aux2='';
+		if (isset($KK))
+		{
+			$tab_val = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 
+			for($A=0;$A<strlen($KK);$A++)
+				{
+					$aux_parte_numerica =ord(substr($KK,$A,1)) % 16;
+					$aux_parte_zona = (ord(substr($KK,$A,1)) - $aux_parte_numerica) / 16;
+					$parte_numerica = $tab_val[$aux_parte_numerica];
+					$parte_zona = $tab_val[$aux_parte_zona];
+					$aux2 .=  $parte_zona.$parte_numerica;
+				}
+			$dados['AUTHORITYKEYIDENTIFIER'] = $aux2;
+		}
+		else
+			{
+				$dados['AUTHORITYKEYIDENTIFIER'] = "auto-assinado";
+			}
+		return $dados;			
+	}
+
+function recupera_dados_do_ceritificado_digital($certificado_digital_formato_pem)
+	{
+	        $X509_PARSE = openssl_x509_parse($certificado_digital_formato_pem);
+		$cert_der =  pem2der($certificado_digital_formato_pem);
+		$aux11 = explode(chr(0x30).chr(0x16).chr(0x80).chr(0x14),$cert_der);
+		//echo '<pre>';
+		//print_r( $aux11);
+		//echo '</pre>';
+		$caid = substr($aux11[1],0,20);
+                $aux11 = explode(chr(0x30).chr(0x81),$cert_der);
+		
+		//echo '<pre>';
+		//print_r( Crl_parseASN(chr(0x30).chr(0x81).$aux11[6]));
+		//echo '</pre>';
+		
+		//$oids_icp = $X509_PARSE['extensions']['subjectAltName'];
+		if(count($aux11)<9)
+			{
+				$ky = 6;
+			}
+		else
+			{
+				$ky = 5;
+			}
+		$oids_icp = chr(0x30).chr(0x81).$aux11[$ky];
+		
+		$funcoes = array(1 => SERIALNUMBER,
+			   3 =>  ISSUER,
+			   4 => BEFOREAFTER,
+			   5 => SUBJECT,
+			   $caid => AUTHORITYKEYIDENTIFIER_B,
+			   $oids_icp => subjectAltName_B);
+			   
+		$dados=array();
+		$cert_data = Crl_parseASN( $cert_der);
+		foreach($funcoes as $parametro => $funcao)
+			{
+				$dados= array_merge($dados,$funcao($cert_data,$parametro));
+			}
+
+		if(!$dados['EMAIL'])
+			{
+				$AUX2 = explode('Email=',$dados['SUBJECT']);
+				$dados['EMAIL'] = $AUX2[1];
+			}
+			
+                if($dados['EMAIL'] == '')
+			{
+				$x = ord(substr($aux11[$ky+1],0)); 
+				$dados['EMAIL'] = substr($aux11[$ky+1],1,$x);
+			}
+
+		if(!$dados['CRLDISTRIBUTIONPOINTS'])
+			{
+				$AUX1 =  explode('http:',$X509_PARSE['extensions']['crlDistributionPoints']);
+				$AUX2 = explode('.crl',$AUX1[1]);
+				if($AUX2[0])
+					{
+						$dados['CRLDISTRIBUTIONPOINTS'] = 'http:' . $AUX2[0] . '.crl';
+					}
+				else
+					{
+						$AUX1 = explode('.crl', $cert_der);
+						$AUX2 = explode('http:',$AUX1[0]);
+						$dados['CRLDISTRIBUTIONPOINTS'] = 'http:' .$AUX2[1] . '.crl';
+					}
+			}
+			
+		return $dados;		
+	
+	}
+
+#============================================================================================
+#============================================================================================
+#============================================================================================
+
+?>
Index: /trunk/seguranca/classes/Verifica_Certificado_conf.php
===================================================================
--- /trunk/seguranca/classes/Verifica_Certificado_conf.php	(revision 1035)
+++ /trunk/seguranca/classes/Verifica_Certificado_conf.php	(revision 1035)
@@ -0,0 +1,5 @@
+<?php
+$GLOBALS['dirtemp']  =   '/var/www/expresso/seguranca/temp'; 
+$GLOBALS['CAs']  =         '/var/www/expresso/seguranca/cas/todos.cer';
+$GLOBALS['CRLs']  =       '/var/www/expresso/seguranca/crls/'; 
+?>
Index: /trunk/seguranca/classes/CertificadoB.php
===================================================================
--- /trunk/seguranca/classes/CertificadoB.php	(revision 1035)
+++ /trunk/seguranca/classes/CertificadoB.php	(revision 1035)
@@ -0,0 +1,271 @@
+<?php
+require_once('funcoes_auxiliares.php');
+require_once('Verifica_Certificado_conf.php');
+require_once('Verifica_Certificado.php');
+
+//  Pre-requisito: A extensao openssl deve estar disponivel no PHP ....
+class certificadoB
+{
+  public $dados = array();        # Area para armazenar os dados recuperados do certificado.
+  public $apresentado = false;    # Deve ser testado para verificar se no certificado processado foi localizado o CPF
+  public $erros_ssl = array(); 
+  public $cert_assinante = '';	
+  public $msg_sem_assinatura = '';  #conteï¿œdo da mensagem sem assinatura, que retorna da funï¿œï¿œo verify do openssl
+  public $arquivos_para_deletar = array();
+  
+  public function __construct()
+  {
+    if(!extension_loaded('openssl'))
+    {
+      #PHP sem suporte ao openssl.....
+      return false;
+    }
+    $this->dados = array();
+    $this->dados_xml = '';
+    $this->apresentado = false;
+    $this->erros_ssl = array();
+    $this->cert_assinante = '';
+    $this->msg_sem_assinatura = '';
+    $this->arquivos_para_deletar = array();
+  }
+
+public function __destruct()
+  {
+    #Remover arquivos temporarios.....	
+    deleta_arquivos_temporarios($this->arquivos_para_deletar);
+  }
+
+# Recupera dados de um certificado no formato pem 
+  function certificado($certificado_pem)
+  {		
+      if (!$certificado_pem) 
+    {
+        $this->apresentado = False;
+        return False;    # Sem parametro ...
+    }
+   $this->dados = recupera_dados_do_ceritificado_digital($certificado_pem);
+   $this->dados_xml = gera_xml_com_dados_do_certificado($this->dados);
+     # Certificado foi processado, as informacoes obtidas estao em $this->dados. 
+  $this->apresentado = true;  
+  }
+
+# Encriptar senha ......
+	public function encriptar_senha($s,$c)
+	{
+		if($s == '')	return false;
+		if($c == '')	return false;
+		$senha_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $senha_arquivo_temporario.'<br>';
+		if(!grava_arquivo($senha_arquivo_temporario,$s))
+		{
+			return false;
+		}
+		$cert_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $cert_arquivo_temporario.'<br>';
+		if(!grava_arquivo($cert_arquivo_temporario,$c))
+		{
+			return false;
+		}
+		$senha_criptografada_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $senha_criptografada_arquivo_temporario.'<br>';
+
+		$w = exec('openssl rsautl -in ' . $senha_arquivo_temporario . ' -out ' . $senha_criptografada_arquivo_temporario . ' -inkey ' . $cert_arquivo_temporario . ' -certin -pkcs -keyform PEM -encrypt',$saida);
+		
+		if(!file_exists($senha_criptografada_arquivo_temporario))
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return false;
+		}
+
+                # Recupera a senha criptada, binario.....		
+		$retorno = file_get_contents($senha_criptografada_arquivo_temporario);
+
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+
+		if(strlen($retorno) != 128) return false;
+
+		return base64_encode($retorno);
+	}
+
+
+# Encriptar uma msg($m) para o(s) destinatario(s) $c(array com certificados)com os headers passados em $h.
+	public function encriptar($m,$c,$h)
+	{
+		if($m == '')	return false;
+		if(!is_array($c))	return false;
+		$aux = count($c);
+		if($aux < 1)	return false;		
+		if(!is_array($h) )	return false;
+		# Tem de verificar todos os certificados que serao utilizados para criptografar a msg..
+		# Inserir a rotina aqui....
+		$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $m_arquivo_temporario.'<br>';
+		if(!grava_arquivo($m_arquivo_temporario,$m))
+		{
+			return false;
+		}
+		$enc_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		//echo $enc_arquivo_temporario.'<br>';
+		
+		// LIMPA ERROS ... Pode ser um problema para outras aplicacoes que usam openssl(fonte de erros unica).
+		while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
+		$this->erros_ssl = array();
+		$resultado = openssl_pkcs7_encrypt($m_arquivo_temporario,$enc_arquivo_temporario,$c,$h,$flags=0,$cipherid=OPENSSL_CIPHER_DES);
+		//$resultado = openssl_pkcs7_encrypt($m_arquivo_temporario,$enc_arquivo_temporario,$c,$h);
+		if(!$resultado)
+		{
+			// Guarda msgs de erro ...
+			while ($erro = openssl_error_string()) 
+			{ 
+				$this->erros_ssl[] = $erro;
+			}
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return false;
+		}
+                # Recupera a msg criptada......		
+		$retorno = file_get_contents($enc_arquivo_temporario);
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+		return $retorno;
+	}
+
+
+# Verifica uma msg($m) assinada... 
+	public function verificar($m)
+	{
+		if($m == '') return false;
+		$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		if(!grava_arquivo($m_arquivo_temporario,$m))
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return false;
+		}
+		$vrf_cert_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		$vrf_msg_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		// LIMPA ERROS ... Pode ser um problema para outras aplicacoes que usam openssl(fonte de erros unica).
+		while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
+		$this->erros_ssl = array();
+		$resultado = openssl_pkcs7_verify($m_arquivo_temporario,0, $vrf_cert_arquivo_temporario,array($GLOBALS['CAs']),$GLOBALS['CAs'],$vrf_msg_arquivo_temporario); 
+	        $retorno = true; 
+		if($resultado === false || $resultado == -1)
+		{
+		        # Indica ocorrencia de erro ... 
+		        $retorno = false;
+			// Guarda msgs de erro ...
+			while ($erro = openssl_error_string()) 
+			{ 
+				$this->erros_ssl[] = $erro;
+			}
+			# Reexecuta o comando com um nivel menor de criticas.
+			$this->cert_assinante = $this->extrai_certificado_da_msg_assinada($m);
+			if(!$this->cert_assinante)
+			{
+				# Se nao foi possivel obter o certificado retorna com falso .....
+				deleta_arquivos_temporarios($this->arquivos_para_deletar);
+				$this->arquivos_para_deletar = array();
+				return false;
+			}
+		}
+		else
+		{
+			# Guarda o certificado usado para assinar a msg
+			$this->cert_assinante  =   file_get_contents($vrf_cert_arquivo_temporario);
+                 }
+		If(file_exists($vrf_msg_arquivo_temporario))  $this->msg_sem_assinatura =  file_get_contents($vrf_msg_arquivo_temporario);
+		$this->certificado($this->cert_assinante);
+		if (!$this->apresentado)
+		{
+			$this->erros_ssl[] = 'Certificado da Msg nao pode ser tratado.';
+			$retorno = false;
+		}
+		else
+		{
+			while ($erro = openssl_error_string()); //  Limpa buffer de erros anteriores......
+			# Certificado poderia ter assinado um email?? 
+			if(!($this->dados['KEYUSAGE']['digitalSignature'] && $this->dados['EXTKEYUSAGE']['emailProtection']))
+			{
+				$this->erros_ssl[] = 'Certificado nao poderia ter sido utilizado para assinar email.';
+				while ($erro = openssl_error_string()) 
+					{ 
+						$this->erros_ssl[] = $erro;
+					}
+				$retorno = false;
+			}
+			$revogado = new Verifica_Certificado($this->dados,$this->cert_assinante);
+			$this->dados['REVOGADO'] = false;
+  			if(!$revogado->status){
+   				$this->erros_ssl[] = $revogado->msgerro;
+				foreach ($revogado->erros_ssl as $item)
+					{
+						$this->erros_ssl[] = $item;
+					}
+				if ($revogado->revogado)
+					$this->dados['REVOGADO'] = true;
+   				$retorno  = false;
+   			}
+		}
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();	
+		return $retorno;
+	}	
+
+	public function extrai_certificado_da_msg_assinada($m)
+	{
+	        $retorno = false;
+	        if(!$m)
+		{
+			return $retorno;
+		}
+		$m_arquivo_temporario = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		if(!grava_arquivo($m_arquivo_temporario,$m))
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return $retorno;
+		}
+		$w='';
+		$saida = array();
+		$w = exec('cat ' . $m_arquivo_temporario . ' | openssl smime -pk7out | openssl pkcs7 -print_certs',$saida);
+		if(!$w=='')
+		{
+			deleta_arquivos_temporarios($this->arquivos_para_deletar);
+			$this->arquivos_para_deletar = array();
+			return $retorno;
+		}
+		$aux1 = '';
+                // gera uma unica string com o conteudo retornado pelo comando...
+		foreach($saida as $linha)
+		{
+			$aux1 .= $linha.chr(0x0A);
+		}
+                // cria um array com os certificados retornados..
+		$aux2 = explode('-----BEGIN CERTIFICATE-----',$aux1);
+		array_shift($aux2);
+		// isolando certificados..
+		$aux5 = array();
+		foreach($aux2 as $item)
+		{
+			$aux3 = explode('-----END CERTIFICATE-----',$item);
+			$aux4 = '-----BEGIN CERTIFICATE-----' . $aux3[0] . '-----END CERTIFICATE-----';
+			$aux5[] = $aux4;
+		}
+		// Testa qual dos certificados nao he uma CA ....
+		foreach($aux5 as $item)
+		{
+			$Dados_cert = recupera_dados_do_ceritificado_digital($item);
+			if(!$Dados_cert['CA'])
+				{
+					$retorno = $item;
+					break;
+				}		
+		}
+		deleta_arquivos_temporarios($this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+		return $retorno;
+	}
+}
+?>
Index: /trunk/seguranca/classes/Verifica_Certificado.php
===================================================================
--- /trunk/seguranca/classes/Verifica_Certificado.php	(revision 1035)
+++ /trunk/seguranca/classes/Verifica_Certificado.php	(revision 1035)
@@ -0,0 +1,138 @@
+<?php
+require_once('Verifica_Certificado_conf.php');
+require_once('funcoes_auxiliares.php');
+
+class Verifica_Certificado 
+{
+	public $msgerro = '';
+	public $revogado = false;
+	public $status = false;
+	public $certificado = '';
+	public $CRL = '';
+        public $erros_ssl = array();
+	public $arquivos_para_deletar = array();
+	
+	public function __construct($parametro1,$parametro2)
+	{	
+		//include('Verifica_Certificado_conf.php');
+	        # $parametro1 = array com dados do certificado... 
+		# $parametro2 = certificado no formato PEM ...
+		$this->status = false;
+		if(!verificaopenssl())
+		{
+			$this->msgerro = 'MSG005i - Modulo openssl nao disponivel no PHP.';
+			return false;
+		}
+		If(!$parametro2)
+		 {
+			$this->msgerro = 'MSG005 - Certificado nao informado.';
+			return false;		
+		 }
+		$this->certificado = $parametro2; 
+		//Pode existir mais de um local para obter a CRL. Vai tabalhar com o primeiro ....
+		$aux = explode('/',$parametro1['CRLDISTRIBUTIONPOINTS'][0]);
+		$this->CRL = $aux[count($aux)-1];	
+		if(!$this->cmd_openssl_verify($this->certificado))
+		 {
+			$this->msgerro = 'MSG010 - Erro verificando Expiracao/CAs do certificado.';
+			return false;		 
+		 }
+		if($this->Testa_se_Certificado_Revogado(trim($GLOBALS['CRLs'].$this->CRL),$parametro1['SERIALNUMBER']))
+		 {
+			$this->msgerro = 'MSG011 - Ocorreu erro validando o certificado.';
+			return false;		 
+		 }		 
+		$this->status = true;
+	}
+	
+  public function __destruct()
+  {
+		#Remover arquivos temporarios.....	
+		deleta_arquivos_temporarios(&$this->arquivos_para_deletar);
+  }
+  
+   private function cmd_openssl_verify($ZXZ)
+	{
+		$this->erros_ssl = array();
+		if(!is_file($GLOBALS['CAs']))
+		{
+			# Se arquivo com cas nao existe, assume certificado invalido..
+			$this->erros_ssl[]= 'Autoridade certificadora desconhecida.(CA-01)';  //'Arquivo CAs nï¿œo localizado.';
+			return false;
+		}
+		$arq = gera_nome_arquivo_temporario(&$this->arquivos_para_deletar);
+		if(!$arq)
+		 {
+			#Nao foi possivel gerar path(nome) para arquivo temporario...
+			$this->erros_ssl[]= 'Autoridade certificadora desconhecida.(CA-02)';  //'Arquivo CAs nï¿œo localizado.';
+			return false;
+		 }
+		$ret = grava_arquivo($arq,$this->certificado);
+		$saida = array();
+		$w = exec('openssl verify -CAfile '.$GLOBALS['CAs'].' '.$arq,$saida);
+		deleta_arquivos_temporarios(&$this->arquivos_para_deletar);
+		$this->arquivos_para_deletar = array();
+		//echo 'w= '.$w.'<br>';
+		//echo '<pre>';
+		//print_r($saida);
+		//echo '</pre>';
+		$aux = explode(' ',$w);	
+		if($aux[1] != 'OK')   // OK no primeiro item do array significa que o comando executaou OK... mas tem erro no certificado...
+		{
+			foreach($saida as $item)
+			{
+			        $aux = explode(':',$item);
+				if(isset($aux[1]))
+				{
+					$this->erros_ssl[] = trim($aux[1]);
+				}
+			}			
+			return false;
+		}
+		return true;
+	}
+	
+	private function Testa_se_Certificado_Revogado($pcrl,$serial)
+	{
+		$this->erros_ssl = array();
+		if(!file_exists($pcrl))
+			{
+				# Se arquivo com crls nao existe, assume certificado revogado..
+				$this->erros_ssl[]= 'Couldn\'t verify if certificate was revoked.(CD-01)';  //'Arquivo CRL nao localizado.';
+				return true;
+			}	
+			if(!is_file($pcrl))
+			{
+				# Se nao for um arquivo, assume certificado revogado..
+				$this->erros_ssl[]= 'Couldn\'t verify if certificate was revoked.(CD-01)';  //'Arquivo CRL nao localizado.';
+				return true;
+			}
+		$crl = file_get_contents($pcrl,true);
+		$cert_data = Crl_parseASN($crl);
+                # testa se crl expirada....	
+		if(gmdate('YmdHis') >= data_hora($cert_data[1][0][1][4][1]))
+		{
+			# Se crl expirada, assume certificado revogado..
+			$this->erros_ssl[]= 'Couldn\'t verify if certificate was revoked.(CD-02)';  //'Arquivo CRL expirado.';
+			return true;
+		}
+		if (!is_array($cert_data) || ($cert_data[0] == 'UNKNOWN')) 
+		{
+			# Se o primeiro parametro aponta uma crl invalida retorna como certificado revogado...
+			$this->erros_ssl[]='Couldn\'t verify if certificate was revoked.(CD-03)'; //Arquivo CRL invalido.
+			return true;
+		}
+		foreach($cert_data[1][0][1][5][1] as $item)
+		{
+			if($serial === $item[1][0][1])
+			{
+			#Certificado esta revogado mesmo !!!!! 
+			$this->erros_ssl[]='REVOKED Certificate.';
+			$this->revogado = true;
+			return true;				
+			}
+		}
+		return false;
+	}	
+ }	
+?>
Index: /trunk/seguranca/classes/funcoes_auxiliares.php
===================================================================
--- /trunk/seguranca/classes/funcoes_auxiliares.php	(revision 1035)
+++ /trunk/seguranca/classes/funcoes_auxiliares.php	(revision 1035)
@@ -0,0 +1,1755 @@
+<?php
+//  Conjunto de funcoes de apoio as Classes de tratamento do certificado digital.
+	
+		function pega_path($chaves,$linha)
+		{
+			if(!is_array($chaves) || !$linha)
+				{
+					return false;
+				}
+			$ret = false;
+			foreach($chaves as $chave)
+				{
+					if(substr($linha,0,strlen($chave)) == $chave)
+						{
+							$c = '';
+							if(strpos($linha,'\'') > 0)
+								{
+									$c = "'";
+								}
+							if(strpos($linha,'"') > 0)
+								{
+									$c = '"';
+								}
+							if(!$c)
+								{
+									break;
+								}
+							$data = explode($c,$linha);
+							$ret = $data[1];
+							break;
+						}
+				}
+			return $ret;
+		}
+	
+	function ler_certificados_CAS($path)
+		{
+			// Ler o arquivo contendo certificados das Cas.
+			// Retorna array com os certificados formato PEM ...
+			$retorno = array();		
+			if(file_exists($path))
+				{
+					$dados_do_arquivo = file_get_contents($path); 
+					$inicio = '-----BEGIN CERTIFICATE-----';
+					$fim = '-----END CERTIFICATE-----';
+					$aux1 = explode($inicio,$dados_do_arquivo);
+					foreach($aux1 as $aux2)
+						{
+							if($aux2)
+								{
+									$aux3 = explode($fim,$aux2);
+									$retorno[] =$inicio . $aux3[0] . $fim;
+								}
+						}
+				}
+			return $retorno;
+		}
+	
+	function gera_xml_com_dados_do_certificado($dados)
+		{
+		        // Recebe array com dados de um certificado e gera o xml com estes dados. 
+			// As chaves formam os tags e os dados  o conteudo do tag ....
+			$aux_xml = "<certificado>";
+			if(is_array($dados))
+				{
+					foreach($dados as $K => $valor)
+						{
+							if(!is_array($valor))
+								{
+									$aux_xml .= '  <' . $K . '>'.$valor.'</' . $K . '>'; 
+								}
+							else
+								{
+									$aux_xml .= '  <' . $K . '>';
+									foreach($valor as $KX => $valorx)
+										{
+											if(is_int($KX))  $KX = 'D' . $KX;
+											$aux_xml .= '  <' . $KX . '>'.$valorx.'</' . $KX . '>';
+										}
+									$aux_xml .= '  </' . $K . '>';
+								}
+						}
+				}
+			$aux_xml .= "</certificado>";
+			return  $aux_xml;
+		}
+		
+		
+	function data_hora ($valor) 
+	{
+		$year  = substr($valor, 0, 2);
+		$month = substr($valor, 2, 2);
+		$day   = substr($valor, 4, 2);
+		$hour  = substr($valor, 6, 2);
+		$min   = substr($valor, 8, 2);
+		$sec   = substr($valor, 10, 2);
+		return gmdate('YmdHis',gmmktime($hour, $min, $sec, $month, $day, $year));
+	}
+
+
+	function gera_nome_arquivo_temporario($tab_arqs)
+	{
+		//include('Verifica_Certificado_conf.php');
+		if(!is_dir($GLOBALS['dirtemp']))
+		{
+			#Se nao existe uma area de trabalho aborta a funcao..
+			return false;
+		}
+		$lista = array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z');
+		$N = $lista[rand(0,count($lista)-1)].date('U').$lista[rand(0,count($lista)-1)].RAND(12345,9999999999).$lista[rand(0,count($lista)-1)].$lista[rand(0,count($lista)-1)].RAND(12345,9999999999).'.tmp';
+		$aux = $GLOBALS['dirtemp'].'/'.$N;;
+	        array_push($tab_arqs ,$aux); 
+		return  $aux;		
+	}
+
+
+	function grava_arquivo($arquivo,$dados)
+	{
+		$ret = file_put_contents($arquivo,$dados);
+		if(!$ret)
+		{
+			return false;
+		}
+		else
+			return $ret;
+	}
+	
+	
+	function deleta_arquivos_temporarios($tab_arqs)
+	{
+		foreach($tab_arqs as $arquivo )
+			{ 
+				if(file_exists($arquivo))
+					{
+						unlink($arquivo);
+					}
+			}	
+	}
+
+
+       	function verificaopenssl()
+	{
+		if(extension_loaded('openssl'))
+		{
+			return true;
+		}
+		else
+			return false;
+	}
+
+
+       	function print_hex($value)
+	{
+		$tab_val = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); 
+		for($A=0;$A<strlen($value);$A++)
+			{
+				$aux_parte_numerica =ord(substr($value,$A,1)) % 16;
+				$aux_parte_zona = (ord(substr($value,$A,1)) - $aux_parte_numerica) / 16;
+				$parte_numerica = $tab_val[$aux_parte_numerica];
+				$parte_zona = $tab_val[$aux_parte_zona];
+				$hex .=  $parte_zona.$parte_numerica;
+			}
+			return $hex;
+	}
+
+
+	function get_length($len,$bytes,$data)
+	{
+		$len = ord($data[1]);
+		$bytes = 0;
+		# Testa se tamanho menor/igual a 127 bytes..
+		# Neste caso $len  ja he o tamanho do conteudo
+		if ($len & 0x80) 
+			{
+				# Testa se tamanho indefinido (nao deve ocorrer em uma codificação DER.
+				if($len == chr(0x80))
+					{
+						# Tamanho indefinido, limitado por 0x0000h
+						$len = strpos($data,chr(0x00).chr(0x00));
+						$bytes = 0;
+					}
+				else					
+					{
+						# he tamanho definido. diz quantos bytes formam o tamanho.... 
+						$bytes = $len & 0x0f;
+						$len = 0;
+						for ($i = 0; $i < $bytes; $i++) 
+							{
+								$len = ($len << 8) | ord($data[$i + 2]);
+							}
+					}
+			}
+	}
+	
+	function xBase128($ab,$q,$flag )
+	{
+		$abc = $ab; 
+		if( $q > 127 )
+			{
+				$abc = xBase128($abc, floor($q / 128), 0 );
+			}
+		$q = $q % 128;
+		if( $flag)
+			{
+				$abc[] = $q;
+			}
+		else
+			{
+				$abc[] = 0x80 | $q;
+			}
+		return $abc;
+	}
+
+
+
+	function OIDtoHex($oid)
+	{
+		$abBinary = array();
+		$partes = explode('.',$oid);
+		$n = 0;
+		$b = 0;
+		for($n = 0; $n < count($partes); $n++)
+		{
+			if($n==0)
+				{
+					$b = 40 * $partes[$n];
+				}
+			elseif($n==1)
+				{
+					$b +=  $partes[$n];
+					$abBinary[] = $b;
+				}
+			else
+				{
+					$abBinary = xBase128($abBinary, $partes[$n], 1 );
+				}
+		}
+		$value =chr(0x06) . chr(count($abBinary));
+		foreach($abBinary as $item)
+		{
+			$value .= chr($item);
+		}
+		return $value;
+	}
+	
+	
+	
+        function Crl_parseASN($data,$context_especific = false)
+	{  
+        // Tabela de OIDs .
+               	$_oids = array(
+			'2.5.4.3' => 'CN',
+			'2.5.4.4' => 'Surname',
+			'2.5.4.6' => 'C',
+			'2.5.4.7' => 'Cidade',
+			'2.5.4.8' => 'Estatdo',
+			'2.5.4.9' => 'StreetAddress',
+			'2.5.4.10' => 'O',
+			'2.5.4.11' => 'OU',
+			'2.5.4.12' => 'Title',
+			'2.5.4.20' => 'TelephoneNumber',
+			'2.5.4.42' => 'GivenName',
+			'2.5.29.14' => 'id-ce-subjectKeyIdentifier',
+			'2.5.29.15' => 'id-ce-keyUsage',
+			'2.5.29.17' => 'id-ce-subjectAltName',
+			'2.5.29.19' => 'id-ce-basicConstraints',
+			'2.5.29.20' => 'id-ce-cRLNumber',
+			'2.5.29.31' => 'id-ce-CRLDistributionPoints',
+			'2.5.29.32' => 'id-ce-certificatePolicies',
+			'2.5.29.35' => 'id-ce-authorityKeyIdentifier',
+			'2.5.29.37' => 'id-ce-extKeyUsage',
+			'1.2.840.113549.1.9.1' => 'Email',
+			'1.2.840.113549.1.1.1' => 'RSAEncryption',
+			'1.2.840.113549.1.1.2' => 'md2WithRSAEncryption',
+			'1.2.840.113549.1.1.4' => 'md5withRSAEncryption',
+			'1.2.840.113549.1.1.5' => 'SHA-1WithRSAEncryption',
+			'1.2.840.10040.4.3' => 'id-dsa-with-sha-1',
+			'1.3.6.1.5.5.7.3.2' => 'id_kp_clientAuth',
+			'1.3.6.1.5.5.7.3.4' => 'id_kp_securityemail',	
+			'1.3.6.1.5.5.7.2.1' => 'id_certificatePolicies',
+			'2.16.840.1.113730.1.1' => 'netscape-cert-type',
+			'2.16.840.1.113730.1.2' => 'netscape-base-url',
+			'2.16.840.1.113730.1.3' => 'netscape-revocation-url',
+			'2.16.840.1.113730.1.4' => 'netscape-ca-revocation-url',
+			'2.16.840.1.113730.1.7' => 'netscape-cert-renewal-url',
+			'2.16.840.1.113730.1.8' => 'netscape-ca-policy-url',
+			'2.16.840.1.113730.1.12' => 'netscape-ssl-server-name',
+			'2.16.840.1.113730.1.13' => 'netscape-comment',
+			'2.16.76.1.2.1' => 'A1',	
+			'2.16.76.1.2.3' => 'A3',	
+			'2.16.76.1.2.1.16' => 'Certification Practice Statement pointer',
+			'2.16.76.1.3.1' => 'Dados do cert parte 1',
+			'2.16.76.1.3.5' => 'Dados do cert parte 2',
+			'2.16.76.1.3.6' => 'Dados do cert parte 3',
+			'0.9.2342.19200300.100.1.25' => ' domainComponent',
+			'1.2.36.68980861.1.1.10' => ' Signet pilot',
+			'1.2.36.68980861.1.1.11' => ' Signet intraNet',
+			'1.2.36.68980861.1.1.2' => ' Signet personal',
+			'1.2.36.68980861.1.1.20' => ' Signet securityPolicy',
+			'1.2.36.68980861.1.1.3' => ' Signet business',
+			'1.2.36.68980861.1.1.4' => ' Signet legal',
+			'1.2.36.75878867.1.100.1.1' => ' Certificates Australia policyIdentifier',
+			'1.2.752.34.1' => ' seis-cp',
+			'1.2.752.34.1.1' => ' SEIS certificatePolicy-s10',
+			'1.2.752.34.2' => ' SEIS pe',
+			'1.2.752.34.3' => ' SEIS at',
+			'1.2.752.34.3.1' => ' SEIS at-personalIdentifier',
+			'1.2.840.10040.2.1' => ' holdinstruction-none',
+			'1.2.840.10040.2.2' => ' holdinstruction-callissuer',
+			'1.2.840.10040.2.3' => ' holdinstruction-reject',
+			'1.2.840.10040.4.1' => ' dsa',
+			'1.2.840.10040.4.3' => ' dsaWithSha1',
+			'1.2.840.10045.1' => ' fieldType',
+			'1.2.840.10045.1.1' => ' prime-field',
+			'1.2.840.10045.1.2' => ' characteristic-two-field',
+			'1.2.840.10045.1.2.1' => ' ecPublicKey',
+			'1.2.840.10045.1.2.3' => ' characteristic-two-basis',
+			'1.2.840.10045.1.2.3.1' => ' onBasis',
+			'1.2.840.10045.1.2.3.2' => ' tpBasis',
+			'1.2.840.10045.1.2.3.3' => ' ppBasis',
+			'1.2.840.10045.2' => ' publicKeyType',
+			'1.2.840.10045.2.1' => ' ecPublicKey',
+			'1.2.840.10046.2.1' => ' dhPublicNumber',
+			'1.2.840.113533.7' => ' nsn',
+			'1.2.840.113533.7.65' => ' nsn-ce',
+			'1.2.840.113533.7.65.0' => ' entrustVersInfo',
+			'1.2.840.113533.7.66' => ' nsn-alg',
+			'1.2.840.113533.7.66.10' => ' cast5CBC',
+			'1.2.840.113533.7.66.11' => ' cast5MAC',
+			'1.2.840.113533.7.66.12' => ' pbeWithMD5AndCAST5-CBC',
+			'1.2.840.113533.7.66.13' => ' passwordBasedMac',
+			'1.2.840.113533.7.66.3' => ' cast3CBC',
+			'1.2.840.113533.7.67' => ' nsn-oc',
+			'1.2.840.113533.7.67.0' => ' entrustUser',
+			'1.2.840.113533.7.68' => ' nsn-at',
+			'1.2.840.113533.7.68.0' => ' entrustCAInfo',
+			'1.2.840.113533.7.68.10' => ' attributeCertificate',
+			'1.2.840.113549.1.1' => ' pkcs-1',
+			'1.2.840.113549.1.1.1' => ' rsaEncryption',
+			'1.2.840.113549.1.1.2' => ' md2withRSAEncryption',
+			'1.2.840.113549.1.1.3' => ' md4withRSAEncryption',
+			'1.2.840.113549.1.1.4' => ' md5withRSAEncryption',
+			'1.2.840.113549.1.1.5' => ' sha1withRSAEncryption',
+			'1.2.840.113549.1.1.6' => ' rsaOAEPEncryptionSET',
+			'1.2.840.113549.1.9.16.2.11' => 'SMIMEEncryptionKeyPreference',
+			'1.2.840.113549.1.12' => ' pkcs-12',
+			'1.2.840.113549.1.12.1' => ' pkcs-12-PbeIds',
+			'1.2.840.113549.1.12.1.1' => ' pbeWithSHAAnd128BitRC4',
+			'1.2.840.113549.1.12.1.2' => ' pbeWithSHAAnd40BitRC4',
+			'1.2.840.113549.1.12.1.3' => ' pbeWithSHAAnd3-KeyTripleDES-CBC',
+			'1.2.840.113549.1.12.1.4' => ' pbeWithSHAAnd2-KeyTripleDES-CBC',
+			'1.2.840.113549.1.12.1.5' => ' pbeWithSHAAnd128BitRC2-CBC',
+			'1.2.840.113549.1.12.1.6' => ' pbeWithSHAAnd40BitRC2-CBC',
+			'1.2.840.113549.1.12.10' => ' pkcs-12Version1',
+			'1.2.840.113549.1.12.10.1' => ' pkcs-12BadIds',
+			'1.2.840.113549.1.12.10.1.1' => ' pkcs-12-keyBag',
+			'1.2.840.113549.1.12.10.1.2' => ' pkcs-12-pkcs-8ShroudedKeyBag',
+			'1.2.840.113549.1.12.10.1.3' => ' pkcs-12-certBag',
+			'1.2.840.113549.1.12.10.1.4' => ' pkcs-12-crlBag',
+			'1.2.840.113549.1.12.10.1.5' => ' pkcs-12-secretBag',
+			'1.2.840.113549.1.12.10.1.6' => ' pkcs-12-safeContentsBag',
+			'1.2.840.113549.1.12.2' => ' pkcs-12-ESPVKID',
+			'1.2.840.113549.1.12.2.1' => ' pkcs-12-PKCS8KeyShrouding',
+			'1.2.840.113549.1.12.3' => ' pkcs-12-BagIds',
+			'1.2.840.113549.1.12.3.1' => ' pkcs-12-keyBagId',
+			'1.2.840.113549.1.12.3.2' => ' pkcs-12-certAndCRLBagId',
+			'1.2.840.113549.1.12.3.3' => ' pkcs-12-secretBagId',
+			'1.2.840.113549.1.12.3.4' => ' pkcs-12-safeContentsId',
+			'1.2.840.113549.1.12.3.5' => ' pkcs-12-pkcs-8ShroudedKeyBagId',
+			'1.2.840.113549.1.12.4' => ' pkcs-12-CertBagID',
+			'1.2.840.113549.1.12.4.1' => ' pkcs-12-X509CertCRLBagID',
+			'1.2.840.113549.1.12.4.2' => ' pkcs-12-SDSICertBagID',
+			'1.2.840.113549.1.12.5' => ' pkcs-12-OID',
+			'1.2.840.113549.1.12.5.1' => ' pkcs-12-PBEID',
+			'1.2.840.113549.1.12.5.1.1' => ' pkcs-12-PBEWithSha1And128BitRC4',
+			'1.2.840.113549.1.12.5.1.2' => ' pkcs-12-PBEWithSha1And40BitRC4',
+			'1.2.840.113549.1.12.5.1.3' => ' pkcs-12-PBEWithSha1AndTripleDESCBC',
+			'1.2.840.113549.1.12.5.1.4' => ' pkcs-12-PBEWithSha1And128BitRC2CBC',
+			'1.2.840.113549.1.12.5.1.5' => ' pkcs-12-PBEWithSha1And40BitRC2CBC',
+			'1.2.840.113549.1.12.5.1.6' => ' pkcs-12-PBEWithSha1AndRC4',
+			'1.2.840.113549.1.12.5.1.7' => ' pkcs-12-PBEWithSha1AndRC2CBC',
+			'1.2.840.113549.1.12.5.2' => ' pkcs-12-EnvelopingID',
+			'1.2.840.113549.1.12.5.2.1' => ' pkcs-12-RSAEncryptionWith128BitRC4',
+			'1.2.840.113549.1.12.5.2.2' => ' pkcs-12-RSAEncryptionWith40BitRC4',
+			'1.2.840.113549.1.12.5.2.3' => ' pkcs-12-RSAEncryptionWithTripleDES',
+			'1.2.840.113549.1.12.5.3' => ' pkcs-12-SignatureID',
+			'1.2.840.113549.1.12.5.3.1' => ' pkcs-12-RSASignatureWithSHA1Digest',
+			'1.2.840.113549.1.3' => ' pkcs-3',
+			'1.2.840.113549.1.3.1' => ' dhKeyAgreement',
+			'1.2.840.113549.1.5' => ' pkcs-5',
+			'1.2.840.113549.1.5.1' => ' pbeWithMD2AndDES-CBC',
+			'1.2.840.113549.1.5.10' => ' pbeWithSHAAndDES-CBC',
+			'1.2.840.113549.1.5.3' => ' pbeWithMD5AndDES-CBC',
+			'1.2.840.113549.1.5.4' => ' pbeWithMD2AndRC2-CBC',
+			'1.2.840.113549.1.5.6' => ' pbeWithMD5AndRC2-CBC',
+			'1.2.840.113549.1.5.9' => ' pbeWithMD5AndXOR',
+			'1.2.840.113549.1.7' => ' pkcs-7',
+			'1.2.840.113549.1.7.1' => ' data',
+			'1.2.840.113549.1.7.2' => ' signedData',
+			'1.2.840.113549.1.7.3' => ' envelopedData',
+			'1.2.840.113549.1.7.4' => ' signedAndEnvelopedData',
+			'1.2.840.113549.1.7.5' => ' digestData',
+			'1.2.840.113549.1.7.6' => ' encryptedData',
+			'1.2.840.113549.1.7.7' => ' dataWithAttributes',
+			'1.2.840.113549.1.7.8' => ' encryptedPrivateKeyInfo',
+			'1.2.840.113549.1.9' => ' pkcs-9',
+			'1.2.840.113549.1.9.1' => ' emailAddress',
+			'1.2.840.113549.1.9.10' => ' issuerAndSerialNumber',
+			'1.2.840.113549.1.9.11' => ' passwordCheck',
+			'1.2.840.113549.1.9.12' => ' publicKey',
+			'1.2.840.113549.1.9.13' => ' signingDescription',
+			'1.2.840.113549.1.9.14' => ' extensionReq',
+			'1.2.840.113549.1.9.15' => ' sMIMECapabilities',
+			'1.2.840.113549.1.9.15.1' => ' preferSignedData',
+			'1.2.840.113549.1.9.15.2' => ' canNotDecryptAny',
+			'1.2.840.113549.1.9.15.3' => ' receiptRequest',
+			'1.2.840.113549.1.9.15.4' => ' receipt',
+			'1.2.840.113549.1.9.15.5' => ' contentHints',
+			'1.2.840.113549.1.9.15.6' => ' mlExpansionHistory',
+			'1.2.840.113549.1.9.16' => ' id-sMIME',
+			'1.2.840.113549.1.9.16.0' => ' id-mod',
+			'1.2.840.113549.1.9.16.0.1' => ' id-mod-cms',
+			'1.2.840.113549.1.9.16.0.2' => ' id-mod-ess',
+			'1.2.840.113549.1.9.16.1' => ' id-ct',
+			'1.2.840.113549.1.9.16.1.1' => ' id-ct-receipt',
+			'1.2.840.113549.1.9.16.2' => ' id-aa',
+			'1.2.840.113549.1.9.16.2.1' => ' id-aa-receiptRequest',
+			'1.2.840.113549.1.9.16.2.2' => ' id-aa-securityLabel',
+			'1.2.840.113549.1.9.16.2.3' => ' id-aa-mlExpandHistory',
+			'1.2.840.113549.1.9.16.2.4' => ' id-aa-contentHint',
+			'1.2.840.113549.1.9.2' => ' unstructuredName',
+			'1.2.840.113549.1.9.20' => ' friendlyName',
+			'1.2.840.113549.1.9.21' => ' localKeyID',
+			'1.2.840.113549.1.9.22' => ' certTypes',
+			'1.2.840.113549.1.9.22.1' => ' x509Certificate',
+			'1.2.840.113549.1.9.22.2' => ' sdsiCertificate',
+			'1.2.840.113549.1.9.23' => ' crlTypes',
+			'1.2.840.113549.1.9.23.1' => ' x509Crl',
+			'1.2.840.113549.1.9.3' => ' contentType',
+			'1.2.840.113549.1.9.4' => ' messageDigest',
+			'1.2.840.113549.1.9.5' => ' signingTime',
+			'1.2.840.113549.1.9.6' => ' countersignature',
+			'1.2.840.113549.1.9.7' => ' challengePassword',
+			'1.2.840.113549.1.9.8' => ' unstructuredAddress',
+			'1.2.840.113549.1.9.9' => ' extendedCertificateAttributes',
+			'1.2.840.113549.2' => ' digestAlgorithm',
+			'1.2.840.113549.2.2' => ' md2',
+			'1.2.840.113549.2.4' => ' md4',
+			'1.2.840.113549.2.5' => ' md5',
+			'1.2.840.113549.3' => ' encryptionAlgorithm',
+			'1.2.840.113549.3.10' => ' desCDMF',
+			'1.2.840.113549.3.2' => ' rc2CBC',
+			'1.2.840.113549.3.3' => ' rc2ECB',
+			'1.2.840.113549.3.4' => ' rc4',
+			'1.2.840.113549.3.5' => ' rc4WithMAC',
+			'1.2.840.113549.3.6' => ' DESX-CBC',
+			'1.2.840.113549.3.7' => ' DES-EDE3-CBC',
+			'1.2.840.113549.3.8' => ' RC5CBC',
+			'1.2.840.113549.3.9' => ' RC5-CBCPad',
+			'1.2.840.113556.4.3' => ' microsoftExcel',
+			'1.2.840.113556.4.4' => ' titledWithOID',
+			'1.2.840.113556.4.5' => ' microsoftPowerPoint',
+			'1.3.133.16.840.9.84' => ' x9-84',
+			'1.3.133.16.840.9.84.0' => ' x9-84-Module',
+			'1.3.133.16.840.9.84.0.1' => ' x9-84-Biometrics',
+			'1.3.133.16.840.9.84.0.2' => ' x9-84-CMS',
+			'1.3.133.16.840.9.84.0.3' => ' x9-84-Identifiers',
+			'1.3.133.16.840.9.84.1' => ' biometric',
+			'1.3.133.16.840.9.84.1.0' => ' id-unknown-Type',
+			'1.3.133.16.840.9.84.1.1' => ' id-body-Odor',
+			'1.3.133.16.840.9.84.1.10' => ' id-palm',
+			'1.3.133.16.840.9.84.1.11' => ' id-retina',
+			'1.3.133.16.840.9.84.1.12' => ' id-signature',
+			'1.3.133.16.840.9.84.1.13' => ' id-speech-Pattern',
+			'1.3.133.16.840.9.84.1.14' => ' id-thermal-Image',
+			'1.3.133.16.840.9.84.1.15' => ' id-vein-Pattern',
+			'1.3.133.16.840.9.84.1.16' => ' id-thermal-Face-Image',
+			'1.3.133.16.840.9.84.1.17' => ' id-thermal-Hand-Image',
+			'1.3.133.16.840.9.84.1.18' => ' id-lip-Movement',
+			'1.3.133.16.840.9.84.1.19' => ' id-gait',
+			'1.3.133.16.840.9.84.1.2' => ' id-dna',
+			'1.3.133.16.840.9.84.1.3' => ' id-ear-Shape',
+			'1.3.133.16.840.9.84.1.4' => ' id-facial-Features',
+			'1.3.133.16.840.9.84.1.5' => ' id-finger-Image',
+			'1.3.133.16.840.9.84.1.6' => ' id-finger-Geometry',
+			'1.3.133.16.840.9.84.1.7' => ' id-hand-Geometry',
+			'1.3.133.16.840.9.84.1.8' => ' id-iris-Features',
+			'1.3.133.16.840.9.84.1.9' => ' id-keystroke-Dynamics',
+			'1.3.133.16.840.9.84.2' => ' processing-algorithm',
+			'1.3.133.16.840.9.84.3' => ' matching-method',
+			'1.3.133.16.840.9.84.4' => ' format-Owner',
+			'1.3.133.16.840.9.84.4.0' => ' cbeff-Owner',
+			'1.3.133.16.840.9.84.4.1' => ' ibia-Owner',
+			'1.3.133.16.840.9.84.4.1.1' => ' id-ibia-SAFLINK',
+			'1.3.133.16.840.9.84.4.1.10' => ' id-ibia-SecuGen',
+			'1.3.133.16.840.9.84.4.1.11' => ' id-ibia-PreciseBiometric',
+			'1.3.133.16.840.9.84.4.1.12' => ' id-ibia-Identix',
+			'1.3.133.16.840.9.84.4.1.13' => ' id-ibia-DERMALOG',
+			'1.3.133.16.840.9.84.4.1.14' => ' id-ibia-LOGICO',
+			'1.3.133.16.840.9.84.4.1.15' => ' id-ibia-NIST',
+			'1.3.133.16.840.9.84.4.1.16' => ' id-ibia-A3Vision',
+			'1.3.133.16.840.9.84.4.1.17' => ' id-ibia-NEC',
+			'1.3.133.16.840.9.84.4.1.18' => ' id-ibia-STMicroelectronics',
+			'1.3.133.16.840.9.84.4.1.2' => ' id-ibia-Bioscrypt',
+			'1.3.133.16.840.9.84.4.1.3' => ' id-ibia-Visionics',
+			'1.3.133.16.840.9.84.4.1.4' => ' id-ibia-InfineonTechnologiesAG',
+			'1.3.133.16.840.9.84.4.1.5' => ' id-ibia-IridianTechnologies',
+			'1.3.133.16.840.9.84.4.1.6' => ' id-ibia-Veridicom',
+			'1.3.133.16.840.9.84.4.1.7' => ' id-ibia-CyberSIGN',
+			'1.3.133.16.840.9.84.4.1.8' => ' id-ibia-eCryp.',
+			'1.3.133.16.840.9.84.4.1.9' => ' id-ibia-FingerprintCardsAB',
+			'1.3.133.16.840.9.84.4.2' => ' x9-Owner',
+			'1.3.14.2.26.5' => ' sha',
+			'1.3.14.3.2.1.1' => ' rsa',
+			'1.3.14.3.2.10' => ' desMAC',
+			'1.3.14.3.2.11' => ' rsaSignature',
+			'1.3.14.3.2.12' => ' dsa',
+			'1.3.14.3.2.13' => ' dsaWithSHA',
+			'1.3.14.3.2.14' => ' mdc2WithRSASignature',
+			'1.3.14.3.2.15' => ' shaWithRSASignature',
+			'1.3.14.3.2.16' => ' dhWithCommonModulus',
+			'1.3.14.3.2.17' => ' desEDE',
+			'1.3.14.3.2.18' => ' sha',
+			'1.3.14.3.2.19' => ' mdc-2',
+			'1.3.14.3.2.2' => ' md4WitRSA',
+			'1.3.14.3.2.2.1' => ' sqmod-N',
+			'1.3.14.3.2.20' => ' dsaCommon',
+			'1.3.14.3.2.21' => ' dsaCommonWithSHA',
+			'1.3.14.3.2.22' => ' rsaKeyTransport',
+			'1.3.14.3.2.23' => ' keyed-hash-seal',
+			'1.3.14.3.2.24' => ' md2WithRSASignature',
+			'1.3.14.3.2.25' => ' md5WithRSASignature',
+			'1.3.14.3.2.26' => ' sha1',
+			'1.3.14.3.2.27' => ' dsaWithSHA1',
+			'1.3.14.3.2.28' => ' dsaWithCommonSHA1',
+			'1.3.14.3.2.29' => ' sha-1WithRSAEncryption',
+			'1.3.14.3.2.3' => ' md5WithRSA',
+			'1.3.14.3.2.3.1' => ' sqmod-NwithRSA',
+			'1.3.14.3.2.4' => ' md4WithRSAEncryption',
+			'1.3.14.3.2.6' => ' desECB',
+			'1.3.14.3.2.7' => ' desCBC',
+			'1.3.14.3.2.8' => ' desOFB',
+			'1.3.14.3.2.9' => ' desCFB',
+			'1.3.14.3.3.1' => ' simple-strong-auth-mechanism',
+			'1.3.14.7.2.1.1' => ' ElGamal',
+			'1.3.14.7.2.3.1' => ' md2WithRSA',
+			'1.3.14.7.2.3.2' => ' md2WithElGamal',
+			'1.3.36.3' => ' algorithm',
+			'1.3.36.3.1' => ' encryptionAlgorithm',
+			'1.3.36.3.1.1' => ' des',
+			'1.3.36.3.1.1.1.1' => ' desECBPad',
+			'1.3.36.3.1.1.1.1.1' => ' desECBPadISO',
+			'1.3.36.3.1.1.2.1' => ' desCBCPad',
+			'1.3.36.3.1.1.2.1.1' => ' desCBCPadISO',
+			'1.3.36.3.1.2' => ' idea',
+			'1.3.36.3.1.2.1' => ' ideaECB',
+			'1.3.36.3.1.2.1.1' => ' ideaECBPad',
+			'1.3.36.3.1.2.1.1.1' => ' ideaECBPadISO',
+			'1.3.36.3.1.2.2' => ' ideaCBC',
+			'1.3.36.3.1.2.2.1' => ' ideaCBCPad',
+			'1.3.36.3.1.2.2.1.1' => ' ideaCBCPadISO',
+			'1.3.36.3.1.2.3' => ' ideaOFB',
+			'1.3.36.3.1.2.4' => ' ideaCFB',
+			'1.3.36.3.1.3' => ' des-3',
+			'1.3.36.3.1.3.1.1' => ' des-3ECBPad',
+			'1.3.36.3.1.3.1.1.1' => ' des-3ECBPadISO',
+			'1.3.36.3.1.3.2.1' => ' des-3CBCPad',
+			'1.3.36.3.1.3.2.1.1' => ' des-3CBCPadISO',
+			'1.3.36.3.2' => ' hashAlgorithm',
+			'1.3.36.3.2.1' => ' ripemd160',
+			'1.3.36.3.2.2' => ' ripemd128',
+			'1.3.36.3.2.3' => ' ripemd256',
+			'1.3.36.3.2.4' => ' mdc2singleLength',
+			'1.3.36.3.2.5' => ' mdc2doubleLength',
+			'1.3.36.3.3' => ' signatureAlgorithm',
+			'1.3.36.3.3.1' => ' rsa',
+			'1.3.36.3.3.1.1' => ' rsaMitSHA-1',
+			'1.3.36.3.3.1.2' => ' rsaMitRIPEMD160',
+			'1.3.36.3.3.2' => ' ellipticCurve',
+			'1.3.36.3.4' => ' signatureScheme',
+			'1.3.36.3.4.1' => ' iso9796-1',
+			'1.3.36.3.4.2.1' => ' iso9796-2',
+			'1.3.36.3.4.2.2' => ' iso9796-2rsa',
+			'1.3.36.4' => ' attribute',
+			'1.3.36.5' => ' policy',
+			'1.3.36.6' => ' api',
+			'1.3.36.6.1' => ' manufacturerSpecific',
+			'1.3.36.6.2' => ' functionalitySpecific',
+			'1.3.36.7' => ' api',
+			'1.3.36.7.1' => ' keyAgreement',
+			'1.3.36.7.2' => ' keyTransport',
+			'1.3.6.1.4.1.2428.10.1.1' => ' UNINETT policyIdentifier',
+			'1.3.6.1.4.1.2712.10' => ' ICE-TEL policyIdentifier',
+			'1.3.6.1.4.1.3029.32.1' => ' cryptlibEnvelope',
+			'1.3.6.1.4.1.3029.32.2' => ' cryptlibPrivateKey',
+			'1.3.6.1.4.1.311' => ' Microsoft OID',
+			'1.3.6.1.4.1.311.10' => ' Crypto 2.0',
+			'1.3.6.1.4.1.311.10.1' => ' certTrustList',
+			'1.3.6.1.4.1.311.10.1.1' => ' szOID_SORTED_CTL',
+			'1.3.6.1.4.1.311.10.10' => ' Microsoft CMC OIDs',
+			'1.3.6.1.4.1.311.10.10.1' => ' szOID_CMC_ADD_ATTRIBUTES',
+			'1.3.6.1.4.1.311.10.11' => ' Microsoft certificate property OIDs',
+			'1.3.6.1.4.1.311.10.11.1' => ' szOID_CERT_PROP_ID_PREFIX',
+			'1.3.6.1.4.1.311.10.12' => ' CryptUI',
+			'1.3.6.1.4.1.311.10.12.1' => ' szOID_ANY_APPLICATION_POLICY',
+			'1.3.6.1.4.1.311.10.2' => ' nextUpdateLocation',
+			'1.3.6.1.4.1.311.10.3.1' => ' certTrustListSigning',
+			'1.3.6.1.4.1.311.10.3.10' => ' szOID_KP_QUALIFIED_SUBORDINATION',
+			'1.3.6.1.4.1.311.10.3.11' => ' szOID_KP_KEY_RECOVERY',
+			'1.3.6.1.4.1.311.10.3.12' => ' szOID_KP_DOCUMENT_SIGNING',
+			'1.3.6.1.4.1.311.10.3.2' => ' timeStampSigning',
+			'1.3.6.1.4.1.311.10.3.3' => ' serverGatedCrypto',
+			'1.3.6.1.4.1.311.10.3.3.1' => ' szOID_SERIALIZED',
+			'1.3.6.1.4.1.311.10.3.4' => ' encryptedFileSystem',
+			'1.3.6.1.4.1.311.10.3.4.1' => ' szOID_EFS_RECOVERY',
+			'1.3.6.1.4.1.311.10.3.5' => ' szOID_WHQL_CRYPTO',
+			'1.3.6.1.4.1.311.10.3.6' => ' szOID_NT5_CRYPTO',
+			'1.3.6.1.4.1.311.10.3.7' => ' szOID_OEM_WHQL_CRYPTO',
+			'1.3.6.1.4.1.311.10.3.8' => ' szOID_EMBEDDED_NT_CRYPTO',
+			'1.3.6.1.4.1.311.10.3.9' => ' szOID_ROOT_LIST_SIGNER',
+			'1.3.6.1.4.1.311.10.4.1' => ' yesnoTrustAttr',
+			'1.3.6.1.4.1.311.10.5.1' => ' szOID_DRM',
+			'1.3.6.1.4.1.311.10.5.2' => ' szOID_DRM_INDIVIDUALIZATION',
+			'1.3.6.1.4.1.311.10.6.1' => ' szOID_LICENSES',
+			'1.3.6.1.4.1.311.10.6.2' => ' szOID_LICENSE_SERVER',
+			'1.3.6.1.4.1.311.10.7' => ' szOID_MICROSOFT_RDN_PREFIX',
+			'1.3.6.1.4.1.311.10.7.1' => ' szOID_KEYID_RDN',
+			'1.3.6.1.4.1.311.10.8.1' => ' szOID_REMOVE_CERTIFICATE',
+			'1.3.6.1.4.1.311.10.9.1' => ' szOID_CROSS_CERT_DIST_POINTS',
+			'1.3.6.1.4.1.311.12' => ' Catalog',
+			'1.3.6.1.4.1.311.12.1.1' => ' szOID_CATALOG_LIST',
+			'1.3.6.1.4.1.311.12.1.2' => ' szOID_CATALOG_LIST_MEMBER',
+			'1.3.6.1.4.1.311.12.2.1' => ' CAT_NAMEVALUE_OBJID',
+			'1.3.6.1.4.1.311.12.2.2' => ' CAT_MEMBERINFO_OBJID',
+			'1.3.6.1.4.1.311.13' => ' Microsoft PKCS10 OIDs',
+			'1.3.6.1.4.1.311.13.1' => ' szOID_RENEWAL_CERTIFICATE',
+			'1.3.6.1.4.1.311.13.2.1' => ' szOID_ENROLLMENT_NAME_VALUE_PAIR',
+			'1.3.6.1.4.1.311.13.2.2' => ' szOID_ENROLLMENT_CSP_PROVIDER',
+			'1.3.6.1.4.1.311.13.2.3' => ' OS Version',
+			'1.3.6.1.4.1.311.15' => ' Microsoft Java',
+			'1.3.6.1.4.1.311.16' => ' Microsoft Outlook/Exchange',
+			'1.3.6.1.4.1.311.16.4' => ' Outlook Express',
+			'1.3.6.1.4.1.311.17' => ' Microsoft PKCS12 attributes',
+			'1.3.6.1.4.1.311.17.1' => ' szOID_LOCAL_MACHINE_KEYSET',
+			'1.3.6.1.4.1.311.18' => ' Microsoft Hydra',
+			'1.3.6.1.4.1.311.19' => ' Microsoft ISPU Test',
+			'1.3.6.1.4.1.311.2' => ' Authenticode',
+			'1.3.6.1.4.1.311.2.1.10' => ' spcAgencyInfo',
+			'1.3.6.1.4.1.311.2.1.11' => ' spcStatementType',
+			'1.3.6.1.4.1.311.2.1.12' => ' spcSpOpusInfo',
+			'1.3.6.1.4.1.311.2.1.14' => ' certExtensions',
+			'1.3.6.1.4.1.311.2.1.15' => ' spcPelmageData',
+			'1.3.6.1.4.1.311.2.1.18' => ' SPC_RAW_FILE_DATA_OBJID',
+			'1.3.6.1.4.1.311.2.1.19' => ' SPC_STRUCTURED_STORAGE_DATA_OBJID',
+			'1.3.6.1.4.1.311.2.1.20' => ' spcLink',
+			'1.3.6.1.4.1.311.2.1.21' => ' individualCodeSigning',
+			'1.3.6.1.4.1.311.2.1.22' => ' commercialCodeSigning',
+			'1.3.6.1.4.1.311.2.1.25' => ' spcLink',
+			'1.3.6.1.4.1.311.2.1.26' => ' spcMinimalCriteriaInfo',
+			'1.3.6.1.4.1.311.2.1.27' => ' spcFinancialCriteriaInfo',
+			'1.3.6.1.4.1.311.2.1.28' => ' spcLink',
+			'1.3.6.1.4.1.311.2.1.29' => ' SPC_HASH_INFO_OBJID',
+			'1.3.6.1.4.1.311.2.1.30' => ' SPC_SIPINFO_OBJID',
+			'1.3.6.1.4.1.311.2.1.4' => ' spcIndirectDataContext',
+			'1.3.6.1.4.1.311.2.2' => ' CTL for Software Publishers Trusted CAs',
+			'1.3.6.1.4.1.311.2.2.1' => ' szOID_TRUSTED_CODESIGNING_CA_LIST',
+			'1.3.6.1.4.1.311.2.2.2' => ' szOID_TRUSTED_CLIENT_AUTH_CA_LIST',
+			'1.3.6.1.4.1.311.2.2.3' => ' szOID_TRUSTED_SERVER_AUTH_CA_LIST',
+			'1.3.6.1.4.1.311.20' => ' Microsoft Enrollment Infrastructure',
+			'1.3.6.1.4.1.311.20.1' => ' szOID_AUTO_ENROLL_CTL_USAGE',
+			'1.3.6.1.4.1.311.20.2' => ' szOID_ENROLL_CERTTYPE_EXTENSION',
+			'1.3.6.1.4.1.311.20.2.1' => ' szOID_ENROLLMENT_AGENT',
+			'1.3.6.1.4.1.311.20.2.2' => ' szOID_KP_SMARTCARD_LOGON',
+			'1.3.6.1.4.1.311.20.2.3' => ' szOID_NT_PRINCIPAL_NAME',
+			'1.3.6.1.4.1.311.20.3' => ' szOID_CERT_MANIFOLD',
+			'1.3.6.1.4.1.311.21' => ' Microsoft CertSrv Infrastructure',
+			'1.3.6.1.4.1.311.21.1' => ' szOID_CERTSRV_CA_VERSION',
+			'1.3.6.1.4.1.311.21.20' => ' Client Information',
+			'1.3.6.1.4.1.311.25' => ' Microsoft Directory Service',
+			'1.3.6.1.4.1.311.25.1' => ' szOID_NTDS_REPLICATION',
+			'1.3.6.1.4.1.311.3' => ' Time Stamping',
+			'1.3.6.1.4.1.311.3.2.1' => ' SPC_TIME_STAMP_REQUEST_OBJID',
+			'1.3.6.1.4.1.311.30' => ' IIS',
+			'1.3.6.1.4.1.311.31' => ' Windows updates and service packs',
+			'1.3.6.1.4.1.311.31.1' => ' szOID_PRODUCT_UPDATE',
+			'1.3.6.1.4.1.311.4' => ' Permissions',
+			'1.3.6.1.4.1.311.40' => ' Fonts',
+			'1.3.6.1.4.1.311.41' => ' Microsoft Licensing and Registration',
+			'1.3.6.1.4.1.311.42' => ' Microsoft Corporate PKI (ITG)',
+			'1.3.6.1.4.1.311.88' => ' CAPICOM',
+			'1.3.6.1.4.1.311.88.1' => ' szOID_CAPICOM_VERSION',
+			'1.3.6.1.4.1.311.88.2' => ' szOID_CAPICOM_ATTRIBUTE',
+			'1.3.6.1.4.1.311.88.2.1' => ' szOID_CAPICOM_DOCUMENT_NAME',
+			'1.3.6.1.4.1.311.88.2.2' => ' szOID_CAPICOM_DOCUMENT_DESCRIPTION',
+			'1.3.6.1.4.1.311.88.3' => ' szOID_CAPICOM_ENCRYPTED_DATA',
+			'1.3.6.1.4.1.311.88.3.1' => ' szOID_CAPICOM_ENCRYPTED_CONTENT',
+			'1.3.6.1.5.5.7' => ' pkix',
+			'1.3.6.1.5.5.7.1' => ' privateExtension',
+			'1.3.6.1.5.5.7.1.1' => ' authorityInfoAccess',
+			'1.3.6.1.5.5.7.12.2' => ' CMC Data',
+			'1.3.6.1.5.5.7.2' => ' policyQualifierIds',
+			'1.3.6.1.5.5.7.2.1' => ' cps',
+			'1.3.6.1.5.5.7.2.2' => ' unotice',
+			'1.3.6.1.5.5.7.3' => ' keyPurpose',
+			'1.3.6.1.5.5.7.3.1' => ' serverAuth',
+			'1.3.6.1.5.5.7.3.2' => ' clientAuth',
+			'1.3.6.1.5.5.7.3.3' => ' codeSigning',
+			'1.3.6.1.5.5.7.3.4' => ' emailProtection',
+			'1.3.6.1.5.5.7.3.5' => ' ipsecEndSystem',
+			'1.3.6.1.5.5.7.3.6' => ' ipsecTunnel',
+			'1.3.6.1.5.5.7.3.7' => ' ipsecUser',
+			'1.3.6.1.5.5.7.3.8' => ' timeStamping',
+			'1.3.6.1.5.5.7.4' => ' cmpInformationTypes',
+			'1.3.6.1.5.5.7.4.1' => ' caProtEncCert',
+			'1.3.6.1.5.5.7.4.2' => ' signKeyPairTypes',
+			'1.3.6.1.5.5.7.4.3' => ' encKeyPairTypes',
+			'1.3.6.1.5.5.7.4.4' => ' preferredSymmAlg',
+			'1.3.6.1.5.5.7.4.5' => ' caKeyUpdateInfo',
+			'1.3.6.1.5.5.7.4.6' => ' currentCRL',
+			'1.3.6.1.5.5.7.48.1' => ' ocsp',
+			'1.3.6.1.5.5.7.48.2' => ' caIssuers',
+			'1.3.6.1.5.5.8.1.1' => ' HMAC-MD5',
+			'1.3.6.1.5.5.8.1.2' => ' HMAC-SHA',
+			'2.16.840.1.101.2.1.1.1' => ' sdnsSignatureAlgorithm',
+			'2.16.840.1.101.2.1.1.10' => ' mosaicKeyManagementAlgorithm',
+			'2.16.840.1.101.2.1.1.11' => ' sdnsKMandSigAlgorithm',
+			'2.16.840.1.101.2.1.1.12' => ' mosaicKMandSigAlgorithm',
+			'2.16.840.1.101.2.1.1.13' => ' SuiteASignatureAlgorithm',
+			'2.16.840.1.101.2.1.1.14' => ' SuiteAConfidentialityAlgorithm',
+			'2.16.840.1.101.2.1.1.15' => ' SuiteAIntegrityAlgorithm',
+			'2.16.840.1.101.2.1.1.16' => ' SuiteATokenProtectionAlgorithm',
+			'2.16.840.1.101.2.1.1.17' => ' SuiteAKeyManagementAlgorithm',
+			'2.16.840.1.101.2.1.1.18' => ' SuiteAKMandSigAlgorithm',
+			'2.16.840.1.101.2.1.1.19' => ' mosaicUpdatedSigAlgorithm',
+			'2.16.840.1.101.2.1.1.2' => ' mosaicSignatureAlgorithm',
+			'2.16.840.1.101.2.1.1.20' => ' mosaicKMandUpdSigAlgorithms',
+			'2.16.840.1.101.2.1.1.21' => ' mosaicUpdatedIntegAlgorithm',
+			'2.16.840.1.101.2.1.1.22' => ' mosaicKeyEncryptionAlgorithm',
+			'2.16.840.1.101.2.1.1.3' => ' sdnsConfidentialityAlgorithm',
+			'2.16.840.1.101.2.1.1.4' => ' mosaicConfidentialityAlgorithm',
+			'2.16.840.1.101.2.1.1.5' => ' sdnsIntegrityAlgorithm',
+			'2.16.840.1.101.2.1.1.6' => ' mosaicIntegrityAlgorithm',
+			'2.16.840.1.101.2.1.1.7' => ' sdnsTokenProtectionAlgorithm',
+			'2.16.840.1.101.2.1.1.8' => ' mosaicTokenProtectionAlgorithm',
+			'2.16.840.1.101.2.1.1.9' => ' sdnsKeyManagementAlgorithm',
+			'2.16.840.1.113730.1' => ' cert-extension',
+			'2.16.840.1.113730.1.1' => ' netscape-cert-type',
+			'2.16.840.1.113730.1.10' => ' EntityLogo',
+			'2.16.840.1.113730.1.11' => ' UserPicture',
+			'2.16.840.1.113730.1.12' => ' netscape-ssl-server-name',
+			'2.16.840.1.113730.1.13' => ' netscape-comment',
+			'2.16.840.1.113730.1.2' => ' netscape-base-url',
+			'2.16.840.1.113730.1.3' => ' netscape-revocation-url',
+			'2.16.840.1.113730.1.4' => ' netscape-ca-revocation-url',
+			'2.16.840.1.113730.1.7' => ' netscape-cert-renewal-url',
+			'2.16.840.1.113730.1.8' => ' netscape-ca-policy-url',
+			'2.16.840.1.113730.1.9' => ' HomePage-url',
+			'2.16.840.1.113730.2' => ' data-type',
+			'2.16.840.1.113730.2.1' => ' GIF',
+			'2.16.840.1.113730.2.2' => ' JPEG',
+			'2.16.840.1.113730.2.3' => ' URL',
+			'2.16.840.1.113730.2.4' => ' HTML',
+			'2.16.840.1.113730.2.5' => ' netscape-cert-sequence',
+			'2.16.840.1.113730.2.6' => ' netscape-cert-url',
+			'2.16.840.1.113730.3' => ' directory',
+			'2.16.840.1.113730.4.1' => ' serverGatedCrypto',
+			'2.16.840.1.113733.1.6.3' => ' Unknown Verisign extension',
+			'2.16.840.1.113733.1.6.6' => ' Unknown Verisign extension',
+			'2.16.840.1.113733.1.7.1.1' => ' Verisign certificatePolicy',
+			'2.16.840.1.113733.1.7.1.1.1' => ' Unknown Verisign policy qualifier',
+			'2.16.840.1.113733.1.7.1.1.2' => ' Unknown Verisign policy qualifier',
+			'2.23.133' => ' TCPA',
+			'2.23.133.1' => ' tcpa_specVersion',
+			'2.23.133.2' => ' tcpa_attribute',
+			'2.23.133.2.1' => ' tcpa_at_tpmManufacturer',
+			'2.23.133.2.10' => ' tcpa_at_securityQualities',
+			'2.23.133.2.11' => ' tcpa_at_tpmProtectionProfile',
+			'2.23.133.2.12' => ' tcpa_at_tpmSecurityTarget',
+			'2.23.133.2.13' => ' tcpa_at_foundationProtectionProfile',
+			'2.23.133.2.14' => ' tcpa_at_foundationSecurityTarget',
+			'2.23.133.2.15' => ' tcpa_at_tpmIdLabel',
+			'2.23.133.2.2' => ' tcpa_at_tpmModel',
+			'2.23.133.2.3' => ' tcpa_at_tpmVersion',
+			'2.23.133.2.4' => ' tcpa_at_platformManufacturer',
+			'2.23.133.2.5' => ' tcpa_at_platformModel',
+			'2.23.133.2.6' => ' tcpa_at_platformVersion',
+			'2.23.133.2.7' => ' tcpa_at_componentManufacturer',
+			'2.23.133.2.8' => ' tcpa_at_componentModel',
+			'2.23.133.2.9' => ' tcpa_at_componentVersion',
+			'2.23.133.3' => ' tcpa_protocol',
+			'2.23.133.3.1' => ' tcpa_prtt_tpmIdProtocol',
+			'2.23.42.0' => ' contentType',
+			'2.23.42.0.0' => ' PANData',
+			'2.23.42.0.1' => ' PANToken',
+			'2.23.42.0.2' => ' PANOnly',
+			'2.23.42.1' => ' msgExt',
+			'2.23.42.10' => ' national',
+			'2.23.42.10.192' => ' Japan',
+			'2.23.42.2' => ' field',
+			'2.23.42.2.0' => ' fullName',
+			'2.23.42.2.1' => ' givenName',
+			'2.23.42.2.10' => ' amount',
+			'2.23.42.2.2' => ' familyName',
+			'2.23.42.2.3' => ' birthFamilyName',
+			'2.23.42.2.4' => ' placeName',
+			'2.23.42.2.5' => ' identificationNumber',
+			'2.23.42.2.6' => ' month',
+			'2.23.42.2.7' => ' date',
+			'2.23.42.2.7.11' => ' accountNumber',
+			'2.23.42.2.7.12' => ' passPhrase',
+			'2.23.42.2.8' => ' address',
+			'2.23.42.2.9' => ' telephone',
+			'2.23.42.3' => ' attribute',
+			'2.23.42.3.0' => ' cert',
+			'2.23.42.3.0.0' => ' rootKeyThumb',
+			'2.23.42.3.0.1' => ' additionalPolicy',
+			'2.23.42.4' => ' algorithm',
+			'2.23.42.5' => ' policy',
+			'2.23.42.5.0' => ' root',
+			'2.23.42.6' => ' module',
+			'2.23.42.7' => ' certExt',
+			'2.23.42.7.0' => ' hashedRootKey',
+			'2.23.42.7.1' => ' certificateType',
+			'2.23.42.7.2' => ' merchantData',
+			'2.23.42.7.3' => ' cardCertRequired',
+			'2.23.42.7.4' => ' tunneling',
+			'2.23.42.7.5' => ' setExtensions',
+			'2.23.42.7.6' => ' setQualifier',
+			'2.23.42.8' => ' brand',
+			'2.23.42.8.1' => ' IATA-ATA',
+			'2.23.42.8.30' => ' Diners',
+			'2.23.42.8.34' => ' AmericanExpress',
+			'2.23.42.8.4' => ' VISA',
+			'2.23.42.8.5' => ' MasterCard',
+			'2.23.42.8.6011' => ' Novus',
+			'2.23.42.9' => ' vendor',
+			'2.23.42.9.0' => ' GlobeSet',
+			'2.23.42.9.1' => ' IBM',
+			'2.23.42.9.10' => ' Griffin',
+			'2.23.42.9.11' => ' Certicom',
+			'2.23.42.9.12' => ' OSS',
+			'2.23.42.9.13' => ' TenthMountain',
+			'2.23.42.9.14' => ' Antares',
+			'2.23.42.9.15' => ' ECC',
+			'2.23.42.9.16' => ' Maithean',
+			'2.23.42.9.17' => ' Netscape',
+			'2.23.42.9.18' => ' Verisign',
+			'2.23.42.9.19' => ' BlueMoney',
+			'2.23.42.9.2' => ' CyberCash',
+			'2.23.42.9.20' => ' Lacerte',
+			'2.23.42.9.21' => ' Fujitsu',
+			'2.23.42.9.22' => ' eLab',
+			'2.23.42.9.23' => ' Entrust',
+			'2.23.42.9.24' => ' VIAnet',
+			'2.23.42.9.25' => ' III',
+			'2.23.42.9.26' => ' OpenMarket',
+			'2.23.42.9.27' => ' Lexem',
+			'2.23.42.9.28' => ' Intertrader',
+			'2.23.42.9.29' => ' Persimmon',
+			'2.23.42.9.3' => ' Terisa',
+			'2.23.42.9.30' => ' NABLE',
+			'2.23.42.9.31' => ' espace-net',
+			'2.23.42.9.32' => ' Hitachi',
+			'2.23.42.9.33' => ' Microsoft',
+			'2.23.42.9.34' => ' NEC',
+			'2.23.42.9.35' => ' Mitsubishi',
+			'2.23.42.9.36' => ' NCR',
+			'2.23.42.9.37' => ' e-COMM',
+			'2.23.42.9.38' => ' Gemplus',
+			'2.23.42.9.4' => ' RSADSI',
+			'2.23.42.9.5' => ' VeriFone',
+			'2.23.42.9.6' => ' TrinTech',
+			'2.23.42.9.7' => ' BankGate',
+			'2.23.42.9.8' => ' GTE',
+			'2.23.42.9.9' => ' CompuSource',
+			'2.5.29.1' => ' authorityKeyIdentifier',
+			'2.5.29.10' => ' basicConstraints',
+			'2.5.29.11' => ' nameConstraints',
+			'2.5.29.12' => ' policyConstraints',
+			'2.5.29.13' => ' basicConstraints',
+			'2.5.29.14' => ' subjectKeyIdentifier',
+			'2.5.29.15' => ' keyUsage',
+			'2.5.29.16' => ' privateKeyUsagePeriod',
+			'2.5.29.17' => ' subjectAltName',
+			'2.5.29.18' => ' issuerAltName',
+			'2.5.29.19' => ' basicConstraints',
+			'2.5.29.2' => ' keyAttributes',
+			'2.5.29.20' => ' cRLNumber',
+			'2.5.29.21' => ' cRLReason',
+			'2.5.29.22' => ' expirationDate',
+			'2.5.29.23' => ' instructionCode',
+			'2.5.29.24' => ' invalidityDate',
+			'2.5.29.26' => ' issuingDistributionPoint',
+			'2.5.29.27' => ' deltaCRLIndicator',
+			'2.5.29.28' => ' issuingDistributionPoint',
+			'2.5.29.29' => ' certificateIssuer',
+			'2.5.29.3' => ' certificatePolicies',
+			'2.5.29.30' => ' nameConstraints',
+			'2.5.29.31' => ' cRLDistributionPoints',
+			'2.5.29.32' => ' certificatePolicies',
+			'2.5.29.33' => ' policyMappings',
+			'2.5.29.34' => ' policyConstraints',
+			'2.5.29.35' => ' authorityKeyIdentifier',
+			'2.5.29.36' => ' policyConstraints',
+			'2.5.29.37' => ' extKeyUsage',
+			'2.5.29.4' => ' keyUsageRestriction',
+			'2.5.29.5' => ' policyMapping',
+			'2.5.29.6' => ' subtreesConstraint',
+			'2.5.29.7' => ' subjectAltName',
+			'2.5.29.8' => ' issuerAltName',
+			'2.5.29.9' => ' subjectDirectoryAttributes',
+			'2.5.4.0' => ' objectClass',
+			'2.5.4.1' => ' aliasObjectName',
+			'2.5.4.12' => ' title',
+			'2.5.4.13' => ' description',
+			'2.5.4.14' => ' searchGuide',
+			'2.5.4.15' => ' businessCategory',
+			'2.5.4.16' => ' postalAddress',
+			'2.5.4.17' => ' postalCode',
+			'2.5.4.18' => ' postOfficeBox',
+			'2.5.4.19' => ' physicalDeliveryOfficeName',
+			'2.5.4.2' => ' knowledgeInformation',
+			'2.5.4.20' => ' telephoneNumber',
+			'2.5.4.21' => ' telexNumber',
+			'2.5.4.22' => ' teletexTerminalIdentifier',
+			'2.5.4.23' => ' facsimileTelephoneNumber',
+			'2.5.4.24' => ' x121Address',
+			'2.5.4.25' => ' internationalISDNNumber',
+			'2.5.4.26' => ' registeredAddress',
+			'2.5.4.27' => ' destinationIndicator',
+			'2.5.4.28' => ' preferredDeliveryMehtod',
+			'2.5.4.29' => ' presentationAddress',
+			'2.5.4.30' => ' supportedApplicationContext',
+			'2.5.4.31' => ' member',
+			'2.5.4.32' => ' owner',
+			'2.5.4.33' => ' roleOccupant',
+			'2.5.4.34' => ' seeAlso',
+			'2.5.4.35' => ' userPassword',
+			'2.5.4.36' => ' userCertificate',
+			'2.5.4.37' => ' caCertificate',
+			'2.5.4.38' => ' authorityRevocationList',
+			'2.5.4.39' => ' certificateRevocationList',
+			'2.5.4.40' => ' crossCertificatePair',
+			'2.5.4.41' => ' givenName',
+			'2.5.4.42' => ' givenName',
+			'2.5.4.5' => ' serialNumber',
+			'2.5.4.52' => ' supportedAlgorithms',
+			'2.5.4.53' => ' deltaRevocationList',
+			'2.5.4.58' => ' crossCertificatePair',
+			'2.5.4.9' => ' streetAddress',
+			'2.5.8' => ' X.500-Algorithms',
+			'2.5.8.1' => ' X.500-Alg-Encryption',
+			'2.5.8.1.1' => ' rsa',
+			'2.16.76.1.1' => 'DPC',
+			'2.16.76.1.1.0' => 'DPC da AC Raiz',
+			'2.16.76.1.1.1' => 'DPC da AC Presidência',
+			'2.16.76.1.1.2' => 'DPC da AC Serpro',
+			'2.16.76.1.1.3' => 'DPC da SERASA Autoridade Certificadora Principal - ACP',
+			'2.16.76.1.1.4' => 'DPC da SERASA Autoridade Certificadora - AC',
+			'2.16.76.1.1.5' => 'DPC da AC CertiSign na ICP­Brasil',
+			'2.16.76.1.1.6' => 'DPC da AC CertiSign SPB na ICP­Brasil',
+			'2.16.76.1.1.7' => 'DPC da SERASA Certificadora Digital',
+			'2.16.76.1.1.8' => 'DPC da AC SRF',
+			'2.16.76.1.1.9' => 'DPC da AC CAIXA',
+			'2.16.76.1.1.10' => 'DPC da AC CAIXA IN',
+			'2.16.76.1.1.11' => 'DPC da AC CAIXA PJ',
+			'2.16.76.1.1.12' => 'DPC da AC CAIXA PF',
+			'2.16.76.1.1.13' => 'DPC da AC SERPRO SRF',
+			'2.16.76.1.1.14' => 'DPC da Autoridade Certificadora CertiSign Múltipla',
+			'2.16.76.1.1.15' => 'DPC da Autoridade Certificadora CertiSign para Secretaria da Receita Federal',
+			'2.16.76.1.1.16' => 'DPC da AC SERASA SRF',
+			'2.16.76.1.1.17' => 'DPC da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.1.18' => 'DPC da Autoridade Certificadora PRODEMGE',
+			'2.16.76.1.1.19' => 'DPC da Autoridade Certificadora do Sistema Justiça Federal - AC­JUS',
+			'2.16.76.1.1.20' => 'Declaração   de   Práticas   de   Certificação   da   Autoridade   Certificadora   do SERPRO Final - DPC SERPRO ACF',
+			'2.16.76.1.1' => 'DPC',
+			'2.16.76.1.1.21' => 'Declaração de Práticas de Certificação da Autoridade Certificadora SINCOR',
+			'2.16.76.1.1.22' => 'Declaração de Práticas de Certificação da Autoridade Certificadora Imprensa Oficial SP SRF',
+			'2.16.76.1.1.23' => 'Declaração de Práticas de Certificação da AC FENACOR',
+			'2.16.76.1.1.24' => 'Declaração de Práticas de Certificação da Autoridade Certificadora SERPRO­ JUS',
+			'2.16.76.1.1.25' => 'DPC da AC Caixa Justiça',
+			'2.16.76.1.1.26' => 'DPC da Autoridade Certificadora Imprensa Oficial SP (AC IMESP)',
+			'2.16.76.1.1.27' => 'DPC da Autoridade Certificadora PRODEMGE SRF',
+			'2.16.76.1.1.28' => 'Declaração de Práticas de Certificação da Autoridade Certificadora CertSign  para a Justiça',
+			'2.16.76.1.1.29' => 'DPC da AC SERASA JUS',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.1' => 'A1',
+			'2.16.76.1.2.1.1' => 'Política de Certificados da ACSERPRO para certificados SERPRO­SPB ­ PC SERPRO­SPB',
+			'2.16.76.1.2.1.2' => 'Política de Certificados para certificados da SERASA Autoridade Certificadora',
+			'2.16.76.1.2.1.3' => 'Política   de   Certificados   da   Autoridade   Certificadora   da   Presidência   da República - PCA1',
+			'2.16.76.1.2.1.4' => 'Política   de   Certificado   da   Autoridade   Certificadora   CertiSign   Certificadora Digital para o Sistema de Pagamentos Brasileiro na ICP­Brasil­ PC da AC CertiSign SPB na ICP­Brasil',
+			'2.16.76.1.2.1.5' => 'Política de Certificados SEPROA1',
+			'2.16.76.1.2.1.6' => 'Política de Certificado Digital para Certificado de Assinatura Digital Tipo A1 -  SERASA CD',
+			'2.16.76.1.2.1.7' => 'Política de Certificado de Assinatura Digital do Tipo A1 da AC Caixa IN',
+			'2.16.76.1.2.1.8' => 'Política de Certificado de Assinatura Digital do Tipo A1 da AC Caixa PF',
+			'2.16.76.1.2.1.9' => 'Política de Certificado de Assinatura Digital do Tipo A1 da AC Caixa PJ',
+			'2.16.76.1.2.1.10' => 'Política de Certificados  da  Autoridade  Certificadora  do  Serpro­SRF  para certificados de assinatura digital do tipo A1 (PCSerpro­SRFA1)',
+			'2.16.76.1.2.1.11' => 'Política de  Certificado de  Assinatura Digital do Tipo  A1 da  Autoridade  Certificadora  CertiSign  Múltipla  na  Infra­estrutura  de  Chaves  Públicas  Brasileira',
+			'2.16.76.1.2.1.12' => 'Política  de  Certificado  de   Assinatura   Digital   Tipo   A1   da   Autoridade  Certificadora CertiSign para a Secretaria da Receita Federal',
+			'2.16.76.1.2.1.13' => 'Política de Certificado de Assinatura Digital Tipo A1 da AC SERASA SRF',
+			'2.16.76.1.2.1.14' => 'Política  de Certificado  de  Assinatura   Digital   Tipo  A1  da  Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.1.15' => 'Política  de  Certificado  de  Assinatura   Digital  Tipo  A1  da  Autoridade  Certificadora PRODEMGE',
+			'2.16.76.1.2.1.16' => 'Política de Certificados SERPRO do Tipo A1 - PC SERPRO ACF A1',
+			'2.16.76.1.2.1.17' => 'Política de Certificados do SERPRO - SPB - PC SERPRO ACF SPB',
+			'2.16.76.1.2.1.18' => 'Política  de  Certificado  de  Assinatura  Digital  Tipo  A1  da  Autoridade Certificadora SINCOR',
+			'2.16.76.1.2.1.19' => 'Política de Certificado  de  Assinatura  Digital  Tipo  A1  da  Autoridade Certificadora SINCOR para Corretores de Seguros',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.1' => 'A1',
+			'2.16.76.1.2.1.20' => 'Política  de  Certificado  de  Assinatura  Digital  Tipo  A1  da  Autoridade Certificadora Imprensa Oficial SP SRF',
+			'2.16.76.1.2.1.21' => 'Política de Certificados SERPRO­JUS do tipo A1 ­ PCSERPROJUSA1',
+			'2.16.76.1.2.1.22' => 'Política de Certificado de Assinatura Digital do Tipo A1 da AC Caixa Justiça',
+			'2.16.76.1.2.1.23' => 'Política  de Certificado de  Assinatura  Tipo  A1 da  Autoridade  Certificadora PRODEMGE SRF',
+			'2.16.76.1.2.1.24' => 'Política de Certificado de Assinatura Digital Tipo A1 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.1.25' => 'Política de Certificado Digital da AC  SERASA­JUS para Certificados Tipo A1',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.2' => 'A2',
+			'2.16.76.1.2.2.1' => 'Política de Certificado Digital para Certificado de Assinatura Digital  Tipo A2 - SERASA CD',
+			'2.16.76.1.2.2.2' => 'Política de Certificado Digital para Certificado de Assinatura Digital Tipo A2 da AC SERASA SRF',
+			'2.16.76.1.2.2.3' => 'Política  de  Certificado  de  Assinatura  Digital   do  Tipo  A2  da  Autoridade  Certificadora  CertiSign  últipla  na  Infra­estrutura  de Chaves Públicas Brasileira',
+			'2.16.76.1.2.2.4' => 'Política  de  Certificado  de  Assinatura  Digital  do Tipo  A2  da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.2.5' => 'Política de Certificado de Assinatura Digital do Tipo A2 da AC Caixa Justiça',
+			'2.16.76.1.2.2.6' => 'Política de Certificado de Assinatura Digital Tipo A2 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.2.7' => 'Política de Certificado  Digital da  AC SERASA­JUS para Certificados Tipo A2',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.3' => 'A3',
+			'2.16.76.1.2.3.1' => 'Política de Certificados da Autoridade Certificadora da Presidência da República - PC ACPR',
+			'2.16.76.1.2.3.2' => 'Política  de  Certificados   da  Autoridade  Certificadora do  SERPRO para certificados SERPRO do tipo A3 - PCSERPROA3',
+			'2.16.76.1.2.3.3' => 'Política de Certificado Digital para Certificado de Assinatura Digital Tipo A3 - SERASA CD',
+			'2.16.76.1.2.3.4' => 'Política de Certificados da Autoridade Certificadora do Serpro­SRF para certificados de assinatura digital do tipo A3 (PCSerpro­SRFA3)',
+			'2.16.76.1.2.3.5' => 'Política de Certificado de Assinatura Digital do Tipo A3 da  Autoridade Certificadora CertiSign Múltipla na Infra­estrutura de Chaves Públicas Brasileira',
+			'2.16.76.1.2.3.6' => 'Política de Certificado de Assinatura Digital Tipo A3 da Autoridade Certificadora CertiSign para a Secretaria da Receita Federal na Infra­estrutura de Chaves Públicas Brasileira',
+			'2.16.76.1.2.3.7' => 'Política de Certificado de Assinatura Digital do Tipo A3 da AC Caixa  IN',
+			'2.16.76.1.2.3.8' => 'Política de Certificado de Assinatura Digital do Tipo A3 da AC Caixa  PF',
+			'2.16.76.1.2.3.9' => 'Política de Certificado de Assinatura Digital do Tipo A3 da AC Caixa   PJ',
+			'2.16.76.1.2.3.10' => 'Política de Certificado de Assinatura Digital do Tipo A3 da AC SERASA SRF',
+			'2.16.76.1.2.3.11' => 'Política de Certificado de Assinatura Digital do Tipo A3 da  Autoridade Certificadora  Imprensa Oficial ­ SP',
+			'2.16.76.1.2.3.12' => 'Política de Certificado de Assinatura Digital do Tipo A3 da  Autoridade Certificadora PRODEMGE',
+			'2.16.76.1.2.3.13' => 'Política de Certificados SERPRO do Tipo A3 - PC SERPRO A3',
+			'2.16.76.1.2.3.14' => 'Política de Certificado de Assinatura Digital Tipo A3 da Autoridade Certificadora SINCOR',
+			'2.16.76.1.2.3.15' => 'Política de Certificado de Assinatura Digital Tipo A3 da Autoridade  Certificadora SINCOR para Corretores de Seguros',
+			'2.16.76.1.2.3.16' => 'Política de Certificado de Assinatura Digital Tipo A3 da Autoridade  Certificadora Imprensa Oficial SP SRF',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.3' => 'A3',
+			'2.16.76.1.2.3.17' => 'Política de Certificado da AC FENACOR A3',
+			'2.16.76.1.2.3.18' => 'Política  de  Certificados  SERPRO­JUS  do  tipo  A3 PCSERPROJUSA3',
+			'2.16.76.1.2.3.19' => 'Política de Certificado de Assinatura Digital do Tipo A3 da AC Caixa Justiça',
+			'2.16.76.1.2.3.20' => 'Política  de  Certificado  de  Assinatura   Tipo   A3   da   Autoridade Certificadora PRODEMGE SRF',
+			'2.16.76.1.2.3.21' => 'Política de Certificado de Assinatura Digital Tipo A3 da Autoridade  Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.3.22' => 'Política   de   Certificado   Digital   da   AC     SERASA­JUS   para Certificados Tipo A3',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.4' => 'A4',
+			'2.16.76.1.2.4.1' => 'Política de Certificado Digital para Certificado de Assinatura Digital  Tipo A4 - SERASA CD;',
+			'2.16.76.1.2.4.2' => 'VAGO',
+			'2.16.76.1.2.4.3' => 'Política de Certificado de Assinatura Digital do Tipo A4 da  Autoridade Certificadora CertiSign Múltipla na Infra­estrutura de Chaves Públicas Brasileira',
+			'2.16.76.1.2.4.4' => 'Política de Certificado de Assinatura Digital Tipo A4 da Autoridade Certificadora CertiSign para a Secretaria da Receita Federal na Infra­estrutura de Chaves Públicas Brasileira',
+			'2.16.76.1.2.4.5' => 'Política de Certificado de Assinatura Digital Tipo A4 da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.4.6' => 'Política de Certificado de Assinatura Digital Tipo A4 da Autoridade Certificadora Imprensa Oficial - SP SRF',
+			'2.16.76.1.2.4.7' => 'Política   de   Certificado   de   Assinatura   Tipo   A4   da   Autoridade Certificadora PRODEMGE SRF',
+			'2.16.76.1.2.4.8' => 'Política de Certificado de Assinatura Digital Tipo A4 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.4.9' => 'VAGO',
+			'2.16.76.1.2.4.10' => 'Política de Certificado Digital  a  AC SERASA­JUS  para Certificados Tipo A4',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.101' => 'S1',
+			'2.16.76.1.2.101.1' => 'Política de Certificado Digital para Certificado de Sigilo Tipo S1 -  SERASA CD',
+			'2.16.76.1.2.101.2' => 'Política de Certificado de Sigilo Tipo S1 da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.101.3' => 'Política  de  Certificado  de  Sigilo  do  Tipo  S1  da   Autoridade Certificadora CertiSign Múltipla',
+			'2.16.76.1.2.101.4' => 'Política   de   Certificado   de   Sigilo   do   Tipo   S1   da   Autoridade Certificadora PRODEMGE',
+			'2.16.76.1.2.101.5' => 'Política de Certificado de Assinatura Digital do Tipo S1 da AC Caixa Justiça',
+			'2.16.76.1.2.101.6' => 'Política de Certificado de Assinatura Digital Tipo S1 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.101.7' => 'Política   de   Certificado   Digital   da   AC     SERASA­JUS   para Cerficados Tipo S1',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.102' => 'S2',
+			'2.16.76.1.2.102.1' => 'Política de Certificado Digital para Certificado de Sigilo Tipo S2 - SERASA CD',
+			'2.16.76.1.2.102.2' => 'Política de Certificado de Sigilo Tipo S2 da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.102.3' => 'Política   de   Certificado   de   Sigilo   do   Tipo   S2   da   Autoridade Certificadora CertiSign Múltipla',
+			'2.16.76.1.2.102.4' => 'Política de Certificado de Assinatura Digital do Tipo S2 da AC Caixa Justiça',
+			'2.16.76.1.2.102.5' => 'Política de Certificado de Assinatura Digital Tipo S2 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.102.6' => 'Política  de  Certificado  Digital  da   AC  SERASA­JUS   para Certificados Tipo S2',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.103' => 'S3',
+			'2.16.76.1.2.103.1' => 'Política de Certificado Digital para Certificado de Sigilo Tipo S3 -  SERASA CD',
+			'2.16.76.1.2.103.2' => 'VAGO',
+			'2.16.76.1.2.103.3' => 'Política   de   Certificado   de   Sigilo   do   Tipo   S3   da   Autoridade Certificadora CertiSign Múltipla',
+			'2.16.76.1.2.103.4' => 'Política de Certificado de Sigilo Tipo S3 da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.103.5' => 'Política de Certificado de Sigilo Tipo S3 da Autoridade Certificadora PRODEMGE',
+			'2.16.76.1.2.103.6' => 'Política de Certificado de Assinatura Digital do Tipo S3 da AC Caixa Justiça',
+			'2.16.76.1.2.103.7' => 'Política de Certificado de Assinatura Digital Tipo S3 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.103.8' => 'Política   de   Certificado   Digital   da   AC     SERASA­JUS   para Certificados Tipo S3',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.104' => 'S4',
+			'2.16.76.1.2.104.1' => 'Política de Certificado Digital para Certificado de Sigilo Tipo S4 - SERASA CD',
+			'2.16.76.1.2.104.2' => 'VAGO',
+			'2.16.76.1.2.104.3' => 'Política   de   Certificado   de   Sigilo   do   Tipo   S4   da   Autoridade Certificadora CertiSign Múltipla',
+			'2.16.76.1.2.104.4' => 'Política de Certificado de Sigilo Tipo S4 da Autoridade Certificadora Imprensa Oficial ­ SP',
+			'2.16.76.1.2.104.5' => 'Política de Certificado de Assinatura Digital Tipo S4 da Autoridade Certificadora CertiSign para a Justiça',
+			'2.16.76.1.2.104.6' => 'Política   de   Certificado   Digital   da   AC     SERASA­JUS   para Certificados Tipo S4',
+			'2.16.76.1.2' => 'PC',
+			'2.16.76.1.2.201' => 'PC de AC',
+			'2.16.76.1.2.201.1' => 'PC da Serasa Autoridade Certificadora Principal - ACP',
+			'2.16.76.1.2.201.2' => 'PC da AC CertiSign na ICP­Brasil',
+			'2.16.76.1.2.201.3' => 'PC da AC SRF',
+			'2.16.76.1.2.201.4' => 'Política de Certificados da Autoridade Certificadora Caixa',
+			'2.16.76.1.2.201.5' => 'PC da Autoridade Certificadora do Sistema Justiça Federal - AC­ JUS',
+			'2.16.76.1.2.201.6' => 'PC da Autoridade Certificadora do SERPRO (AC SERPRO)',
+			'2.16.76.1.2.201.7' => 'PC da Autoridade Certificadora Imprensa Oficial SP (AC IMESP)',
+			'2.16.76.1.3' => 'Atributos Obrigatórios de Certificados',
+			'2.16.76.1.3.1' => 'campo otherName em certificado de pessoa física',
+			'2.16.76.1.3.2' => 'campo otherName em certificado de pessoa  jurídica',
+			'2.16.76.1.3.3' => 'campo otherName em certificado de pessoa  jurídica',
+			'2.16.76.1.3.4' => 'campo otherName em certificado de pessoa jurídica',
+			'2.16.76.1.3.5' => 'campo otherName em certificado de pessoa física',
+			'2.16.76.1.3.6' => 'campo otherName em certificado de pessoa física',
+			'2.16.76.1.3.7' => 'campo otherName em certificado de pessoa jurídica',
+			'2.16.76.1.4' => 'Atributos Opcionais de  Certificados',
+			'2.16.76.1.4.1' => 'Entidades Sindicais',
+			'2.16.76.1.4.1.1' => 'SINCOR',
+			'2.16.76.1.4.1.1.1' => 'Número de registro do corretor associado');
+
+
+		$result = array();
+		
+		while (strlen($data) > 1) 
+		{
+			$class = ord($data[0]);
+			switch ($class) 
+			{
+				case 0x30:
+					// Sequence
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$sequence_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$values = Crl_parseASN($sequence_data);
+					if (!is_array($values) || is_string($values[0])) 
+					{
+						$values = array($values);
+					}
+					$result[] = array('sequence (' . $len . ')' , $values);
+					break;
+
+				case 0x31:
+					// Set of
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$sequence_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('set (' . $len . ')' , Crl_parseASN($sequence_data));
+					break;
+
+				case 0x01:
+					// Boolean type
+					$boolean_value = (ord($data[2]) == 0xff);
+					$data = substr($data, 3);
+					$result[] = array('boolean (1)' , $boolean_value);
+					break;
+				
+				case 0x02:
+					// Integer type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$integer_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					if($len == 16)
+					{
+						$result[] = array('integer(' . $len . ')', $integer_data);
+						break;
+					}
+					else
+					{
+						$value = 0;
+						if ($len <= 4) 
+						{
+							// Method works fine for small integers
+							for ($i = 0; $i < strlen($integer_data); $i++) 
+							{
+								$value = ($value << 8) | ord($integer_data[$i]);
+							}
+						} 
+						else 
+						{
+							// Method works for arbitrary length integers 
+							if (extension_loaded('bcmath')) 
+							{
+								for ($i = 0; $i < strlen($integer_data); $i++) 
+								{
+									$value = bcadd(bcmul($value, 256), ord($integer_data[$i]));
+								}
+							} 
+							else 
+							{
+								$value = -1;
+							}
+						}
+						$result[] = array('integer(' . $len . ')', $value);
+						break;
+					}
+
+				case 0x03:
+					// Bitstring type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$bitstring_data = substr($data, 2+bytes ,  $len);
+					$data = substr($data, 2 + $bytes + $len);
+					//$result[] = array('bit string (' . $len . ')' ,Crl_parseASN($bitstring_data));
+					$result[] = array('bit string (' . $len . ')' ,'UnsedBits:'.ord($bitstring_data[0]).':'.ord($bitstring_data[1]));
+					break;
+
+				case 0x04:
+					// Octetstring type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$octectstring_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					if($context_especific)
+					{
+						$result[] = array('octet string(' . $len . ')'  , $octectstring_data);
+					}
+					else
+					{
+						$result[] = array('octet string (' . $len . ')' , Crl_parseASN($octectstring_data));
+					}
+					break;
+
+				case 0x05:
+					// Null type
+					$data = substr($data, 2);
+					$result[] = array('null', null);
+					break;
+
+				case 0x06:
+					// Object identifier type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$oid_data = substr($data, 2 + $bytes, $len);
+					$x_len = $data[1];
+					$data = substr($data, 2 + $bytes + $len);
+
+					// Unpack the OID
+					$plain  = floor(ord($oid_data[0]) / 40);
+					$plain .= '.' . ord($oid_data[0]) % 40;
+
+					$value = 0;
+					$i = 1;
+					while ($i < strlen($oid_data)) 
+					{
+						$value = $value << 7;
+						$value = $value | (ord($oid_data[$i]) & 0x7f);
+
+						if (!(ord($oid_data[$i]) & 0x80)) 
+						{
+							$plain .= '.' . $value;
+							$value = 0;
+						}
+						$i++;
+					}
+
+					if (isset($_oids[$plain])) 
+					{
+						$result[] =  array('oid(' . $len . '): '  . $plain, $_oids[$plain]);
+					} 
+					else 
+					{
+						$result[] = array('oid(' . $len . '): '  . $plain, $plain);
+					}
+					break;
+
+				case 0x16:
+					// Character string type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$string_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('IA5 String (' . $len . ')'  , $string_data);
+					break;
+					
+				case 0x12:
+				case 0x14:
+				case 0x15:	
+				case 0x81:			
+					// Character string type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$string_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('string (' . $len . ')'  , $string_data);
+					break;
+
+				case 0x80:
+					// Character string type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$string_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('string (' . $len . ')'  , print_hex($string_data));
+					break;
+					
+				case 0x13:
+				case 0x86:
+					// Printable string type
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$string_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('Printable String (' . $len . ')'  , $string_data);
+					break;
+
+				case 0x17:
+					// Time types
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$time_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('utctime (' . $len . ')'  , $time_data);
+					break;
+
+				case 0x82:
+					// X509v3 extensions?
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$sequence_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('extension : X509v3 extensions (' . $len . ')'  , array(Crl_parseASN($sequence_data)));
+					//$result[] = Crl_parseASN($sequence_data);
+					break;
+
+				case 0xa0:
+					// Extensions
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$extension_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('Context Especific (' . $len . ')' , array(Crl_parseASN($extension_data,true)));
+					break;
+					
+				case 0xa3:
+					// Extensions
+					$len = ord($data[1]);
+					$bytes = 0;
+					get_length(&$len,&$bytes,$data);
+					$extension_data = substr($data, 2 + $bytes, $len);
+					$data = substr($data, 2 + $bytes + $len);
+					$result[] = array('extension (0xA3)  (' . $len . ')' ,array(Crl_parseASN($extension_data)));
+					break;
+
+				case 0xe6:
+					$extension_data = substr($data, 0, 1);
+					$data = substr($data, 1);
+					$result[] = array('extension (0xE6) (' . $len . ')'  , dechex($extension_data));
+					break;
+
+				case 0xa1:
+					$extension_data = substr($data, 0, 1);
+					$data = substr($data, 6);
+					$result[] = array('extension (0xA1) (' . $len . ')'  , dechex($extension_data));
+					break;
+
+				default:
+					// Unknown
+					$result[] = 'UNKNOWN' .  $data;;
+					//file_put_contents('/opt/lampp/htdocs/seguranca/temp/arquivo_desconhecido.txt',$data);
+					$data = '';
+					break;
+			}
+        }
+
+        return (count($result) > 1) ? $result : array_pop($result);
+
+   }
+   
+   function openssl_to_timestamp ($in) 
+   {
+	$year  = substr($in, 0, 4); /* NOTE: Yes, this returns a two digit year */
+        $month = substr($in, 4, 2);
+        $day   = substr($in, 6, 2);
+        $hour  = substr($in, 8, 2);
+        $min   = substr($in, 10, 2);
+        $sec   = substr($in, 12, 2);
+    
+        return gmmktime($hour, $min, $sec, $month, $day, $year);
+	}
+
+#============================================================================================
+# Transforma o certificado do formato PEM para o formato DER ...
+function pem2der($pem_data) 
+	{
+		$begin = "CERTIFICATE-----";
+		$end   = "-----END";
+		$pem_data = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));    
+		$pem_data = substr($pem_data, 0, strpos($pem_data, $end));
+		$der = base64_decode($pem_data);
+		return $der;
+	}
+
+
+function recupera_dados_oid($certificado_digital_formato_der, $oid)
+	{
+		// Esta função assume que a oid esta inserida dentro de uma estrutura do tipo "sequencia" , como primeiro elemento da estrutura...
+	        $oid_hexa = OIDtoHex($oid);                                                        // converte oid de texto para hexadecimal ...
+		$partes = explode($oid_hexa,$certificado_digital_formato_der);    // Faz o split pela oid...
+		$ret = array();
+		if(count($partes)>1)
+			{
+				for($i=1;$i<count($partes);$i++)
+					{
+					        //O inicio da seq pode estar a 3 ou 2 digitos antes do inicio da oid .... depende do numero de bytes usados para  tamanho da seq.
+						$xcv4 = substr($partes[$i-1],strlen($partes[$i-1])-4,4); // recupera da primeira parte os 4 ultimos digitos...
+						$xcv3 = substr($partes[$i-1],strlen($partes[$i-1])-3,3); // recupera da primeira parte os 3 ultimos digitos...
+						$xcv2 = substr($partes[$i-1],strlen($partes[$i-1])-2,2); // recupera da primeira parte os 2 ultimos digitos...
+						if($xcv4[0] == chr(0x30))
+							{
+								$xcv = $xcv4;
+							}
+						else
+							{
+								if($xcv3[0] == chr(0x30))
+									{
+										$xcv = $xcv3;
+									}
+								else
+									{
+										$xcv = $xcv2;
+									}
+							}
+						$data = $xcv . $oid_hexa . $partes[$i];           // reconstroi a sequencia.....				
+						$len = ord($data[1]);
+						$bytes = 0;
+						get_length(&$len,&$bytes,$data);                  // obtem tamanho da parte de dados da oid.
+						$oid_data = substr($data,2 + $bytes,$len);    // Obtem porcao de bytes pertencentes a oid.
+						$ret[] =  Crl_parseASN($oid_data);                 // parse dos dados da oid.
+					} 
+			}
+		return $ret;
+	}
+
+
+# Recupera dados da oid passada como parametro.....
+function parse($oid,$valor)
+	{
+		//
+		//  OID's PESSOA FISICA = 2.16.76.1.3.1 ,  2.16.76.1.3.6 ,  2.16.76.1.3.5 ,  2.16.76.1.4.n ... as 2.16.1.4.n não são obrigatórias e ão sao tratadas..
+		//
+		//  OID's PESSOA JURIDICA = 2.16.76.1.3.4 ,  2.16.76.1.3.2 , 2.16.76.1.3.3 , 2.16.76.1.3.7 
+		//
+		//  OID's EQUIPAMENTO/APLICAÇÃO = 2.16.76.1.3.8 ,  2.16.76.1.3.3 , 2.16.76.1.3.2 , 2.16.76.1.3.4 
+		//	
+		$oids = array('2.16.76.1.3.1' => array('1'=>array('NASCIMENTO',8),
+		                                               '2'=>array('CPF',11),
+							       '3'=>array('NIS',11),
+							       '4'=>array('RG',15),
+							       '5'=>array('ORGAOUF',6)),
+				     '2.16.76.1.3.2' => array('1'=>array('NOMERESPONSAVELCERTIFICADO',0)),
+				     '2.16.76.1.3.3' => array('1'=>array('CNPJ',14)),
+			             '2.16.76.1.3.4' => array('1'=>array('NASCIMENTO',8),
+		                                               '2'=>array('CPF',11),
+							       '3'=>array('NIS',11),
+							       '4'=>array('RG',15),
+							       '5'=>array('ORGAOUF',6)),	
+				     '2.16.76.1.3.5' => array('1'=>array('TITULO',12),
+				                              '2'=>array('ZONA',3),
+							      '3'=>array('SECAO',4),
+							      '4'=>array('TITULO_CIDADE_UF',0)),	
+				     '2.16.76.1.3.6' => array('1'=>array('CADINSS',12)),							      
+				     '2.16.76.1.3.7' => array('1'=>array('CEI',12)),								       
+				     '2.16.76.1.3.8' => array('1'=>array('NOMEEMPRESARIAL',0)));				     
+				     
+		$resultado = array(); 
+		$esta_oid = $oids[$oid];
+		$p = 0;
+		for($i=1;$i < count($esta_oid) + 1; $i++)
+			{
+				if($esta_oid[$i][1] == 0)
+					{
+						# se igual a zero, então esta apontando um ultimo elemento, iniciando em $p, até o fim dos dados
+						$tamanho = strlen($valor) - $p;
+					}
+				else
+					{
+						$tamanho = $esta_oid[$i][1];
+					} 
+				$resultado[$oid][$esta_oid[$i][0]] = substr($valor,$p,$tamanho);
+				// A linha logo abaixo he para manter compatibilidade com versoes anteriores... Sera desativada assim que possivel...
+				$resultado[$esta_oid[$i][0]] = substr($valor,$p,$tamanho);
+				$p = $p + $esta_oid[$i][1];
+			}
+
+		return $resultado;
+	}  
+
+	
+function subjectAltName($xx, $certificado_digital_formato_der)
+	{
+		$dados = array();
+		$ret = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.17');
+		if(count($ret))
+		{
+			if(substr($ret[0][1][0],0,12) == 'octet string')
+				{
+					$ret = $ret[0][1][1][1];
+				}
+			else
+				{
+					$ret = $ret[0][2][1][1];  // Se não iniciou por um octet string skipa para o próximo item na estrutura.
+				}
+			foreach($ret as $group)
+				{
+					if(substr($group[0],0,17) == 'Context Especific')  // primeiro indice tem de ter o valor  'Context Especific' ...
+						{
+							$oid = explode(':',$group[1][0][0][0]);   //  Pega o numero da oid.
+							$dados = array_merge(parse(trim($oid[1]), $group[1][0][1][1][0][1]),$dados); // Passa a oid e o seu valor para ser parseado....
+						}
+					if(substr($group[0],0,6) == 'string')
+						{
+							if(strpos($group[1],'@'))                  //se he email tem de ter uma @.
+								{
+									$aux_email = $group[1];
+								}
+						}
+				}
+			// O  EMAIL foi localizado no loop de tratamento das OIDs.....
+			$dados['EMAIL'] = $aux_email;
+		}
+		return $dados;
+	}
+
+	
+function CRLDistributionPointsxx($xx, $certificado_digital_formato_der)
+	{
+		$AUX = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.31');
+		$i=1;
+		if(substr($AUX[0][1][0],0,7) == 'boolean')
+			{
+				$i=2;
+			}
+		$AUX1 = $AUX[0][$i][1][1][0];
+		// Pode existir mais de uma crl, mas vamos considerar apenas a primeira.....
+		return array('CRLDISTRIBUTIONPOINTS' => $AUX1[1][0][1][0][1][0][1]);		
+	}	
+
+function CRLDistributionPoints($xx, $certificado_digital_formato_der)
+	{
+		$AUX = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.31');
+		$i=1;
+		if(substr($AUX[0][1][0],0,7) == 'boolean')
+			{
+				$i=2;
+			}
+                $ret = array();
+		if($AUX[0][$i][1][1])
+			{
+				if(is_array($AUX[0][$i][1][1]))
+					{
+						//Pode existir mais de um local para obter a CRL.
+						foreach($AUX[0][$i][1][1] as $crl)
+						  {
+						      if(substr($crl[1][0][1][0][1][0][1],0,4) == 'http')
+							{
+								$ret[] = $crl[1][0][1][0][1][0][1];
+							}
+						  }
+					  }
+			  }
+                return array('CRLDISTRIBUTIONPOINTS' => $ret);
+	}	
+
+
+function SERIALNUMBER($cert_data,$KK)
+	{
+		$dados = array();
+		if($cert_data[1][0][1][$KK][1])
+			{
+				$dados['SERIALNUMBER'] = $cert_data[1][0][1][$KK][1];
+			}
+		return $dados;			
+	}
+	
+function SUBJECT($cert_data,$KK)
+	{
+		$dados = array();
+		$dados['SUBJECT'] = array();
+		foreach($cert_data[1][0][1][$KK][1] as $AUX2)
+			{
+				$dados['SUBJECT'][$AUX2[1][1][0][1]] = $AUX2[1][1][1][1];
+			}
+			$AUX = explode(':',$dados['SUBJECT']['CN']);
+		$dados['NOME'] = $AUX[0];
+		return $dados;			
+	}
+		
+function ISSUER($cert_data,$KK)		
+	{
+		$dados = array();	
+		$AUX0 = '/';
+		$dados['EMISSOR_CAMINHO_COMPLETO']  = array();
+		
+		foreach($cert_data[1][0][1][$KK][1] as $AUX2)
+			{
+				$dados['EMISSOR_CAMINHO_COMPLETO'][$AUX2[1][1][0][1]] = $AUX2[1][1][1][1] ;
+			}
+		$dados['EMISSOR'] = $dados['EMISSOR_CAMINHO_COMPLETO']['CN'];
+		return $dados;	
+	}		
+
+
+function BEFOREAFTER($cert_data,$KK)
+	{
+		$dados = array();
+		$dados['INICIO_VALIDADE'] = data_hora($cert_data[1][0][1][$KK][1][0][1]);
+		$dados['FIM_VALIDADE'] = data_hora($cert_data[1][0][1][$KK][1][1][1]);
+		$agora = date('YmdHis');
+		if(($agora < $dados['INICIO_VALIDADE']) || ($agora > $dados['FIM_VALIDADE']))
+			{
+				$dados['EXPIRADO'] = true;
+			}
+		else
+			{
+				$dados['EXPIRADO'] = false;
+			}	
+		return $dados;		
+		}	
+
+
+function AUTHORITYKEYIDENTIFIER($xx, $certificado_digital_formato_der)
+	{
+		$dados = array();
+		if (isset($certificado_digital_formato_der))
+			{
+				$caid = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.35');
+				$i=1;
+				if(substr($caid[0][1][0],0,7) == 'boolean')
+					{
+						$i=2;
+					}
+				$dados['AUTHORITYKEYIDENTIFIER'] = $caid[0][$i][1][1][0][1];
+			}
+		else
+			{
+				// Se nao existir um valor, assume certificado auto assinado .....
+				$dados['AUTHORITYKEYIDENTIFIER'] = "auto-assinado";
+			}
+		return $dados;			
+	}
+	
+function KEYUSAGE($xx, $certificado_digital_formato_der)
+	{
+		$KeyUsage= array( 0x80 => 'digitalSignature', 
+			      0x40 => 'nonRepudiation',
+                              0x20 => 'keyEncipherment',
+			      0x10 => 'dataEncipherment',
+			      0x08 => 'keyAgreement',
+			      0x04 => 'keyCertSign',
+			      0x02 => 'cRLSign');
+
+		$dados = array();
+		if (isset($certificado_digital_formato_der))
+			{
+				$AUX = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.15');  // busca oid do keyusage
+				$AUX = explode(':',$AUX[0][2][1][1]);
+				if(count($AUX) == 3)
+					{
+						foreach($KeyUsage as $chave => $valor)
+							{
+								if($AUX[2] & $chave)
+									{
+										$dados['KEYUSAGE'][$valor] = TRUE;
+									}
+							}
+					}
+			}	
+		return $dados;			
+	}
+
+function EXTKEYUSAGE($xx, $certificado_digital_formato_der)
+	{
+		$dados = array();
+		if (isset($certificado_digital_formato_der))
+			{
+				$AUX = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.37');  // busca oid do extkeyusage
+				$AUX1 = $AUX[0][count($AUX[0])-1];
+				if(count($AUX1) > 0)
+				{
+				foreach($AUX1[1][1] as $itens)
+					{
+					        $AUX2 = explode(':',$itens[0]);
+						$dados['EXTKEYUSAGE'][trim($itens[1])] =  trim($AUX2[1]);
+					}
+				}
+			}
+		return $dados;			
+	}
+	
+function BASICCONSTRAINTS($xx, $certificado_digital_formato_der)
+	{
+		$dados = array();
+		if (isset($certificado_digital_formato_der))
+			{
+				$AUX = recupera_dados_oid($certificado_digital_formato_der,'2.5.29.19');  // busca oid do BasicConstraints
+				if(count($AUX) > 0)
+					{
+						$dados['CA'] = $AUX[0][count($AUX[0])-1][1][1][0][1];
+					}
+			}
+		return $dados;			
+	}
+	
+function recupera_dados_do_ceritificado_digital($certificado_digital_formato_pem)
+	{
+		$cert_der =  pem2der($certificado_digital_formato_pem);
+		
+		$funcoes = array(SERIALNUMBER => 1,
+					ISSUER => 3,
+					BEFOREAFTER => 4,
+					SUBJECT => 5,
+					AUTHORITYKEYIDENTIFIER => $cert_der,
+					KEYUSAGE => $cert_der,
+					EXTKEYUSAGE => $cert_der,
+					BASICCONSTRAINTS => $cert_der,
+					CRLDistributionPoints =>  $cert_der,
+					subjectAltName => $cert_der);
+			   
+		$dados=array();
+		
+		$cert_data = Crl_parseASN( $cert_der);
+		
+		foreach($funcoes as $funcao => $parametro)
+			{
+				$dados= array_merge($dados,$funcao($cert_data,$parametro));
+			}
+
+		if(!$dados['EMAIL'])
+			{
+				$AUX = explode('emailAddress=',$dados['SUBJECT']);
+				if(count($AUX) > 1)
+					{
+						$dados['EMAIL'] = $AUX[1];
+					}
+			}
+		return $dados;		
+	}
+
+#============================================================================================
+
+?>
Index: /trunk/seguranca/security.php
===================================================================
--- /trunk/seguranca/security.php	(revision 1035)
+++ /trunk/seguranca/security.php	(revision 1035)
@@ -0,0 +1,253 @@
+<?php
+	require_once('classes/CertificadoB.php');
+
+        $Linhas = explode(chr(0x0A),file_get_contents($_SERVER["DOCUMENT_ROOT"] . '/seguranca/crl_admin/crl_admin_confg.py'));
+	
+	foreach($Linhas as $linha)
+		{
+			$path = pega_path(array( 'arquivo =', 'arquivo='),$linha);
+			if($path) $path1 = $path;
+			$path = pega_path(array( 'log =', 'log='),$linha);
+			if($path) $path2 = $path;
+			$path = pega_path(array( 'CAfile =', 'CAfile='),$linha);
+			if($path) $path3 = $path;
+		}
+
+	if($path3)
+		{
+		$item = 1;
+		$todos_certificados =  ler_certificados_CAS($path3);
+		$aux_emissores= array();
+		$tab_certs = array();
+		$CB = new CertificadoB();
+		foreach($todos_certificados as $certificados)
+			{
+				$CB -> certificado($certificados);
+				$df = $CB->dados['FIM_VALIDADE'];
+				$di =  $CB->dados['INICIO_VALIDADE'];
+				if(gmdate("YmdHis") > $df)
+					{	
+						$cor = '<label style="color: #FF0000" >Expirado em: </label>';
+					}
+				else
+					{
+						$cor = '<label>Valido at&eacute; </label>';
+					}
+				$info = $cor . substr($df,0,4) . '/' . substr($df,4,2) . '/' . substr($df,6,2) . '  -  ' . substr($df,8,2) . ':' . substr($df,10,2) . ':' . substr($df,12,2) . ' GMT';
+				$info = '<font size="1"' . $info . '</font>';
+				// Armazena alguns dados do certificado. $tabs_certs esta na mesma ordem em que os certificados aparecem no arquivo todos.cer.....
+				$tab_certs[$CB->dados['SUBJECT']['CN']]['item'] = $item++;
+				$tab_certs[$CB->dados['SUBJECT']['CN']]['emissor'] =  $CB->dados['EMISSOR_CAMINHO_COMPLETO']['CN'];
+				$tab_certs[$CB->dados['SUBJECT']['CN']]['fim_validade'] = $info;
+				$tab_certs[$CB->dados['SUBJECT']['CN']]['inicio_validade'] = $di;
+				if($CB->dados['EMISSOR_CAMINHO_COMPLETO']['CN'] !=  $CB->dados['SUBJECT']['CN'])
+					{
+						// Se nao he um auto assinado (identifica um raiz), salva emissor , faz a chave a tdata de inicio de validade do certificado...
+						$aux_emissores[$di][$CB->dados['EMISSOR_CAMINHO_COMPLETO']['CN']][$CB->dados['SUBJECT']['CN']] = '9' ;
+					}
+			}
+                // ordena certificados pela data de inicio de validade ......			
+		ksort($aux_emissores);
+		$NOVO = array();
+		$AUX3 = array();
+		$emissores = array();
+
+		foreach($aux_emissores as $kchave1 => $emis1)
+			{
+				foreach($emis1 as $Kchave2 => $emis2)
+					{
+						foreach($emis2 as $Kchave3 => $emis3)
+							{
+									$emissores[$Kchave2][$Kchave3] = '9';
+							}
+					}
+			}
+
+		// O array $NOVO vai conter a cadeia dos certificados de CAs ....
+		foreach($emissores as $K => $V)
+			{
+			        if($AUX3[$K] != '0')
+				{
+					foreach($V as $K1 => $V1)
+						{
+									if($emissores[$K1])
+										{
+											$NOVO[$K][$K1] = $emissores[$K1];
+											$AUX3[$K1] = '0';
+										}
+									else
+										{
+											$NOVO[$K][$K1] = '0';
+										}
+						}	
+				}
+			} 
+		
+		// Valores auxiliares para fazer a identacao .....
+		$prefixo0 = '&nbsp;&nbsp;' . '|';
+		$prefixo1 =  '&nbsp;&nbsp;' .  '|' .  '____' ;
+		$prefixo2 =  '&nbsp;&nbsp;' . '|' .  '&nbsp;&nbsp;' . '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' . '|' ;
+		$prefixo2A =  '&nbsp;&nbsp;' . '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' . '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' . '|' ;
+		$prefixo3 =  '&nbsp;&nbsp;' . '|' .  '&nbsp;&nbsp;' . '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' . '|'  . '____' ;
+		$prefixo3A =  '&nbsp;&nbsp;' .  '&nbsp;&nbsp;'  .  '&nbsp;&nbsp;' . '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' .  '&nbsp;&nbsp;' . '|'  . '____' ;
+
+		echo '<script type="text/javascript" src="certificados.js"></script>';
+		echo '<h2 style="color: #000066">Cadeias de certificados AC\'s configuradas:</h2>';	
+		echo '<div style="border: #000000 1px solid; overflow: auto; width: 770px; height: 400px; white-space: pre;  padding: 3px; " >';
+		echo '<pre>';
+		foreach($NOVO as $K => $V)
+			{
+				if($tab_certs[$K]['fim_validade'])
+					{
+						$msg =  $tab_certs[$K]['fim_validade'];
+					}
+				else
+					{
+						$msg =  '<font color="FF0000" size="4"><b>Certificado ausente da cadeia.</b></font> ';
+					}
+				echo '<br/><font color="0000FF" size="4"><b><a href="javascript:Um_Certificado(\''. $tab_certs[$K]['item']  . ' - ' . $K .'\')" style="text-decoration: none" >' . $K . '</a></b></font>  ' . $msg . '<br/>';
+				if(is_array($V))
+					{
+						$num = count($V);
+						$item = 0;
+						foreach($V as $K1 => $V1)
+							{
+								$item = $item + 1;
+								echo $prefixo0 . '<br/>';
+								if($tab_certs[$K1]['fim_validade'])
+									{
+										$msg =  $tab_certs[$K1]['fim_validade'];
+									}
+								else
+									{
+										$msg =  '<font color="FF0000" ><b>Certificado ausente da cadeia.</b></font> ';
+									}
+								echo $prefixo1 .  '<font color="#000000" ><a href="javascript:Um_Certificado(\''. $tab_certs[$K1]['item']  . ' - ' . $K1 .'\')" style="text-decoration: none" >' . $K1 . '</a></font> ' .  '  ' . $msg . '<br/>';
+								if(is_array($V1))
+									{
+										foreach($V1 as $K2 => $V2)
+											{
+												if($tab_certs[$K1]['fim_validade'])
+													{
+														$msg =  $tab_certs[$K1]['fim_validade'];
+													}
+												else
+													{
+														$msg =  '<font color="FF0000" ><b>Certificado ausente da cadeia.</b></font> ';
+													}
+												if($num>$item)
+													{
+														echo  $prefixo2 . '<br/>';
+														echo$prefixo3 . '<font color="#000000" ><a href="javascript:Um_Certificado(\''. $tab_certs[$K2]['item']  . ' - ' . $K2 .'\')" style="text-decoration: none" >' . $K2 . '</a></font> ' .  '  ' . $msg . '<br/>';
+													}
+												else
+													{
+														echo  $prefixo2A . '<br/>';
+														echo $prefixo3A .  '<font color="#000000" ><a href="javascript:Um_Certificado(\''. $tab_certs[$K2]['item']  . ' - ' . $K2 .'\')" style="text-decoration: none" >' . $K2 . '</a></font> ' .  '  ' . $msg . '<br/>';										
+													}
+											}
+									}
+							}
+					}
+			}
+		echo '</pre>';
+		echo '</div><br/>';		
+		}
+	if($path1)
+		{
+			$Linhas = explode(chr(0x0A),file_get_contents($path1));
+			echo '<h2  style="color: #000066">LCR\'s configuradas:</h2>';	
+			echo '<table border ="1" style="margin-top: 8px; width: 770px">';
+			echo '<th nowrap align="left" style=" padding: 5px">Lista de Certificados revogados obtida em:</th><th nowrap align="left" style=" padding: 5px">Onde é salva a LCR:</th>';
+			foreach($Linhas as $linha)
+				{
+					if($linha[0] != '#' && $linha != '')
+						{
+							$c = explode(';', $linha);
+							$n = explode('/',$c[0]);
+							$f = $c[1] . $n[count($n)-1];
+							echo '<tr><td nowrap valign="top" style=" padding: 5px">' . $c[0] . '</td><td nowrap style=" padding: 5px">';
+							echo $f;
+							if(!is_file($f))
+								{
+									echo '<p style="margin-bottom: 5px"><b  style="color: #FF0000">Arquivo n&atilde;o localizado.</b></p>'; 
+								}
+							else
+								{
+									$data = file_get_contents($f);
+									$dados = Crl_parseASN($data);
+									echo '<br/><br/>Emitido por: ';
+									$aux = $dados[1][0][1][2][1]; // pega dados do emissor.
+									$aux = $aux[count($aux)-1];  // ultimo item he o do CN.....
+									echo $aux[1][1][1][1];
+									echo '<br/>Num. certificados: ';
+									$num = 0;
+									if(count($dados[1][0][1]) > 6)        // qtd de itens esperado he 7. o 6 contem os certificados revogados.
+										{
+											$num = count($dados[1][0][1][5][1]);  // pega o numero de certificados revogados na LCR.
+										}
+									echo $num; 
+									echo '<br/>LCR num. : ';
+									$oid_Num_crl = recupera_dados_oid($data,'2.5.29.20');  // oid que informa o numero de geracao da LCR.
+									$num = $oid_Num_crl[0][1][1][1];
+									if($num)
+										{
+											echo $num; 
+										}
+									else 
+										{
+											echo '0';
+										}
+									echo '<br>';
+									$di = data_hora($dados[1][0][1][3][1]);             // data, hora em que foi gerada a LCR.
+									$df = data_hora($dados[1][0][1][4][1]);		   // data, hora em que expira a LCR.							
+									if(gmdate("YmdHis") < $di)
+										{
+											$cor = 'style="color: #FF0000"';
+										}
+									else
+										{
+											$cor = 'style="color: #000066"';
+										}
+									echo '<p><b  ' . $cor . '>Gerada em : </b>' . substr($di,0,4) . '/' . substr($di,4,2) . '/' . substr($di,6,2) . '  -  ' . substr($di,8,2) . ':' . substr($di,10,2) . ':' . substr($di,12,2) . ' GMT</p>';
+									if(gmdate("YmdHis") > $df)
+										{
+											$cor = 'style="color: #FF0000" >Expirada em: ';
+										}
+									else
+										{
+											$cor = 'style="color: #000066" >Expira em: ';
+										}
+									echo '<p><b  ' . $cor . ' </b>' . substr($df,0,4) . '/' . substr($df,4,2) . '/' . substr($df,6,2) . '  -  ' . substr($df,8,2) . ':' . substr($df,10,2) . ':' . substr($df,12,2) . ' GMT</p>';									
+								}
+							echo  '</td></tr>';
+						}
+				}
+			echo '</table><br><br><br>';
+		}
+	
+
+		
+		
+	if($path2)
+		{
+			echo '<br><h2  style="color: #000066">Log da atualiza&ccedil;&atilde;o das LCR\'s:</h2>';	
+			echo '<div style="border: #000000 1px solid; overflow: auto; width: 770px; height:290px; white-space: pre; padding: 5px" >';
+			echo '<pre>';
+			if(is_file($path2))
+				{
+					$saida = array();
+					$ret = exec('cat ' . $path2 . ' | grep ' . date('Y-m-d') ,$saida);
+					foreach($saida as $linha)
+						{
+							echo $linha . chr(0x0A);
+						}
+				}
+			else
+				{
+					echo '<p style="margin-bottom: 5px"><b  style="color: #FF0000">Arquivo  ' . $path2 . '  n&atilde;o localizado.</b></p>'; 
+				}
+			echo '</pre>';
+			echo '</div><br><br>';
+		}
+?>
Index: /trunk/seguranca/simplepie.inc
===================================================================
--- /trunk/seguranca/simplepie.inc	(revision 1035)
+++ /trunk/seguranca/simplepie.inc	(revision 1035)
@@ -0,0 +1,13319 @@
+<?php
+/**
+ * SimplePie
+ *
+ * A PHP-Based RSS and Atom Feed Framework.
+ * Takes the hard work out of managing a complete RSS/Atom solution.
+ *
+ * Copyright (c) 2004-2008, Ryan Parman and Geoffrey Sneddon
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 	* Redistributions of source code must retain the above copyright notice, this list of
+ * 	  conditions and the following disclaimer.
+ *
+ * 	* Redistributions in binary form must reproduce the above copyright notice, this list
+ * 	  of conditions and the following disclaimer in the documentation and/or other materials
+ * 	  provided with the distribution.
+ *
+ * 	* Neither the name of the SimplePie Team nor the names of its contributors may be used
+ * 	  to endorse or promote products derived from this software without specific prior
+ * 	  written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+ * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * @package SimplePie
+ * @version 1.1.1
+ * @copyright 2004-2008 Ryan Parman, Geoffrey Sneddon
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @link http://simplepie.org/ SimplePie
+ * @link http://simplepie.org/support/ Please submit all bug reports and feature requests to the SimplePie forums
+ * @license http://www.opensource.org/licenses/bsd-license.php BSD License
+ * @todo phpDoc comments
+ */
+
+/**
+ * SimplePie Name
+ */
+define('SIMPLEPIE_NAME', 'SimplePie');
+
+/**
+ * SimplePie Version
+ */
+define('SIMPLEPIE_VERSION', '1.1.1');
+
+/**
+ * SimplePie Build
+ * @todo Hardcode for release (there's no need to have to call SimplePie_Misc::parse_date() only every load of simplepie.inc)
+ */
+define('SIMPLEPIE_BUILD', 20080315205903);
+//define('SIMPLEPIE_BUILD', gmdate('YmdHis', SimplePie_Misc::parse_date(substr('$Date: 2008-03-15 15:28:23 -0700 (Sat, 15 Mar 2008) $', 7, 25)) ? SimplePie_Misc::parse_date(substr('$Date: 2008-03-15 15:28:23 -0700 (Sat, 15 Mar 2008) $', 7, 25)) : filemtime(__FILE__)));
+
+/**
+ * SimplePie Website URL
+ */
+define('SIMPLEPIE_URL', 'http://simplepie.org');
+
+/**
+ * SimplePie Useragent
+ * @see SimplePie::set_useragent()
+ */
+define('SIMPLEPIE_USERAGENT', SIMPLEPIE_NAME . '/' . SIMPLEPIE_VERSION . ' (Feed Parser; ' . SIMPLEPIE_URL . '; Allow like Gecko) Build/' . SIMPLEPIE_BUILD);
+
+/**
+ * SimplePie Linkback
+ */
+define('SIMPLEPIE_LINKBACK', '<a href="' . SIMPLEPIE_URL . '" title="' . SIMPLEPIE_NAME . ' ' . SIMPLEPIE_VERSION . '">' . SIMPLEPIE_NAME . '</a>');
+
+/**
+ * No Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_NONE', 0);
+
+/**
+ * Feed Link Element Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_AUTODISCOVERY', 1);
+
+/**
+ * Local Feed Extension Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_LOCAL_EXTENSION', 2);
+
+/**
+ * Local Feed Body Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_LOCAL_BODY', 4);
+
+/**
+ * Remote Feed Extension Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_REMOTE_EXTENSION', 8);
+
+/**
+ * Remote Feed Body Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_REMOTE_BODY', 16);
+
+/**
+ * All Feed Autodiscovery
+ * @see SimplePie::set_autodiscovery_level()
+ */
+define('SIMPLEPIE_LOCATOR_ALL', 31);
+
+/**
+ * No known feed type
+ */
+define('SIMPLEPIE_TYPE_NONE', 0);
+
+/**
+ * RSS 0.90
+ */
+define('SIMPLEPIE_TYPE_RSS_090', 1);
+
+/**
+ * RSS 0.91 (Netscape)
+ */
+define('SIMPLEPIE_TYPE_RSS_091_NETSCAPE', 2);
+
+/**
+ * RSS 0.91 (Userland)
+ */
+define('SIMPLEPIE_TYPE_RSS_091_USERLAND', 4);
+
+/**
+ * RSS 0.91 (both Netscape and Userland)
+ */
+define('SIMPLEPIE_TYPE_RSS_091', 6);
+
+/**
+ * RSS 0.92
+ */
+define('SIMPLEPIE_TYPE_RSS_092', 8);
+
+/**
+ * RSS 0.93
+ */
+define('SIMPLEPIE_TYPE_RSS_093', 16);
+
+/**
+ * RSS 0.94
+ */
+define('SIMPLEPIE_TYPE_RSS_094', 32);
+
+/**
+ * RSS 1.0
+ */
+define('SIMPLEPIE_TYPE_RSS_10', 64);
+
+/**
+ * RSS 2.0
+ */
+define('SIMPLEPIE_TYPE_RSS_20', 128);
+
+/**
+ * RDF-based RSS
+ */
+define('SIMPLEPIE_TYPE_RSS_RDF', 65);
+
+/**
+ * Non-RDF-based RSS (truly intended as syndication format)
+ */
+define('SIMPLEPIE_TYPE_RSS_SYNDICATION', 190);
+
+/**
+ * All RSS
+ */
+define('SIMPLEPIE_TYPE_RSS_ALL', 255);
+
+/**
+ * Atom 0.3
+ */
+define('SIMPLEPIE_TYPE_ATOM_03', 256);
+
+/**
+ * Atom 1.0
+ */
+define('SIMPLEPIE_TYPE_ATOM_10', 512);
+
+/**
+ * All Atom
+ */
+define('SIMPLEPIE_TYPE_ATOM_ALL', 768);
+
+/**
+ * All feed types
+ */
+define('SIMPLEPIE_TYPE_ALL', 1023);
+
+/**
+ * No construct
+ */
+define('SIMPLEPIE_CONSTRUCT_NONE', 0);
+
+/**
+ * Text construct
+ */
+define('SIMPLEPIE_CONSTRUCT_TEXT', 1);
+
+/**
+ * HTML construct
+ */
+define('SIMPLEPIE_CONSTRUCT_HTML', 2);
+
+/**
+ * XHTML construct
+ */
+define('SIMPLEPIE_CONSTRUCT_XHTML', 4);
+
+/**
+ * base64-encoded construct
+ */
+define('SIMPLEPIE_CONSTRUCT_BASE64', 8);
+
+/**
+ * IRI construct
+ */
+define('SIMPLEPIE_CONSTRUCT_IRI', 16);
+
+/**
+ * A construct that might be HTML
+ */
+define('SIMPLEPIE_CONSTRUCT_MAYBE_HTML', 32);
+
+/**
+ * All constructs
+ */
+define('SIMPLEPIE_CONSTRUCT_ALL', 63);
+
+/**
+ * PCRE for HTML attributes
+ */
+define('SIMPLEPIE_PCRE_HTML_ATTRIBUTE', '((?:[\x09\x0A\x0B\x0C\x0D\x20]+[^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?)*)[\x09\x0A\x0B\x0C\x0D\x20]*');
+
+/**
+ * PCRE for XML attributes
+ */
+define('SIMPLEPIE_PCRE_XML_ATTRIBUTE', '((?:\s+(?:(?:[^\s:]+:)?[^\s:]+)\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'))*)\s*');
+
+/**
+ * XML Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_XML', 'http://www.w3.org/XML/1998/namespace');
+
+/**
+ * Atom 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ATOM_10', 'http://www.w3.org/2005/Atom');
+
+/**
+ * Atom 0.3 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ATOM_03', 'http://purl.org/atom/ns#');
+
+/**
+ * RDF Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RDF', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#');
+
+/**
+ * RSS 0.90 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_090', 'http://my.netscape.com/rdf/simple/0.9/');
+
+/**
+ * RSS 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_10', 'http://purl.org/rss/1.0/');
+
+/**
+ * RSS 1.0 Content Module Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT', 'http://purl.org/rss/1.0/modules/content/');
+
+/**
+ * DC 1.0 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_DC_10', 'http://purl.org/dc/elements/1.0/');
+
+/**
+ * DC 1.1 Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_DC_11', 'http://purl.org/dc/elements/1.1/');
+
+/**
+ * W3C Basic Geo (WGS84 lat/long) Vocabulary Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO', 'http://www.w3.org/2003/01/geo/wgs84_pos#');
+
+/**
+ * GeoRSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_GEORSS', 'http://www.georss.org/georss');
+
+/**
+ * Media RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS', 'http://search.yahoo.com/mrss/');
+
+/**
+ * Wrong Media RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG', 'http://search.yahoo.com/mrss');
+
+/**
+ * iTunes RSS Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_ITUNES', 'http://www.itunes.com/dtds/podcast-1.0.dtd');
+
+/**
+ * XHTML Namespace
+ */
+define('SIMPLEPIE_NAMESPACE_XHTML', 'http://www.w3.org/1999/xhtml');
+
+/**
+ * IANA Link Relations Registry
+ */
+define('SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY', 'http://www.iana.org/assignments/relation/');
+
+/**
+ * Whether we're running on PHP5
+ */
+define('SIMPLEPIE_PHP5', version_compare(PHP_VERSION, '5.0.0', '>='));
+
+/**
+ * No file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_NONE', 0);
+
+/**
+ * Remote file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_REMOTE', 1);
+
+/**
+ * Local file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_LOCAL', 2);
+
+/**
+ * fsockopen() file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_FSOCKOPEN', 4);
+
+/**
+ * cURL file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_CURL', 8);
+
+/**
+ * file_get_contents() file source
+ */
+define('SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS', 16);
+
+/**
+ * SimplePie
+ *
+ * @package SimplePie
+ * @version "Razzleberry"
+ * @copyright 2004-2007 Ryan Parman, Geoffrey Sneddon
+ * @author Ryan Parman
+ * @author Geoffrey Sneddon
+ * @todo Option for type of fetching (cache, not modified header, fetch, etc.)
+ */
+class SimplePie
+{
+	/**
+	 * @var array Raw data
+	 * @access private
+	 */
+	var $data = array();
+
+	/**
+	 * @var mixed Error string
+	 * @access private
+	 */
+	var $error;
+
+	/**
+	 * @var object Instance of SimplePie_Sanitize (or other class)
+	 * @see SimplePie::set_sanitize_class()
+	 * @access private
+	 */
+	var $sanitize;
+
+	/**
+	 * @var string SimplePie Useragent
+	 * @see SimplePie::set_useragent()
+	 * @access private
+	 */
+	var $useragent = SIMPLEPIE_USERAGENT;
+
+	/**
+	 * @var string Feed URL
+	 * @see SimplePie::set_feed_url()
+	 * @access private
+	 */
+	var $feed_url;
+
+	/**
+	 * @var object Instance of SimplePie_File to use as a feed
+	 * @see SimplePie::set_file()
+	 * @access private
+	 */
+	var $file;
+
+	/**
+	 * @var string Raw feed data
+	 * @see SimplePie::set_raw_data()
+	 * @access private
+	 */
+	var $raw_data;
+
+	/**
+	 * @var int Timeout for fetching remote files
+	 * @see SimplePie::set_timeout()
+	 * @access private
+	 */
+	var $timeout = 10;
+
+	/**
+	 * @var bool Forces fsockopen() to be used for remote files instead
+	 * of cURL, even if a new enough version is installed
+	 * @see SimplePie::force_fsockopen()
+	 * @access private
+	 */
+	var $force_fsockopen = false;
+
+	/**
+	 * @var bool Force the given data/URL to be treated as a feed no matter what
+	 * it appears like
+	 * @see SimplePie::force_feed()
+	 * @access private
+	 */
+	var $force_feed = false;
+
+	/**
+	 * @var bool Enable/Disable XML dump
+	 * @see SimplePie::enable_xml_dump()
+	 * @access private
+	 */
+	var $xml_dump = false;
+
+	/**
+	 * @var bool Enable/Disable Caching
+	 * @see SimplePie::enable_cache()
+	 * @access private
+	 */
+	var $cache = true;
+
+	/**
+	 * @var int Cache duration (in seconds)
+	 * @see SimplePie::set_cache_duration()
+	 * @access private
+	 */
+	var $cache_duration = 3600;
+
+	/**
+	 * @var int Auto-discovery cache duration (in seconds)
+	 * @see SimplePie::set_autodiscovery_cache_duration()
+	 * @access private
+	 */
+	var $autodiscovery_cache_duration = 604800; // 7 Days.
+
+	/**
+	 * @var string Cache location (relative to executing script)
+	 * @see SimplePie::set_cache_location()
+	 * @access private
+	 */
+	var $cache_location = './cache';
+
+	/**
+	 * @var string Function that creates the cache filename
+	 * @see SimplePie::set_cache_name_function()
+	 * @access private
+	 */
+	var $cache_name_function = 'md5';
+
+	/**
+	 * @var bool Reorder feed by date descending
+	 * @see SimplePie::enable_order_by_date()
+	 * @access private
+	 */
+	var $order_by_date = true;
+
+	/**
+	 * @var mixed Force input encoding to be set to the follow value
+	 * (false, or anything type-cast to false, disables this feature)
+	 * @see SimplePie::set_input_encoding()
+	 * @access private
+	 */
+	var $input_encoding = false;
+
+	/**
+	 * @var int Feed Autodiscovery Level
+	 * @see SimplePie::set_autodiscovery_level()
+	 * @access private
+	 */
+	var $autodiscovery = SIMPLEPIE_LOCATOR_ALL;
+
+	/**
+	 * @var string Class used for caching feeds
+	 * @see SimplePie::set_cache_class()
+	 * @access private
+	 */
+	var $cache_class = 'SimplePie_Cache';
+
+	/**
+	 * @var string Class used for locating feeds
+	 * @see SimplePie::set_locator_class()
+	 * @access private
+	 */
+	var $locator_class = 'SimplePie_Locator';
+
+	/**
+	 * @var string Class used for parsing feeds
+	 * @see SimplePie::set_parser_class()
+	 * @access private
+	 */
+	var $parser_class = 'SimplePie_Parser';
+
+	/**
+	 * @var string Class used for fetching feeds
+	 * @see SimplePie::set_file_class()
+	 * @access private
+	 */
+	var $file_class = 'SimplePie_File';
+
+	/**
+	 * @var string Class used for items
+	 * @see SimplePie::set_item_class()
+	 * @access private
+	 */
+	var $item_class = 'SimplePie_Item';
+
+	/**
+	 * @var string Class used for authors
+	 * @see SimplePie::set_author_class()
+	 * @access private
+	 */
+	var $author_class = 'SimplePie_Author';
+
+	/**
+	 * @var string Class used for categories
+	 * @see SimplePie::set_category_class()
+	 * @access private
+	 */
+	var $category_class = 'SimplePie_Category';
+
+	/**
+	 * @var string Class used for enclosures
+	 * @see SimplePie::set_enclosures_class()
+	 * @access private
+	 */
+	var $enclosure_class = 'SimplePie_Enclosure';
+
+	/**
+	 * @var string Class used for Media RSS <media:text> captions
+	 * @see SimplePie::set_caption_class()
+	 * @access private
+	 */
+	var $caption_class = 'SimplePie_Caption';
+
+	/**
+	 * @var string Class used for Media RSS <media:copyright>
+	 * @see SimplePie::set_copyright_class()
+	 * @access private
+	 */
+	var $copyright_class = 'SimplePie_Copyright';
+
+	/**
+	 * @var string Class used for Media RSS <media:credit>
+	 * @see SimplePie::set_credit_class()
+	 * @access private
+	 */
+	var $credit_class = 'SimplePie_Credit';
+
+	/**
+	 * @var string Class used for Media RSS <media:rating>
+	 * @see SimplePie::set_rating_class()
+	 * @access private
+	 */
+	var $rating_class = 'SimplePie_Rating';
+
+	/**
+	 * @var string Class used for Media RSS <media:restriction>
+	 * @see SimplePie::set_restriction_class()
+	 * @access private
+	 */
+	var $restriction_class = 'SimplePie_Restriction';
+
+	/**
+	 * @var string Class used for content-type sniffing
+	 * @see SimplePie::set_content_type_sniffer_class()
+	 * @access private
+	 */
+	var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
+
+	/**
+	 * @var string Class used for item sources.
+	 * @see SimplePie::set_source_class()
+	 * @access private
+	 */
+	var $source_class = 'SimplePie_Source';
+
+	/**
+	 * @var mixed Set javascript query string parameter (false, or
+	 * anything type-cast to false, disables this feature)
+	 * @see SimplePie::set_javascript()
+	 * @access private
+	 */
+	var $javascript = 'js';
+
+	/**
+	 * @var int Maximum number of feeds to check with autodiscovery
+	 * @see SimplePie::set_max_checked_feeds()
+	 * @access private
+	 */
+	var $max_checked_feeds = 10;
+
+	/**
+	 * @var string Web-accessible path to the handler_favicon.php file.
+	 * @see SimplePie::set_favicon_handler()
+	 * @access private
+	 */
+	var $favicon_handler = '';
+
+	/**
+	 * @var string Web-accessible path to the handler_image.php file.
+	 * @see SimplePie::set_image_handler()
+	 * @access private
+	 */
+	var $image_handler = '';
+
+	/**
+	 * @var array Stores the URLs when multiple feeds are being initialized.
+	 * @see SimplePie::set_feed_url()
+	 * @access private
+	 */
+	var $multifeed_url = array();
+
+	/**
+	 * @var array Stores SimplePie objects when multiple feeds initialized.
+	 * @access private
+	 */
+	var $multifeed_objects = array();
+
+	/**
+	 * @var array Stores the get_object_vars() array for use with multifeeds.
+	 * @see SimplePie::set_feed_url()
+	 * @access private
+	 */
+	var $config_settings = null;
+
+	/**
+	 * @var integer Stores the number of items to return per-feed with multifeeds.
+	 * @see SimplePie::set_item_limit()
+	 * @access private
+	 */
+	var $item_limit = 0;
+
+	/**
+	 * @var array Stores the default attributes to be stripped by strip_attributes().
+	 * @see SimplePie::strip_attributes()
+	 * @access private
+	 */
+	var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+
+	/**
+	 * @var array Stores the default tags to be stripped by strip_htmltags().
+	 * @see SimplePie::strip_htmltags()
+	 * @access private
+	 */
+	var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+
+	/**
+	 * The SimplePie class contains feed level data and options
+	 *
+	 * There are two ways that you can create a new SimplePie object. The first
+	 * is by passing a feed URL as a parameter to the SimplePie constructor
+	 * (as well as optionally setting the cache location and cache expiry). This
+	 * will initialise the whole feed with all of the default settings, and you
+	 * can begin accessing methods and properties immediately.
+	 *
+	 * The second way is to create the SimplePie object with no parameters
+	 * at all. This will enable you to set configuration options. After setting
+	 * them, you must initialise the feed using $feed->init(). At that point the
+	 * object's methods and properties will be available to you. This format is
+	 * what is used throughout this documentation.
+	 *
+	 * @access public
+	 * @since 1.0 Preview Release
+	 * @param string $feed_url This is the URL you want to parse.
+	 * @param string $cache_location This is where you want the cache to be stored.
+	 * @param int $cache_duration This is the number of seconds that you want to store the cache file for.
+	 */
+	function SimplePie($feed_url = null, $cache_location = null, $cache_duration = null)
+	{
+		// Other objects, instances created here so we can set options on them
+		$this->sanitize =& new SimplePie_Sanitize;
+
+		// Set options if they're passed to the constructor
+		if ($cache_location !== null)
+		{
+			$this->set_cache_location($cache_location);
+		}
+
+		if ($cache_duration !== null)
+		{
+			$this->set_cache_duration($cache_duration);
+		}
+
+		// Only init the script if we're passed a feed URL
+		if ($feed_url !== null)
+		{
+			$this->set_feed_url($feed_url);
+			$this->init();
+		}
+	}
+
+	/**
+	 * Used for converting object to a string
+	 */
+	function __toString()
+	{
+		return md5(serialize($this->data));
+	}
+	
+	/**
+	 * Remove items that link back to this before destroying this object
+	 */
+	function __destruct()
+	{
+		if (!empty($this->data['items']))
+		{
+			foreach ($this->data['items'] as $item)
+			{
+				$item->__destruct();
+			}
+			unset($this->data['items']);
+		}
+		if (!empty($this->data['ordered_items']))
+		{
+			foreach ($this->data['ordered_items'] as $item)
+			{
+				$item->__destruct();
+			}
+			unset($this->data['ordered_items']);
+		}
+	}
+	
+	/**
+	 * Force the given data/URL to be treated as a feed no matter what it
+	 * appears like
+	 *
+	 * @access public
+	 * @since 1.1
+	 * @param bool $enable Force the given data/URL to be treated as a feed
+	 */
+	function force_feed($enable = false)
+	{
+		$this->force_feed = (bool) $enable;
+	}
+
+	/**
+	 * This is the URL of the feed you want to parse.
+	 *
+	 * This allows you to enter the URL of the feed you want to parse, or the
+	 * website you want to try to use auto-discovery on. This takes priority
+	 * over any set raw data.
+	 *
+	 * You can set multiple feeds to mash together by passing an array instead
+	 * of a string for the $url. Remember that with each additional feed comes
+	 * additional processing and resources.
+	 *
+	 * @access public
+	 * @since 1.0 Preview Release
+	 * @param mixed $url This is the URL (or array of URLs) that you want to parse.
+	 * @see SimplePie::set_raw_data()
+	 */
+	function set_feed_url($url)
+	{
+		if (is_array($url))
+		{
+			$this->multifeed_url = array();
+			foreach ($url as $value)
+			{
+				$this->multifeed_url[] = SimplePie_Misc::fix_protocol($value, 1);
+			}
+		}
+		else
+		{
+			$this->feed_url = SimplePie_Misc::fix_protocol($url, 1);
+		}
+	}
+
+	/**
+	 * Provides an instance of SimplePie_File to use as a feed
+	 *
+	 * @access public
+	 * @param object &$file Instance of SimplePie_File (or subclass)
+	 * @return bool True on success, false on failure
+	 */
+	function set_file(&$file)
+	{
+		if (is_a($file, 'SimplePie_File'))
+		{
+			$this->feed_url = $file->url;
+			$this->file =& $file;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to use a string of RSS/Atom data instead of a remote feed.
+	 *
+	 * If you have a feed available as a string in PHP, you can tell SimplePie
+	 * to parse that data string instead of a remote feed. Any set feed URL
+	 * takes precedence.
+	 *
+	 * @access public
+	 * @since 1.0 Beta 3
+	 * @param string $data RSS or Atom data as a string.
+	 * @see SimplePie::set_feed_url()
+	 */
+	function set_raw_data($data)
+	{
+		$this->raw_data = $data;
+	}
+
+	/**
+	 * Allows you to override the default timeout for fetching remote feeds.
+	 *
+	 * This allows you to change the maximum time the feed's server to respond
+	 * and send the feed back.
+	 *
+	 * @access public
+	 * @since 1.0 Beta 3
+	 * @param int $timeout The maximum number of seconds to spend waiting to retrieve a feed.
+	 */
+	function set_timeout($timeout = 10)
+	{
+		$this->timeout = (int) $timeout;
+	}
+
+	/**
+	 * Forces SimplePie to use fsockopen() instead of the preferred cURL
+	 * functions.
+	 *
+	 * @access public
+	 * @since 1.0 Beta 3
+	 * @param bool $enable Force fsockopen() to be used
+	 */
+	function force_fsockopen($enable = false)
+	{
+		$this->force_fsockopen = (bool) $enable;
+	}
+
+	/**
+	 * Outputs the raw XML content of the feed, after it has gone through
+	 * SimplePie's filters.
+	 *
+	 * Used only for debugging, this function will output the XML content as
+	 * text/xml. When SimplePie reads in a feed, it does a bit of cleaning up
+	 * before trying to parse it. Many parts of the feed are re-written in
+	 * memory, and in the end, you have a parsable feed. XML dump shows you the
+	 * actual XML that SimplePie tries to parse, which may or may not be very
+	 * different from the original feed.
+	 *
+	 * @access public
+	 * @since 1.0 Preview Release
+	 * @param bool $enable Enable XML dump
+	 */
+	function enable_xml_dump($enable = false)
+	{
+		$this->xml_dump = (bool) $enable;
+	}
+
+	/**
+	 * Enables/disables caching in SimplePie.
+	 *
+	 * This option allows you to disable caching all-together in SimplePie.
+	 * However, disabling the cache can lead to longer load times.
+	 *
+	 * @access public
+	 * @since 1.0 Preview Release
+	 * @param bool $enable Enable caching
+	 */
+	function enable_cache($enable = true)
+	{
+		$this->cache = (bool) $enable;
+	}
+
+	/**
+	 * Set the length of time (in seconds) that the contents of a feed
+	 * will be cached.
+	 *
+	 * @access public
+	 * @param int $seconds The feed content cache duration.
+	 */
+	function set_cache_duration($seconds = 3600)
+	{
+		$this->cache_duration = (int) $seconds;
+	}
+
+	/**
+	 * Set the length of time (in seconds) that the autodiscovered feed
+	 * URL will be cached.
+	 *
+	 * @access public
+	 * @param int $seconds The autodiscovered feed URL cache duration.
+	 */
+	function set_autodiscovery_cache_duration($seconds = 604800)
+	{
+		$this->autodiscovery_cache_duration = (int) $seconds;
+	}
+
+	/**
+	 * Set the file system location where the cached files should be stored.
+	 *
+	 * @access public
+	 * @param string $location The file system location.
+	 */
+	function set_cache_location($location = './cache')
+	{
+		$this->cache_location = (string) $location;
+	}
+
+	/**
+	 * Determines whether feed items should be sorted into reverse chronological order.
+	 *
+	 * @access public
+	 * @param bool $enable Sort as reverse chronological order.
+	 */
+	function enable_order_by_date($enable = true)
+	{
+		$this->order_by_date = (bool) $enable;
+	}
+
+	/**
+	 * Allows you to override the character encoding reported by the feed.
+	 *
+	 * @access public
+	 * @param string $encoding Character encoding.
+	 */
+	function set_input_encoding($encoding = false)
+	{
+		if ($encoding)
+		{
+			$this->input_encoding = (string) $encoding;
+		}
+		else
+		{
+			$this->input_encoding = false;
+		}
+	}
+
+	/**
+	 * Set how much feed autodiscovery to do
+	 *
+	 * @access public
+	 * @see SIMPLEPIE_LOCATOR_NONE
+	 * @see SIMPLEPIE_LOCATOR_AUTODISCOVERY
+	 * @see SIMPLEPIE_LOCATOR_LOCAL_EXTENSION
+	 * @see SIMPLEPIE_LOCATOR_LOCAL_BODY
+	 * @see SIMPLEPIE_LOCATOR_REMOTE_EXTENSION
+	 * @see SIMPLEPIE_LOCATOR_REMOTE_BODY
+	 * @see SIMPLEPIE_LOCATOR_ALL
+	 * @param int $level Feed Autodiscovery Level (level can be a
+	 * combination of the above constants, see bitwise OR operator)
+	 */
+	function set_autodiscovery_level($level = SIMPLEPIE_LOCATOR_ALL)
+	{
+		$this->autodiscovery = (int) $level;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for caching.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_cache_class($class = 'SimplePie_Cache')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Cache'))
+		{
+			$this->cache_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for auto-discovery.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_locator_class($class = 'SimplePie_Locator')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Locator'))
+		{
+			$this->locator_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for XML parsing.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_parser_class($class = 'SimplePie_Parser')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Parser'))
+		{
+			$this->parser_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for remote file fetching.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_file_class($class = 'SimplePie_File')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_File'))
+		{
+			$this->file_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for data sanitization.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_sanitize_class($class = 'SimplePie_Sanitize')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Sanitize'))
+		{
+			$this->sanitize =& new $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for handling feed items.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_item_class($class = 'SimplePie_Item')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Item'))
+		{
+			$this->item_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for handling author data.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_author_class($class = 'SimplePie_Author')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Author'))
+		{
+			$this->author_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for handling category data.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_category_class($class = 'SimplePie_Category')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Category'))
+		{
+			$this->category_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for feed enclosures.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_enclosure_class($class = 'SimplePie_Enclosure')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Enclosure'))
+		{
+			$this->enclosure_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for <media:text> captions
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_caption_class($class = 'SimplePie_Caption')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Caption'))
+		{
+			$this->caption_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for <media:copyright>
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_copyright_class($class = 'SimplePie_Copyright')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Copyright'))
+		{
+			$this->copyright_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for <media:credit>
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_credit_class($class = 'SimplePie_Credit')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Credit'))
+		{
+			$this->credit_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for <media:rating>
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_rating_class($class = 'SimplePie_Rating')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Rating'))
+		{
+			$this->rating_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for <media:restriction>
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_restriction_class($class = 'SimplePie_Restriction')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Restriction'))
+		{
+			$this->restriction_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses for content-type sniffing.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_content_type_sniffer_class($class = 'SimplePie_Content_Type_Sniffer')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Content_Type_Sniffer'))
+		{
+			$this->content_type_sniffer_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to change which class SimplePie uses item sources.
+	 * Useful when you are overloading or extending SimplePie's default classes.
+	 *
+	 * @access public
+	 * @param string $class Name of custom class.
+	 * @link http://php.net/manual/en/keyword.extends.php PHP4 extends documentation
+	 * @link http://php.net/manual/en/language.oop5.basic.php#language.oop5.basic.extends PHP5 extends documentation
+	 */
+	function set_source_class($class = 'SimplePie_Source')
+	{
+		if (SimplePie_Misc::is_subclass_of($class, 'SimplePie_Source'))
+		{
+			$this->source_class = $class;
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Allows you to override the default user agent string.
+	 *
+	 * @access public
+	 * @param string $ua New user agent string.
+	 */
+	function set_useragent($ua = SIMPLEPIE_USERAGENT)
+	{
+		$this->useragent = (string) $ua;
+	}
+
+	/**
+	 * Set callback function to create cache filename with
+	 *
+	 * @access public
+	 * @param mixed $function Callback function
+	 */
+	function set_cache_name_function($function = 'md5')
+	{
+		if (is_callable($function))
+		{
+			$this->cache_name_function = $function;
+		}
+	}
+
+	/**
+	 * Set javascript query string parameter
+	 *
+	 * @access public
+	 * @param mixed $get Javascript query string parameter
+	 */
+	function set_javascript($get = 'js')
+	{
+		if ($get)
+		{
+			$this->javascript = (string) $get;
+		}
+		else
+		{
+			$this->javascript = false;
+		}
+	}
+
+	/**
+	 * Set options to make SP as fast as possible.  Forgoes a
+	 * substantial amount of data sanitization in favor of speed.
+	 *
+	 * @access public
+	 * @param bool $set Whether to set them or not
+	 */
+	function set_stupidly_fast($set = false)
+	{
+		if ($set)
+		{
+			$this->enable_order_by_date(false);
+			$this->remove_div(false);
+			$this->strip_comments(false);
+			$this->strip_htmltags(false);
+			$this->strip_attributes(false);
+			$this->set_image_handler(false);
+		}
+	}
+
+	/**
+	 * Set maximum number of feeds to check with autodiscovery
+	 *
+	 * @access public
+	 * @param int $max Maximum number of feeds to check
+	 */
+	function set_max_checked_feeds($max = 10)
+	{
+		$this->max_checked_feeds = (int) $max;
+	}
+
+	function remove_div($enable = true)
+	{
+		$this->sanitize->remove_div($enable);
+	}
+
+	function strip_htmltags($tags = '', $encode = null)
+	{
+		if ($tags === '')
+		{
+			$tags = $this->strip_htmltags;
+		}
+		$this->sanitize->strip_htmltags($tags);
+		if ($encode !== null)
+		{
+			$this->sanitize->encode_instead_of_strip($tags);
+		}
+	}
+
+	function encode_instead_of_strip($enable = true)
+	{
+		$this->sanitize->encode_instead_of_strip($enable);
+	}
+
+	function strip_attributes($attribs = '')
+	{
+		if ($attribs === '')
+		{
+			$attribs = $this->strip_attributes;
+		}
+		$this->sanitize->strip_attributes($attribs);
+	}
+
+	function set_output_encoding($encoding = 'UTF-8')
+	{
+		$this->sanitize->set_output_encoding($encoding);
+	}
+
+	function strip_comments($strip = false)
+	{
+		$this->sanitize->strip_comments($strip);
+	}
+
+	/**
+	 * Set element/attribute key/value pairs of HTML attributes
+	 * containing URLs that need to be resolved relative to the feed
+	 *
+	 * @access public
+	 * @since 1.0
+	 * @param array $element_attribute Element/attribute key/value pairs
+	 */
+	function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
+	{
+		$this->sanitize->set_url_replacements($element_attribute);
+	}
+
+	/**
+	 * Set the handler to enable the display of cached favicons.
+	 *
+	 * @access public
+	 * @param str $page Web-accessible path to the handler_favicon.php file.
+	 * @param str $qs The query string that the value should be passed to.
+	 */
+	function set_favicon_handler($page = false, $qs = 'i')
+	{
+		if ($page != false)
+		{
+			$this->favicon_handler = $page . '?' . $qs . '=';
+		}
+		else
+		{
+			$this->favicon_handler = '';
+		}
+	}
+
+	/**
+	 * Set the handler to enable the display of cached images.
+	 *
+	 * @access public
+	 * @param str $page Web-accessible path to the handler_image.php file.
+	 * @param str $qs The query string that the value should be passed to.
+	 */
+	function set_image_handler($page = false, $qs = 'i')
+	{
+		if ($page != false)
+		{
+			$this->sanitize->set_image_handler($page . '?' . $qs . '=');
+		}
+		else
+		{
+			$this->image_handler = '';
+		}
+	}
+
+	/**
+	 * Set the limit for items returned per-feed with multifeeds.
+	 *
+	 * @access public
+	 * @param integer $limit The maximum number of items to return.
+	 */
+	function set_item_limit($limit = 0)
+	{
+		$this->item_limit = (int) $limit;
+	}
+
+	function init()
+	{
+		if ((function_exists('version_compare') && version_compare(PHP_VERSION, '4.3.0', '<')) || !extension_loaded('xml') || !extension_loaded('pcre'))
+		{
+			return false;
+		}
+		if (isset($_GET[$this->javascript]))
+		{
+			if (function_exists('ob_gzhandler'))
+			{
+				ob_start('ob_gzhandler');
+			}
+			header('Content-type: text/javascript; charset: UTF-8');
+			header('Cache-Control: must-revalidate');
+			header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
+			?>
+function embed_odeo(link) {
+	document.writeln('<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url='+link+'"></embed>');
+}
+
+function embed_quicktime(type, bgcolor, width, height, link, placeholder, loop) {
+	if (placeholder != '') {
+		document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" href="'+link+'" src="'+placeholder+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="false" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
+	}
+	else {
+		document.writeln('<embed type="'+type+'" style="cursor:hand; cursor:pointer;" src="'+link+'" width="'+width+'" height="'+height+'" autoplay="false" target="myself" controller="true" loop="'+loop+'" scale="aspect" bgcolor="'+bgcolor+'" pluginspage="http://www.apple.com/quicktime/download/"></embed>');
+	}
+}
+
+function embed_flash(bgcolor, width, height, link, loop, type) {
+	document.writeln('<embed src="'+link+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="'+type+'" quality="high" width="'+width+'" height="'+height+'" bgcolor="'+bgcolor+'" loop="'+loop+'"></embed>');
+}
+
+function embed_flv(width, height, link, placeholder, loop, player) {
+	document.writeln('<embed src="'+player+'" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="'+width+'" height="'+height+'" wmode="transparent" flashvars="file='+link+'&autostart=false&repeat='+loop+'&showdigits=true&showfsbutton=false"></embed>');
+}
+
+function embed_wmedia(width, height, link) {
+	document.writeln('<embed type="application/x-mplayer2" src="'+link+'" autosize="1" width="'+width+'" height="'+height+'" showcontrols="1" showstatusbar="0" showdisplay="0" autostart="0"></embed>');
+}
+			<?php
+			exit;
+		}
+
+		// Pass whatever was set with config options over to the sanitizer.
+		$this->sanitize->pass_cache_data($this->cache, $this->cache_location, $this->cache_name_function, $this->cache_class);
+		$this->sanitize->pass_file_data($this->file_class, $this->timeout, $this->useragent, $this->force_fsockopen);
+
+		if ($this->feed_url !== null || $this->raw_data !== null)
+		{
+			$this->data = array();
+			$this->multifeed_objects = array();
+			$cache = false;
+
+			if ($this->feed_url !== null)
+			{
+				$parsed_feed_url = SimplePie_Misc::parse_url($this->feed_url);
+				// Decide whether to enable caching
+				if ($this->cache && $parsed_feed_url['scheme'] !== '')
+				{
+					$cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $this->feed_url), 'spc');
+				}
+				// If it's enabled and we don't want an XML dump, use the cache
+				if ($cache && !$this->xml_dump)
+				{
+					// Load the Cache
+					$this->data = $cache->load();
+					if (!empty($this->data))
+					{
+						// If the cache is for an outdated build of SimplePie
+						if (!isset($this->data['build']) || $this->data['build'] != SIMPLEPIE_BUILD)
+						{
+							$cache->unlink();
+							$this->data = array();
+						}
+						// If we've hit a collision just rerun it with caching disabled
+						elseif (isset($this->data['url']) && $this->data['url'] != $this->feed_url)
+						{
+							$cache = false;
+							$this->data = array();
+						}
+						// If we've got a non feed_url stored (if the page isn't actually a feed, or is a redirect) use that URL.
+						elseif (isset($this->data['feed_url']))
+						{
+							// If the autodiscovery cache is still valid use it.
+							if ($cache->mtime() + $this->autodiscovery_cache_duration > time())
+							{
+								// Do not need to do feed autodiscovery yet.
+								if ($this->data['feed_url'] == $this->data['url'])
+								{
+									$cache->unlink();
+									$this->data = array();
+								}
+								else
+								{
+									$this->set_feed_url($this->data['feed_url']);
+									return $this->init();
+								}
+							}
+						}
+						// Check if the cache has been updated
+						elseif ($cache->mtime() + $this->cache_duration < time())
+						{
+							// If we have last-modified and/or etag set
+							if (isset($this->data['headers']['last-modified']) || isset($this->data['headers']['etag']))
+							{
+								$headers = array();
+								if (isset($this->data['headers']['last-modified']))
+								{
+									$headers['if-modified-since'] = $this->data['headers']['last-modified'];
+								}
+								if (isset($this->data['headers']['etag']))
+								{
+									$headers['if-none-match'] = '"' . $this->data['headers']['etag'] . '"';
+								}
+								$file =& new $this->file_class($this->feed_url, $this->timeout/10, 5, $headers, $this->useragent, $this->force_fsockopen);
+								if ($file->success)
+								{
+									if ($file->status_code == 304)
+									{
+										$cache->touch();
+										return true;
+									}
+									else
+									{
+										$headers = $file->headers;
+									}
+								}
+								else
+								{
+									unset($file);
+								}
+							}
+						}
+						// If the cache is still valid, just return true
+						else
+						{
+							return true;
+						}
+					}
+					// If the cache is empty, delete it
+					else
+					{
+						$cache->unlink();
+						$this->data = array();
+					}
+				}
+				// If we don't already have the file (it'll only exist if we've opened it to check if the cache has been modified), open it.
+				if (!isset($file))
+				{
+					if (is_a($this->file, 'SimplePie_File') && $this->file->url == $this->feed_url)
+					{
+						$file =& $this->file;
+					}
+					else
+					{
+						$file =& new $this->file_class($this->feed_url, $this->timeout, 5, null, $this->useragent, $this->force_fsockopen);
+					}
+				}
+				// If the file connection has an error, set SimplePie::error to that and quit
+				if (!$file->success)
+				{
+					$this->error = $file->error;
+					if (!empty($this->data))
+					{
+						return true;
+					}
+					else
+					{
+						return false;
+					}
+				}
+
+				if (!$this->force_feed)
+				{
+					// Check if the supplied URL is a feed, if it isn't, look for it.
+					$locate =& new $this->locator_class($file, $this->timeout, $this->useragent, $this->file_class, $this->max_checked_feeds, $this->content_type_sniffer_class);
+					if (!$locate->is_feed($file))
+					{
+						// We need to unset this so that if SimplePie::set_file() has been called that object is untouched
+						unset($file);
+						if ($file = $locate->find($this->autodiscovery))
+						{
+							if ($cache)
+							{
+								$this->data = array('url' => $this->feed_url, 'feed_url' => $file->url, 'build' => SIMPLEPIE_BUILD);
+								if (!$cache->save($this))
+								{
+									trigger_error("$cache->name is not writeable", E_USER_WARNING);
+								}
+								$cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, call_user_func($this->cache_name_function, $file->url), 'spc');
+							}
+							$this->feed_url = $file->url;
+						}
+						else
+						{
+							$this->error = "A feed could not be found at $this->feed_url";
+							SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
+							return false;
+						}
+					}
+					$locate = null;
+				}
+
+				$headers = $file->headers;
+				$data = $file->body;
+				$sniffer = new $this->content_type_sniffer_class($file);
+				$sniffed = $sniffer->get_type();
+			}
+			else
+			{
+				$data = $this->raw_data;
+			}
+			
+			// Set up array of possible encodings
+			$encodings = array();
+
+			// First check to see if input has been overridden.
+			if ($this->input_encoding !== false)
+			{
+				$encodings[] = $this->input_encoding;
+			}
+			
+			$application_types = array('application/xml', 'application/xml-dtd', 'application/xml-external-parsed-entity');
+			$text_types = array('text/xml', 'text/xml-external-parsed-entity');
+			
+			// RFC 3023 (only applies to sniffed content)
+			if (isset($sniffed))
+			{
+				if (in_array($sniffed, $application_types) || substr($sniffed, 0, 12) === 'application/' && substr($sniffed, -4) === '+xml')
+				{
+					if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+					{
+						$encodings[] = strtoupper($charset[1]);
+					}
+					$encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
+					$encodings[] = 'UTF-8';
+				}
+				elseif (in_array($sniffed, $text_types) || substr($sniffed, 0, 5) === 'text/' && substr($sniffed, -4) === '+xml')
+				{
+					if (isset($headers['content-type']) && preg_match('/;\x20?charset=([^;]*)/i', $headers['content-type'], $charset))
+					{
+						$encodings[] = $charset[1];
+					}
+					$encodings[] = 'US-ASCII';
+				}
+				// Text MIME-type default
+				elseif (substr($sniffed, 0, 5) === 'text/')
+				{
+					$encodings[] = 'US-ASCII';
+				}
+			}
+			
+			// Fallback to XML 1.0 Appendix F.1/UTF-8/ISO-8859-1
+			$encodings = array_merge($encodings, SimplePie_Misc::xml_encoding($data));
+			$encodings[] = 'UTF-8';
+			$encodings[] = 'ISO-8859-1';
+			
+			// There's no point in trying an encoding twice
+			$encodings = array_unique($encodings);
+			
+			// If we want the XML, just output that with the most likely encoding and quit
+			if ($this->xml_dump)
+			{
+				header('Content-type: text/xml; charset=' . $encodings[0]);
+				echo $data;
+				exit;
+			}
+			
+			// Loop through each possible encoding, till we return something, or run out of possibilities
+			foreach ($encodings as $encoding)
+			{
+				// Change the encoding to UTF-8 (as we always use UTF-8 internally)
+				$utf8_data = SimplePie_Misc::change_encoding($data, $encoding, 'UTF-8');
+
+				// Create new parser
+				$parser =& new $this->parser_class();
+				
+				// If it's parsed fine
+				if ($parser->parse($utf8_data, 'UTF-8'))
+				{
+					$this->data = $parser->get_data();
+					if (isset($this->data['child']))
+					{
+						if (isset($headers))
+						{
+							$this->data['headers'] = $headers;
+						}
+						$this->data['build'] = SIMPLEPIE_BUILD;
+	
+						// Cache the file if caching is enabled
+						if ($cache && !$cache->save($this))
+						{
+							trigger_error("$cache->name is not writeable", E_USER_WARNING);
+						}
+						return true;
+					}
+					else
+					{
+						$this->error = "A feed could not be found at $this->feed_url";
+						SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
+						return false;
+					}
+				}
+			}
+			// We have an error, just set SimplePie::error to it and quit
+			$this->error = sprintf('XML error: %s at line %d, column %d', $parser->get_error_string(), $parser->get_current_line(), $parser->get_current_column());
+			SimplePie_Misc::error($this->error, E_USER_NOTICE, __FILE__, __LINE__);
+			return false;
+		}
+		elseif (!empty($this->multifeed_url))
+		{
+			$i = 0;
+			$success = 0;
+			$this->multifeed_objects = array();
+			foreach ($this->multifeed_url as $url)
+			{
+				if (SIMPLEPIE_PHP5)
+				{
+					// This keyword needs to defy coding standards for PHP4 compatibility
+					$this->multifeed_objects[$i] = clone($this);
+				}
+				else
+				{
+					$this->multifeed_objects[$i] = $this;
+				}
+				$this->multifeed_objects[$i]->set_feed_url($url);
+				$success |= $this->multifeed_objects[$i]->init();
+				$i++;
+			}
+			return (bool) $success;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * Return the error message for the occured error
+	 *
+	 * @access public
+	 * @return string Error message
+	 */
+	function error()
+	{
+		return $this->error;
+	}
+
+	function get_encoding()
+	{
+		return $this->sanitize->output_encoding;
+	}
+
+	function handle_content_type($mime = 'text/html')
+	{
+		if (!headers_sent())
+		{
+			$header = "Content-type: $mime;";
+			if ($this->get_encoding())
+			{
+				$header .= ' charset=' . $this->get_encoding();
+			}
+			else
+			{
+				$header .= ' charset=UTF-8';
+			}
+			header($header);
+		}
+	}
+
+	function get_type()
+	{
+		if (!isset($this->data['type']))
+		{
+			$this->data['type'] = SIMPLEPIE_TYPE_ALL;
+			if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed']))
+			{
+				$this->data['type'] &= SIMPLEPIE_TYPE_ATOM_10;
+			}
+			elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed']))
+			{
+				$this->data['type'] &= SIMPLEPIE_TYPE_ATOM_03;
+			}
+			elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF']))
+			{
+				if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['channel'])
+				|| isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['image'])
+				|| isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['item'])
+				|| isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_10]['textinput']))
+				{
+					$this->data['type'] &= SIMPLEPIE_TYPE_RSS_10;
+				}
+				if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['channel'])
+				|| isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['image'])
+				|| isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['item'])
+				|| isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][SIMPLEPIE_NAMESPACE_RSS_090]['textinput']))
+				{
+					$this->data['type'] &= SIMPLEPIE_TYPE_RSS_090;
+				}
+			}
+			elseif (isset($this->data['child']['']['rss']))
+			{
+				$this->data['type'] &= SIMPLEPIE_TYPE_RSS_ALL;
+				if (isset($this->data['child']['']['rss'][0]['attribs']['']['version']))
+				{
+					switch (trim($this->data['child']['']['rss'][0]['attribs']['']['version']))
+					{
+						case '0.91':
+							$this->data['type'] &= SIMPLEPIE_TYPE_RSS_091;
+							if (isset($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data']))
+							{
+								switch (trim($this->data['child']['']['rss'][0]['child']['']['skiphours']['hour'][0]['data']))
+								{
+									case '0':
+										$this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_NETSCAPE;
+										break;
+
+									case '24':
+										$this->data['type'] &= SIMPLEPIE_TYPE_RSS_091_USERLAND;
+										break;
+								}
+							}
+							break;
+
+						case '0.92':
+							$this->data['type'] &= SIMPLEPIE_TYPE_RSS_092;
+							break;
+
+						case '0.93':
+							$this->data['type'] &= SIMPLEPIE_TYPE_RSS_093;
+							break;
+
+						case '0.94':
+							$this->data['type'] &= SIMPLEPIE_TYPE_RSS_094;
+							break;
+
+						case '2.0':
+							$this->data['type'] &= SIMPLEPIE_TYPE_RSS_20;
+							break;
+					}
+				}
+			}
+			else
+			{
+				$this->data['type'] = SIMPLEPIE_TYPE_NONE;
+			}
+		}
+		return $this->data['type'];
+	}
+
+	/**
+	 * Returns the URL for the favicon of the feed's website.
+	 *
+	 * @todo Cache atom:icon
+	 * @access public
+	 * @since 1.0
+	 */
+	function get_favicon()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif (($url = $this->get_link()) !== null && preg_match('/^http(s)?:\/\//i', $url))
+		{
+			$favicon = SimplePie_Misc::absolutize_url('/favicon.ico', $url);
+
+			if ($this->cache && $this->favicon_handler)
+			{
+				$favicon_filename = call_user_func($this->cache_name_function, $favicon);
+				$cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $favicon_filename, 'spi');
+
+				if ($cache->load())
+				{
+					return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
+				}
+				else
+				{
+					$file =& new $this->file_class($favicon, $this->timeout / 10, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
+
+					if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300)) && strlen($file->body) > 0)
+					{
+						$sniffer = new $this->content_type_sniffer_class($file);
+						if (substr($sniffer->get_type(), 0, 6) === 'image/')
+						{
+							if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
+							{
+								return $this->sanitize($this->favicon_handler . $favicon_filename, SIMPLEPIE_CONSTRUCT_IRI);
+							}
+							else
+							{
+								trigger_error("$cache->name is not writeable", E_USER_WARNING);
+								return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
+							}
+						}
+					}
+				}
+			}
+			else
+			{
+				return $this->sanitize($favicon, SIMPLEPIE_CONSTRUCT_IRI);
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * @todo If we have a perm redirect we should return the new URL
+	 * @todo When we make the above change, let's support <itunes:new-feed-url> as well
+	 * @todo Also, |atom:link|@rel=self
+	 */
+	function subscribe_url()
+	{
+		if ($this->feed_url !== null)
+		{
+			return $this->sanitize($this->feed_url, SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function subscribe_feed()
+	{
+		if ($this->feed_url !== null)
+		{
+			return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function subscribe_outlook()
+	{
+		if ($this->feed_url !== null)
+		{
+			return 'outlook' . $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 2), SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function subscribe_podcast()
+	{
+		if ($this->feed_url !== null)
+		{
+			return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 3), SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function subscribe_itunes()
+	{
+		if ($this->feed_url !== null)
+		{
+			return $this->sanitize(SimplePie_Misc::fix_protocol($this->feed_url, 4), SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * Creates the subscribe_* methods' return data
+	 *
+	 * @access private
+	 * @param string $feed_url String to prefix to the feed URL
+	 * @param string $site_url String to prefix to the site URL (and
+	 * suffix to the feed URL)
+	 * @return mixed URL if feed exists, false otherwise
+	 */
+	function subscribe_service($feed_url, $site_url = null)
+	{
+		if ($this->subscribe_url())
+		{
+			$return = $this->sanitize($feed_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->feed_url);
+			if ($site_url !== null && $this->get_link() !== null)
+			{
+				$return .= $this->sanitize($site_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_link());
+			}
+			return $return;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function subscribe_aol()
+	{
+		return $this->subscribe_service('http://feeds.my.aol.com/add.jsp?url=');
+	}
+
+	function subscribe_bloglines()
+	{
+		return urldecode($this->subscribe_service('http://www.bloglines.com/sub/'));
+	}
+
+	function subscribe_eskobo()
+	{
+		return $this->subscribe_service('http://www.eskobo.com/?AddToMyPage=');
+	}
+
+	function subscribe_feedfeeds()
+	{
+		return $this->subscribe_service('http://www.feedfeeds.com/add?feed=');
+	}
+
+	function subscribe_feedster()
+	{
+		return $this->subscribe_service('http://www.feedster.com/myfeedster.php?action=addrss&confirm=no&rssurl=');
+	}
+
+	function subscribe_google()
+	{
+		return $this->subscribe_service('http://fusion.google.com/add?feedurl=');
+	}
+
+	function subscribe_gritwire()
+	{
+		return $this->subscribe_service('http://my.gritwire.com/feeds/addExternalFeed.aspx?FeedUrl=');
+	}
+
+	function subscribe_msn()
+	{
+		return $this->subscribe_service('http://my.msn.com/addtomymsn.armx?id=rss&ut=', '&ru=');
+	}
+
+	function subscribe_netvibes()
+	{
+		return $this->subscribe_service('http://www.netvibes.com/subscribe.php?url=');
+	}
+
+	function subscribe_newsburst()
+	{
+		return $this->subscribe_service('http://www.newsburst.com/Source/?add=');
+	}
+
+	function subscribe_newsgator()
+	{
+		return $this->subscribe_service('http://www.newsgator.com/ngs/subscriber/subext.aspx?url=');
+	}
+
+	function subscribe_odeo()
+	{
+		return $this->subscribe_service('http://www.odeo.com/listen/subscribe?feed=');
+	}
+
+	function subscribe_podnova()
+	{
+		return $this->subscribe_service('http://www.podnova.com/index_your_podcasts.srf?action=add&url=');
+	}
+
+	function subscribe_rojo()
+	{
+		return $this->subscribe_service('http://www.rojo.com/add-subscription?resource=');
+	}
+
+	function subscribe_yahoo()
+	{
+		return $this->subscribe_service('http://add.my.yahoo.com/rss?url=');
+	}
+
+	function get_feed_tags($namespace, $tag)
+	{
+		$type = $this->get_type();
+		if ($type & SIMPLEPIE_TYPE_ATOM_10)
+		{
+			if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag]))
+			{
+				return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['child'][$namespace][$tag];
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_ATOM_03)
+		{
+			if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag]))
+			{
+				return $this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['child'][$namespace][$tag];
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_RDF)
+		{
+			if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag]))
+			{
+				return $this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['child'][$namespace][$tag];
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+		{
+			if (isset($this->data['child']['']['rss'][0]['child'][$namespace][$tag]))
+			{
+				return $this->data['child']['']['rss'][0]['child'][$namespace][$tag];
+			}
+		}
+		return null;
+	}
+
+	function get_channel_tags($namespace, $tag)
+	{
+		$type = $this->get_type();
+		if ($type & SIMPLEPIE_TYPE_ATOM_ALL)
+		{
+			if ($return = $this->get_feed_tags($namespace, $tag))
+			{
+				return $return;
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_10)
+		{
+			if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'channel'))
+			{
+				if (isset($channel[0]['child'][$namespace][$tag]))
+				{
+					return $channel[0]['child'][$namespace][$tag];
+				}
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_090)
+		{
+			if ($channel = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'channel'))
+			{
+				if (isset($channel[0]['child'][$namespace][$tag]))
+				{
+					return $channel[0]['child'][$namespace][$tag];
+				}
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+		{
+			if ($channel = $this->get_feed_tags('', 'channel'))
+			{
+				if (isset($channel[0]['child'][$namespace][$tag]))
+				{
+					return $channel[0]['child'][$namespace][$tag];
+				}
+			}
+		}
+		return null;
+	}
+
+	function get_image_tags($namespace, $tag)
+	{
+		$type = $this->get_type();
+		if ($type & SIMPLEPIE_TYPE_RSS_10)
+		{
+			if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'image'))
+			{
+				if (isset($image[0]['child'][$namespace][$tag]))
+				{
+					return $image[0]['child'][$namespace][$tag];
+				}
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_090)
+		{
+			if ($image = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'image'))
+			{
+				if (isset($image[0]['child'][$namespace][$tag]))
+				{
+					return $image[0]['child'][$namespace][$tag];
+				}
+			}
+		}
+		if ($type & SIMPLEPIE_TYPE_RSS_SYNDICATION)
+		{
+			if ($image = $this->get_channel_tags('', 'image'))
+			{
+				if (isset($image[0]['child'][$namespace][$tag]))
+				{
+					return $image[0]['child'][$namespace][$tag];
+				}
+			}
+		}
+		return null;
+	}
+
+	function get_base($element = array())
+	{
+		if (!($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION) && !empty($element['xml_base_explicit']) && isset($element['xml_base']))
+		{
+			return $element['xml_base'];
+		}
+		elseif ($this->get_link() !== null)
+		{
+			return $this->get_link();
+		}
+		else
+		{
+			return $this->subscribe_url();
+		}
+	}
+
+	function sanitize($data, $type, $base = '')
+	{
+		return $this->sanitize->sanitize($data, $type, $base);
+	}
+
+	function get_title()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags('', 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_category($key = 0)
+	{
+		$categories = $this->get_categories();
+		if (isset($categories[$key]))
+		{
+			return $categories[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_categories()
+	{
+		$categories = array();
+
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+		{
+			$term = null;
+			$scheme = null;
+			$label = null;
+			if (isset($category['attribs']['']['term']))
+			{
+				$term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($category['attribs']['']['scheme']))
+			{
+				$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($category['attribs']['']['label']))
+			{
+				$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			$categories[] =& new $this->category_class($term, $scheme, $label);
+		}
+		foreach ((array) $this->get_channel_tags('', 'category') as $category)
+		{
+			$categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+		{
+			$categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+		{
+			$categories[] =& new $this->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+
+		if (!empty($categories))
+		{
+			return SimplePie_Misc::array_unique($categories);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_author($key = 0)
+	{
+		$authors = $this->get_authors();
+		if (isset($authors[$key]))
+		{
+			return $authors[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_authors()
+	{
+		$authors = array();
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+		{
+			$name = null;
+			$uri = null;
+			$email = null;
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+			{
+				$name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+			{
+				$uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+			}
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+			{
+				$email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $uri !== null)
+			{
+				$authors[] =& new $this->author_class($name, $uri, $email);
+			}
+		}
+		if ($author = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+		{
+			$name = null;
+			$url = null;
+			$email = null;
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+			{
+				$name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+			{
+				$url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+			}
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+			{
+				$email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $url !== null)
+			{
+				$authors[] =& new $this->author_class($name, $url, $email);
+			}
+		}
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+		{
+			$authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+		{
+			$authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+		{
+			$authors[] =& new $this->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+
+		if (!empty($authors))
+		{
+			return SimplePie_Misc::array_unique($authors);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_contributor($key = 0)
+	{
+		$contributors = $this->get_contributors();
+		if (isset($contributors[$key]))
+		{
+			return $contributors[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_contributors()
+	{
+		$contributors = array();
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+		{
+			$name = null;
+			$uri = null;
+			$email = null;
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+			{
+				$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+			{
+				$uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+			{
+				$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $uri !== null)
+			{
+				$contributors[] =& new $this->author_class($name, $uri, $email);
+			}
+		}
+		foreach ((array) $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+		{
+			$name = null;
+			$url = null;
+			$email = null;
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+			{
+				$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+			{
+				$url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+			{
+				$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $url !== null)
+			{
+				$contributors[] =& new $this->author_class($name, $url, $email);
+			}
+		}
+
+		if (!empty($contributors))
+		{
+			return SimplePie_Misc::array_unique($contributors);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_link($key = 0, $rel = 'alternate')
+	{
+		$links = $this->get_links($rel);
+		if (isset($links[$key]))
+		{
+			return $links[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * Added for parity between the parent-level and the item/entry-level.
+	 */
+	function get_permalink()
+	{
+		return $this->get_link(0);
+	}
+
+	function get_links($rel = 'alternate')
+	{
+		if (!isset($this->data['links']))
+		{
+			$this->data['links'] = array();
+			if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+			{
+				foreach ($links as $link)
+				{
+					if (isset($link['attribs']['']['href']))
+					{
+						$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+						$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+					}
+				}
+			}
+			if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+			{
+				foreach ($links as $link)
+				{
+					if (isset($link['attribs']['']['href']))
+					{
+						$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+						$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+					}
+				}
+			}
+			if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_channel_tags('', 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+
+			$keys = array_keys($this->data['links']);
+			foreach ($keys as $key)
+			{
+				if (SimplePie_Misc::is_isegment_nz_nc($key))
+				{
+					if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+					{
+						$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+						$this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+					}
+					else
+					{
+						$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+					}
+				}
+				elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+				{
+					$this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+				}
+				$this->data['links'][$key] = array_unique($this->data['links'][$key]);
+			}
+		}
+
+		if (isset($this->data['links'][$rel]))
+		{
+			return $this->data['links'][$rel];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_description()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags('', 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_copyright()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags('', 'copyright'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_language()
+	{
+		if ($return = $this->get_channel_tags('', 'language'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang']))
+		{
+			return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang']))
+		{
+			return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['feed'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (isset($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang']))
+		{
+			return $this->sanitize($this->data['child'][SIMPLEPIE_NAMESPACE_RDF]['RDF'][0]['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (isset($this->data['headers']['content-language']))
+		{
+			return $this->sanitize($this->data['headers']['content-language'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_latitude()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+		{
+			return (float) $match[1];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_longitude()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif (($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+		{
+			return (float) $match[2];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_image_title()
+	{
+		if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_image_tags('', 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_image_url()
+	{
+		if ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+		{
+			return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_channel_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'url'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'url'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_image_tags('', 'url'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_image_link()
+	{
+		if ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_image_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_image_tags('', 'link'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_image_width()
+	{
+		if ($return = $this->get_image_tags('', 'width'))
+		{
+			return round($return[0]['data']);
+		}
+		elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url'))
+		{
+			return 88.0;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_image_height()
+	{
+		if ($return = $this->get_image_tags('', 'height'))
+		{
+			return round($return[0]['data']);
+		}
+		elseif ($this->get_type() & SIMPLEPIE_TYPE_RSS_SYNDICATION && $this->get_image_tags('', 'url'))
+		{
+			return 31.0;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_item_quantity($max = 0)
+	{
+		$qty = count($this->get_items());
+		if ($max == 0)
+		{
+			return $qty;
+		}
+		else
+		{
+			return ($qty > $max) ? $max : $qty;
+		}
+	}
+
+	function get_item($key = 0)
+	{
+		$items = $this->get_items();
+		if (isset($items[$key]))
+		{
+			return $items[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_items($start = 0, $end = 0)
+	{
+		if (!empty($this->multifeed_objects))
+		{
+			return SimplePie::merge_items($this->multifeed_objects, $start, $end, $this->item_limit);
+		}
+		elseif (!isset($this->data['items']))
+		{
+			if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'entry'))
+			{
+				$keys = array_keys($items);
+				foreach ($keys as $key)
+				{
+					$this->data['items'][] =& new $this->item_class($this, $items[$key]);
+				}
+			}
+			if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'entry'))
+			{
+				$keys = array_keys($items);
+				foreach ($keys as $key)
+				{
+					$this->data['items'][] =& new $this->item_class($this, $items[$key]);
+				}
+			}
+			if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'item'))
+			{
+				$keys = array_keys($items);
+				foreach ($keys as $key)
+				{
+					$this->data['items'][] =& new $this->item_class($this, $items[$key]);
+				}
+			}
+			if ($items = $this->get_feed_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'item'))
+			{
+				$keys = array_keys($items);
+				foreach ($keys as $key)
+				{
+					$this->data['items'][] =& new $this->item_class($this, $items[$key]);
+				}
+			}
+			if ($items = $this->get_channel_tags('', 'item'))
+			{
+				$keys = array_keys($items);
+				foreach ($keys as $key)
+				{
+					$this->data['items'][] =& new $this->item_class($this, $items[$key]);
+				}
+			}
+		}
+
+		if (!empty($this->data['items']))
+		{
+			// If we want to order it by date, check if all items have a date, and then sort it
+			if ($this->order_by_date)
+			{
+				if (!isset($this->data['ordered_items']))
+				{
+					$do_sort = true;
+					foreach ($this->data['items'] as $item)
+					{
+						if (!$item->get_date('U'))
+						{
+							$do_sort = false;
+							break;
+						}
+					}
+					$item = null;
+					$this->data['ordered_items'] = $this->data['items'];
+					if ($do_sort)
+					{
+						usort($this->data['ordered_items'], array(&$this, 'sort_items'));
+					}
+				}
+				$items = $this->data['ordered_items'];
+			}
+			else
+			{
+				$items = $this->data['items'];
+			}
+
+			// Slice the data as desired
+			if ($end == 0)
+			{
+				return array_slice($items, $start);
+			}
+			else
+			{
+				return array_slice($items, $start, $end);
+			}
+		}
+		else
+		{
+			return array();
+		}
+	}
+
+	function sort_items($a, $b)
+	{
+		return $a->get_date('U') <= $b->get_date('U');
+	}
+
+	function merge_items($urls, $start = 0, $end = 0, $limit = 0)
+	{
+		if (is_array($urls) && sizeof($urls) > 0)
+		{
+			$items = array();
+			foreach ($urls as $arg)
+			{
+				if (is_a($arg, 'SimplePie'))
+				{
+					$items = array_merge($items, $arg->get_items(0, $limit));
+				}
+				else
+				{
+					trigger_error('Arguments must be SimplePie objects', E_USER_WARNING);
+				}
+			}
+
+			$do_sort = true;
+			foreach ($items as $item)
+			{
+				if (!$item->get_date('U'))
+				{
+					$do_sort = false;
+					break;
+				}
+			}
+			$item = null;
+			if ($do_sort)
+			{
+				usort($items, array('SimplePie', 'sort_items'));
+			}
+
+			if ($end == 0)
+			{
+				return array_slice($items, $start);
+			}
+			else
+			{
+				return array_slice($items, $start, $end);
+			}
+		}
+		else
+		{
+			trigger_error('Cannot merge zero SimplePie objects', E_USER_WARNING);
+			return array();
+		}
+	}
+}
+
+class SimplePie_Item
+{
+	var $feed;
+	var $data = array();
+
+	function SimplePie_Item($feed, $data)
+	{
+		$this->feed = $feed;
+		$this->data = $data;
+	}
+
+	function __toString()
+	{
+		return md5(serialize($this->data));
+	}
+	
+	/**
+	 * Remove items that link back to this before destroying this object
+	 */
+	function __destruct()
+	{
+		unset($this->feed);
+	}
+
+	function get_item_tags($namespace, $tag)
+	{
+		if (isset($this->data['child'][$namespace][$tag]))
+		{
+			return $this->data['child'][$namespace][$tag];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_base($element = array())
+	{
+		return $this->feed->get_base($element);
+	}
+
+	function sanitize($data, $type, $base = '')
+	{
+		return $this->feed->sanitize($data, $type, $base);
+	}
+
+	function get_feed()
+	{
+		return $this->feed;
+	}
+
+	function get_id($hash = false)
+	{
+		if (!$hash)
+		{
+			if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'id'))
+			{
+				return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'id'))
+			{
+				return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			elseif ($return = $this->get_item_tags('', 'guid'))
+			{
+				return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'identifier'))
+			{
+				return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'identifier'))
+			{
+				return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			elseif (($return = $this->get_permalink()) !== null)
+			{
+				return $return;
+			}
+			elseif (($return = $this->get_title()) !== null)
+			{
+				return $return;
+			}
+		}
+		if ($this->get_permalink() !== null || $this->get_title() !== null)
+		{
+			return md5($this->get_permalink() . $this->get_title());
+		}
+		else
+		{
+			return md5(serialize($this->data));
+		}
+	}
+
+	function get_title()
+	{
+		if (!isset($this->data['title']))
+		{
+			if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+			}
+			elseif ($return = $this->get_item_tags('', 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+			{
+				$this->data['title'] = $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			else
+			{
+				$this->data['title'] = null;
+			}
+		}
+		return $this->data['title'];
+	}
+
+	function get_description($description_only = false)
+	{
+		if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'summary'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'summary'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags('', 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (!$description_only)
+		{
+			return $this->get_content(true);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_content($content_only = false)
+	{
+		if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'content'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_content_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'content'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10_MODULES_CONTENT, 'encoded'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		elseif (!$content_only)
+		{
+			return $this->get_description(true);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_category($key = 0)
+	{
+		$categories = $this->get_categories();
+		if (isset($categories[$key]))
+		{
+			return $categories[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_categories()
+	{
+		$categories = array();
+
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+		{
+			$term = null;
+			$scheme = null;
+			$label = null;
+			if (isset($category['attribs']['']['term']))
+			{
+				$term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($category['attribs']['']['scheme']))
+			{
+				$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($category['attribs']['']['label']))
+			{
+				$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			$categories[] =& new $this->feed->category_class($term, $scheme, $label);
+		}
+		foreach ((array) $this->get_item_tags('', 'category') as $category)
+		{
+			$categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+		{
+			$categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+		{
+			$categories[] =& new $this->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+
+		if (!empty($categories))
+		{
+			return SimplePie_Misc::array_unique($categories);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_author($key = 0)
+	{
+		$authors = $this->get_authors();
+		if (isset($authors[$key]))
+		{
+			return $authors[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_contributor($key = 0)
+	{
+		$contributors = $this->get_contributors();
+		if (isset($contributors[$key]))
+		{
+			return $contributors[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_contributors()
+	{
+		$contributors = array();
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+		{
+			$name = null;
+			$uri = null;
+			$email = null;
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+			{
+				$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+			{
+				$uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+			{
+				$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $uri !== null)
+			{
+				$contributors[] =& new $this->feed->author_class($name, $uri, $email);
+			}
+		}
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+		{
+			$name = null;
+			$url = null;
+			$email = null;
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+			{
+				$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+			{
+				$url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+			{
+				$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $url !== null)
+			{
+				$contributors[] =& new $this->feed->author_class($name, $url, $email);
+			}
+		}
+
+		if (!empty($contributors))
+		{
+			return SimplePie_Misc::array_unique($contributors);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * @todo Atom inheritance (item author, source author, feed author)
+	 */
+	function get_authors()
+	{
+		$authors = array();
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+		{
+			$name = null;
+			$uri = null;
+			$email = null;
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+			{
+				$name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+			{
+				$uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+			}
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+			{
+				$email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $uri !== null)
+			{
+				$authors[] =& new $this->feed->author_class($name, $uri, $email);
+			}
+		}
+		if ($author = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+		{
+			$name = null;
+			$url = null;
+			$email = null;
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+			{
+				$name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+			{
+				$url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+			}
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+			{
+				$email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $url !== null)
+			{
+				$authors[] =& new $this->feed->author_class($name, $url, $email);
+			}
+		}
+		if ($author = $this->get_item_tags('', 'author'))
+		{
+			$authors[] =& new $this->feed->author_class(null, null, $this->sanitize($author[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+		}
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+		{
+			$authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+		{
+			$authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+		{
+			$authors[] =& new $this->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+
+		if (!empty($authors))
+		{
+			return SimplePie_Misc::array_unique($authors);
+		}
+		elseif (($source = $this->get_source()) && ($authors = $source->get_authors()))
+		{
+			return $authors;
+		}
+		elseif ($authors = $this->feed->get_authors())
+		{
+			return $authors;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_copyright()
+	{
+		if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_date($date_format = 'j F Y, g:i a')
+	{
+		if (!isset($this->data['date']))
+		{
+			if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'published'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'updated'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'issued'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'created'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'modified'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags('', 'pubDate'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_11, 'date'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+			elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_DC_10, 'date'))
+			{
+				$this->data['date']['raw'] = $return[0]['data'];
+			}
+
+			if (!empty($this->data['date']['raw']))
+			{
+				$parser = SimplePie_Parse_Date::get();
+				$this->data['date']['parsed'] = $parser->parse($this->data['date']['raw']);
+			}
+			else
+			{
+				$this->data['date'] = null;
+			}
+		}
+		if ($this->data['date'])
+		{
+			$date_format = (string) $date_format;
+			switch ($date_format)
+			{
+				case '':
+					return $this->sanitize($this->data['date']['raw'], SIMPLEPIE_CONSTRUCT_TEXT);
+
+				case 'U':
+					return $this->data['date']['parsed'];
+
+				default:
+					return date($date_format, $this->data['date']['parsed']);
+			}
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_local_date($date_format = '%c')
+	{
+		if (!$date_format)
+		{
+			return $this->sanitize($this->get_date(''), SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (($date = $this->get_date('U')) !== null)
+		{
+			return strftime($date_format, $date);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_permalink()
+	{
+		$link = $this->get_link();
+		$enclosure = $this->get_enclosure(0);
+		if ($link !== null)
+		{
+			return $link;
+		}
+		elseif ($enclosure !== null)
+		{
+			return $enclosure->get_link();
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_link($key = 0, $rel = 'alternate')
+	{
+		$links = $this->get_links($rel);
+		if ($links[$key] !== null)
+		{
+			return $links[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_links($rel = 'alternate')
+	{
+		if (!isset($this->data['links']))
+		{
+			$this->data['links'] = array();
+			foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
+			{
+				if (isset($link['attribs']['']['href']))
+				{
+					$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+					$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+				}
+			}
+			foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
+			{
+				if (isset($link['attribs']['']['href']))
+				{
+					$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+					$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+				}
+			}
+			if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_item_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_item_tags('', 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_item_tags('', 'guid'))
+			{
+				if (!isset($links[0]['attribs']['']['isPermaLink']) || strtolower(trim($links[0]['attribs']['']['isPermaLink'])) == 'true')
+				{
+					$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+				}
+			}
+
+			$keys = array_keys($this->data['links']);
+			foreach ($keys as $key)
+			{
+				if (SimplePie_Misc::is_isegment_nz_nc($key))
+				{
+					if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+					{
+						$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+						$this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+					}
+					else
+					{
+						$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+					}
+				}
+				elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+				{
+					$this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+				}
+				$this->data['links'][$key] = array_unique($this->data['links'][$key]);
+			}
+		}
+		if (isset($this->data['links'][$rel]))
+		{
+			return $this->data['links'][$rel];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * @todo Add ability to prefer one type of content over another (in a media group).
+	 */
+	function get_enclosure($key = 0, $prefer = null)
+	{
+		$enclosures = $this->get_enclosures();
+		if (isset($enclosures[$key]))
+		{
+			return $enclosures[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * Grabs all available enclosures (podcasts, etc.)
+	 *
+	 * Supports the <enclosure> RSS tag, as well as Media RSS and iTunes RSS.
+	 *
+	 * At this point, we're pretty much assuming that all enclosures for an item are the same content.  Anything else is too complicated to properly support.
+	 *
+	 * @todo Add support for end-user defined sorting of enclosures by type/handler (so we can prefer the faster-loading FLV over MP4).
+	 * @todo If an element exists at a level, but it's value is empty, we should fall back to the value from the parent (if it exists).
+	 */
+	function get_enclosures()
+	{
+		if (!isset($this->data['enclosures']))
+		{
+			$this->data['enclosures'] = array();
+
+			// Elements
+			$captions_parent = null;
+			$categories_parent = null;
+			$copyrights_parent = null;
+			$credits_parent = null;
+			$description_parent = null;
+			$duration_parent = null;
+			$hashes_parent = null;
+			$keywords_parent = null;
+			$player_parent = null;
+			$ratings_parent = null;
+			$restrictions_parent = null;
+			$thumbnails_parent = null;
+			$title_parent = null;
+
+			// Let's do the channel and item-level ones first, and just re-use them if we need to.
+			$parent = $this->get_feed();
+
+			// CAPTIONS
+			if ($captions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
+			{
+				foreach ($captions as $caption)
+				{
+					$caption_type = null;
+					$caption_lang = null;
+					$caption_startTime = null;
+					$caption_endTime = null;
+					$caption_text = null;
+					if (isset($caption['attribs']['']['type']))
+					{
+						$caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['attribs']['']['lang']))
+					{
+						$caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['attribs']['']['start']))
+					{
+						$caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['attribs']['']['end']))
+					{
+						$caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['data']))
+					{
+						$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+				}
+			}
+			elseif ($captions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'text'))
+			{
+				foreach ($captions as $caption)
+				{
+					$caption_type = null;
+					$caption_lang = null;
+					$caption_startTime = null;
+					$caption_endTime = null;
+					$caption_text = null;
+					if (isset($caption['attribs']['']['type']))
+					{
+						$caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['attribs']['']['lang']))
+					{
+						$caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['attribs']['']['start']))
+					{
+						$caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['attribs']['']['end']))
+					{
+						$caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($caption['data']))
+					{
+						$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$captions_parent[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+				}
+			}
+			if (is_array($captions_parent))
+			{
+				$captions_parent = array_values(SimplePie_Misc::array_unique($captions_parent));
+			}
+
+			// CATEGORIES
+			foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
+			{
+				$term = null;
+				$scheme = null;
+				$label = null;
+				if (isset($category['data']))
+				{
+					$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				if (isset($category['attribs']['']['scheme']))
+				{
+					$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				else
+				{
+					$scheme = 'http://search.yahoo.com/mrss/category_schema';
+				}
+				if (isset($category['attribs']['']['label']))
+				{
+					$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				$categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+			}
+			foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'category') as $category)
+			{
+				$term = null;
+				$scheme = null;
+				$label = null;
+				if (isset($category['data']))
+				{
+					$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				if (isset($category['attribs']['']['scheme']))
+				{
+					$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				else
+				{
+					$scheme = 'http://search.yahoo.com/mrss/category_schema';
+				}
+				if (isset($category['attribs']['']['label']))
+				{
+					$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				$categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+			}
+			foreach ((array) $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'category') as $category)
+			{
+				$term = null;
+				$scheme = 'http://www.itunes.com/dtds/podcast-1.0.dtd';
+				$label = null;
+				if (isset($category['attribs']['']['text']))
+				{
+					$label = $this->sanitize($category['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				$categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+
+				if (isset($category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category']))
+				{
+					foreach ((array) $category['child'][SIMPLEPIE_NAMESPACE_ITUNES]['category'] as $subcategory)
+					{
+						if (isset($subcategory['attribs']['']['text']))
+						{
+							$label = $this->sanitize($subcategory['attribs']['']['text'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						$categories_parent[] =& new $this->feed->category_class($term, $scheme, $label);
+					}
+				}
+			}
+			if (is_array($categories_parent))
+			{
+				$categories_parent = array_values(SimplePie_Misc::array_unique($categories_parent));
+			}
+
+			// COPYRIGHT
+			if ($copyright = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
+			{
+				$copyright_url = null;
+				$copyright_label = null;
+				if (isset($copyright[0]['attribs']['']['url']))
+				{
+					$copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				if (isset($copyright[0]['data']))
+				{
+					$copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				$copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+			}
+			elseif ($copyright = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'copyright'))
+			{
+				$copyright_url = null;
+				$copyright_label = null;
+				if (isset($copyright[0]['attribs']['']['url']))
+				{
+					$copyright_url = $this->sanitize($copyright[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				if (isset($copyright[0]['data']))
+				{
+					$copyright_label = $this->sanitize($copyright[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+				$copyrights_parent =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+			}
+
+			// CREDITS
+			if ($credits = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
+			{
+				foreach ($credits as $credit)
+				{
+					$credit_role = null;
+					$credit_scheme = null;
+					$credit_name = null;
+					if (isset($credit['attribs']['']['role']))
+					{
+						$credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($credit['attribs']['']['scheme']))
+					{
+						$credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$credit_scheme = 'urn:ebu';
+					}
+					if (isset($credit['data']))
+					{
+						$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+				}
+			}
+			elseif ($credits = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'credit'))
+			{
+				foreach ($credits as $credit)
+				{
+					$credit_role = null;
+					$credit_scheme = null;
+					$credit_name = null;
+					if (isset($credit['attribs']['']['role']))
+					{
+						$credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($credit['attribs']['']['scheme']))
+					{
+						$credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$credit_scheme = 'urn:ebu';
+					}
+					if (isset($credit['data']))
+					{
+						$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$credits_parent[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+				}
+			}
+			if (is_array($credits_parent))
+			{
+				$credits_parent = array_values(SimplePie_Misc::array_unique($credits_parent));
+			}
+
+			// DESCRIPTION
+			if ($description_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
+			{
+				if (isset($description_parent[0]['data']))
+				{
+					$description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+			}
+			elseif ($description_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'description'))
+			{
+				if (isset($description_parent[0]['data']))
+				{
+					$description_parent = $this->sanitize($description_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+			}
+
+			// DURATION
+			if ($duration_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'duration'))
+			{
+				$seconds = null;
+				$minutes = null;
+				$hours = null;
+				if (isset($duration_parent[0]['data']))
+				{
+					$temp = explode(':', $this->sanitize($duration_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+					if (sizeof($temp) > 0)
+					{
+						(int) $seconds = array_pop($temp);
+					}
+					if (sizeof($temp) > 0)
+					{
+						(int) $minutes = array_pop($temp);
+						$seconds += $minutes * 60;
+					}
+					if (sizeof($temp) > 0)
+					{
+						(int) $hours = array_pop($temp);
+						$seconds += $hours * 3600;
+					}
+					unset($temp);
+					$duration_parent = $seconds;
+				}
+			}
+
+			// HASHES
+			if ($hashes_iterator = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
+			{
+				foreach ($hashes_iterator as $hash)
+				{
+					$value = null;
+					$algo = null;
+					if (isset($hash['data']))
+					{
+						$value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($hash['attribs']['']['algo']))
+					{
+						$algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$algo = 'md5';
+					}
+					$hashes_parent[] = $algo.':'.$value;
+				}
+			}
+			elseif ($hashes_iterator = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'hash'))
+			{
+				foreach ($hashes_iterator as $hash)
+				{
+					$value = null;
+					$algo = null;
+					if (isset($hash['data']))
+					{
+						$value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($hash['attribs']['']['algo']))
+					{
+						$algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$algo = 'md5';
+					}
+					$hashes_parent[] = $algo.':'.$value;
+				}
+			}
+			if (is_array($hashes_parent))
+			{
+				$hashes_parent = array_values(SimplePie_Misc::array_unique($hashes_parent));
+			}
+
+			// KEYWORDS
+			if ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
+			{
+				if (isset($keywords[0]['data']))
+				{
+					$temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+					foreach ($temp as $word)
+					{
+						$keywords_parent[] = trim($word);
+					}
+				}
+				unset($temp);
+			}
+			elseif ($keywords = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
+			{
+				if (isset($keywords[0]['data']))
+				{
+					$temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+					foreach ($temp as $word)
+					{
+						$keywords_parent[] = trim($word);
+					}
+				}
+				unset($temp);
+			}
+			elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'keywords'))
+			{
+				if (isset($keywords[0]['data']))
+				{
+					$temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+					foreach ($temp as $word)
+					{
+						$keywords_parent[] = trim($word);
+					}
+				}
+				unset($temp);
+			}
+			elseif ($keywords = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'keywords'))
+			{
+				if (isset($keywords[0]['data']))
+				{
+					$temp = explode(',', $this->sanitize($keywords[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+					foreach ($temp as $word)
+					{
+						$keywords_parent[] = trim($word);
+					}
+				}
+				unset($temp);
+			}
+			if (is_array($keywords_parent))
+			{
+				$keywords_parent = array_values(SimplePie_Misc::array_unique($keywords_parent));
+			}
+
+			// PLAYER
+			if ($player_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
+			{
+				if (isset($player_parent[0]['attribs']['']['url']))
+				{
+					$player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+				}
+			}
+			elseif ($player_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'player'))
+			{
+				if (isset($player_parent[0]['attribs']['']['url']))
+				{
+					$player_parent = $this->sanitize($player_parent[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+				}
+			}
+
+			// RATINGS
+			if ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
+			{
+				foreach ($ratings as $rating)
+				{
+					$rating_scheme = null;
+					$rating_value = null;
+					if (isset($rating['attribs']['']['scheme']))
+					{
+						$rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$rating_scheme = 'urn:simple';
+					}
+					if (isset($rating['data']))
+					{
+						$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+				}
+			}
+			elseif ($ratings = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
+			{
+				foreach ($ratings as $rating)
+				{
+					$rating_scheme = 'urn:itunes';
+					$rating_value = null;
+					if (isset($rating['data']))
+					{
+						$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+				}
+			}
+			elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'rating'))
+			{
+				foreach ($ratings as $rating)
+				{
+					$rating_scheme = null;
+					$rating_value = null;
+					if (isset($rating['attribs']['']['scheme']))
+					{
+						$rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					else
+					{
+						$rating_scheme = 'urn:simple';
+					}
+					if (isset($rating['data']))
+					{
+						$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+				}
+			}
+			elseif ($ratings = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'explicit'))
+			{
+				foreach ($ratings as $rating)
+				{
+					$rating_scheme = 'urn:itunes';
+					$rating_value = null;
+					if (isset($rating['data']))
+					{
+						$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$ratings_parent[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+				}
+			}
+			if (is_array($ratings_parent))
+			{
+				$ratings_parent = array_values(SimplePie_Misc::array_unique($ratings_parent));
+			}
+
+			// RESTRICTIONS
+			if ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
+			{
+				foreach ($restrictions as $restriction)
+				{
+					$restriction_relationship = null;
+					$restriction_type = null;
+					$restriction_value = null;
+					if (isset($restriction['attribs']['']['relationship']))
+					{
+						$restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($restriction['attribs']['']['type']))
+					{
+						$restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($restriction['data']))
+					{
+						$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+				}
+			}
+			elseif ($restrictions = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
+			{
+				foreach ($restrictions as $restriction)
+				{
+					$restriction_relationship = 'allow';
+					$restriction_type = null;
+					$restriction_value = 'itunes';
+					if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes')
+					{
+						$restriction_relationship = 'deny';
+					}
+					$restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+				}
+			}
+			elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'restriction'))
+			{
+				foreach ($restrictions as $restriction)
+				{
+					$restriction_relationship = null;
+					$restriction_type = null;
+					$restriction_value = null;
+					if (isset($restriction['attribs']['']['relationship']))
+					{
+						$restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($restriction['attribs']['']['type']))
+					{
+						$restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($restriction['data']))
+					{
+						$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					$restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+				}
+			}
+			elseif ($restrictions = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'block'))
+			{
+				foreach ($restrictions as $restriction)
+				{
+					$restriction_relationship = 'allow';
+					$restriction_type = null;
+					$restriction_value = 'itunes';
+					if (isset($restriction['data']) && strtolower($restriction['data']) == 'yes')
+					{
+						$restriction_relationship = 'deny';
+					}
+					$restrictions_parent[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+				}
+			}
+			if (is_array($restrictions_parent))
+			{
+				$restrictions_parent = array_values(SimplePie_Misc::array_unique($restrictions_parent));
+			}
+
+			// THUMBNAILS
+			if ($thumbnails = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+			{
+				foreach ($thumbnails as $thumbnail)
+				{
+					if (isset($thumbnail['attribs']['']['url']))
+					{
+						$thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+					}
+				}
+			}
+			elseif ($thumbnails = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'thumbnail'))
+			{
+				foreach ($thumbnails as $thumbnail)
+				{
+					if (isset($thumbnail['attribs']['']['url']))
+					{
+						$thumbnails_parent[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+					}
+				}
+			}
+
+			// TITLES
+			if ($title_parent = $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
+			{
+				if (isset($title_parent[0]['data']))
+				{
+					$title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+			}
+			elseif ($title_parent = $parent->get_channel_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'title'))
+			{
+				if (isset($title_parent[0]['data']))
+				{
+					$title_parent = $this->sanitize($title_parent[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+				}
+			}
+
+			// Clear the memory
+			unset($parent);
+
+			// Attributes
+			$bitrate = null;
+			$channels = null;
+			$duration = null;
+			$expression = null;
+			$framerate = null;
+			$height = null;
+			$javascript = null;
+			$lang = null;
+			$length = null;
+			$medium = null;
+			$samplingrate = null;
+			$type = null;
+			$url = null;
+			$width = null;
+
+			// Elements
+			$captions = null;
+			$categories = null;
+			$copyrights = null;
+			$credits = null;
+			$description = null;
+			$hashes = null;
+			$keywords = null;
+			$player = null;
+			$ratings = null;
+			$restrictions = null;
+			$thumbnails = null;
+			$title = null;
+
+			// If we have media:group tags, loop through them.
+			foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_MEDIARSS, 'group') as $group)
+			{
+				// If we have media:content tags, loop through them.
+				foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
+				{
+					if (isset($content['attribs']['']['url']))
+					{
+						// Attributes
+						$bitrate = null;
+						$channels = null;
+						$duration = null;
+						$expression = null;
+						$framerate = null;
+						$height = null;
+						$javascript = null;
+						$lang = null;
+						$length = null;
+						$medium = null;
+						$samplingrate = null;
+						$type = null;
+						$url = null;
+						$width = null;
+
+						// Elements
+						$captions = null;
+						$categories = null;
+						$copyrights = null;
+						$credits = null;
+						$description = null;
+						$hashes = null;
+						$keywords = null;
+						$player = null;
+						$ratings = null;
+						$restrictions = null;
+						$thumbnails = null;
+						$title = null;
+
+						// Start checking the attributes of media:content
+						if (isset($content['attribs']['']['bitrate']))
+						{
+							$bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['channels']))
+						{
+							$channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['duration']))
+						{
+							$duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						else
+						{
+							$duration = $duration_parent;
+						}
+						if (isset($content['attribs']['']['expression']))
+						{
+							$expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['framerate']))
+						{
+							$framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['height']))
+						{
+							$height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['lang']))
+						{
+							$lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['fileSize']))
+						{
+							$length = ceil($content['attribs']['']['fileSize']);
+						}
+						if (isset($content['attribs']['']['medium']))
+						{
+							$medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['samplingrate']))
+						{
+							$samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['type']))
+						{
+							$type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['width']))
+						{
+							$width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						$url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+
+						// Checking the other optional media: elements. Priority: media:content, media:group, item, channel
+
+						// CAPTIONS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+							{
+								$caption_type = null;
+								$caption_lang = null;
+								$caption_startTime = null;
+								$caption_endTime = null;
+								$caption_text = null;
+								if (isset($caption['attribs']['']['type']))
+								{
+									$caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['lang']))
+								{
+									$caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['start']))
+								{
+									$caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['end']))
+								{
+									$caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['data']))
+								{
+									$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+							}
+							if (is_array($captions))
+							{
+								$captions = array_values(SimplePie_Misc::array_unique($captions));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+						{
+							foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+							{
+								$caption_type = null;
+								$caption_lang = null;
+								$caption_startTime = null;
+								$caption_endTime = null;
+								$caption_text = null;
+								if (isset($caption['attribs']['']['type']))
+								{
+									$caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['lang']))
+								{
+									$caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['start']))
+								{
+									$caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['end']))
+								{
+									$caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['data']))
+								{
+									$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+							}
+							if (is_array($captions))
+							{
+								$captions = array_values(SimplePie_Misc::array_unique($captions));
+							}
+						}
+						else
+						{
+							$captions = $captions_parent;
+						}
+
+						// CATEGORIES
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+						{
+							foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+							{
+								$term = null;
+								$scheme = null;
+								$label = null;
+								if (isset($category['data']))
+								{
+									$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($category['attribs']['']['scheme']))
+								{
+									$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$scheme = 'http://search.yahoo.com/mrss/category_schema';
+								}
+								if (isset($category['attribs']['']['label']))
+								{
+									$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$categories[] =& new $this->feed->category_class($term, $scheme, $label);
+							}
+						}
+						if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+						{
+							foreach ((array) $group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+							{
+								$term = null;
+								$scheme = null;
+								$label = null;
+								if (isset($category['data']))
+								{
+									$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($category['attribs']['']['scheme']))
+								{
+									$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$scheme = 'http://search.yahoo.com/mrss/category_schema';
+								}
+								if (isset($category['attribs']['']['label']))
+								{
+									$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$categories[] =& new $this->feed->category_class($term, $scheme, $label);
+							}
+						}
+						if (is_array($categories) && is_array($categories_parent))
+						{
+							$categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
+						}
+						elseif (is_array($categories))
+						{
+							$categories = array_values(SimplePie_Misc::array_unique($categories));
+						}
+						elseif (is_array($categories_parent))
+						{
+							$categories = array_values(SimplePie_Misc::array_unique($categories_parent));
+						}
+
+						// COPYRIGHTS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+						{
+							$copyright_url = null;
+							$copyright_label = null;
+							if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+							{
+								$copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+							}
+							if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+							{
+								$copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+							}
+							$copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+						{
+							$copyright_url = null;
+							$copyright_label = null;
+							if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+							{
+								$copyright_url = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+							}
+							if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+							{
+								$copyright_label = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+							}
+							$copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+						}
+						else
+						{
+							$copyrights = $copyrights_parent;
+						}
+
+						// CREDITS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+							{
+								$credit_role = null;
+								$credit_scheme = null;
+								$credit_name = null;
+								if (isset($credit['attribs']['']['role']))
+								{
+									$credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($credit['attribs']['']['scheme']))
+								{
+									$credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$credit_scheme = 'urn:ebu';
+								}
+								if (isset($credit['data']))
+								{
+									$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+							}
+							if (is_array($credits))
+							{
+								$credits = array_values(SimplePie_Misc::array_unique($credits));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+						{
+							foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+							{
+								$credit_role = null;
+								$credit_scheme = null;
+								$credit_name = null;
+								if (isset($credit['attribs']['']['role']))
+								{
+									$credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($credit['attribs']['']['scheme']))
+								{
+									$credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$credit_scheme = 'urn:ebu';
+								}
+								if (isset($credit['data']))
+								{
+									$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+							}
+							if (is_array($credits))
+							{
+								$credits = array_values(SimplePie_Misc::array_unique($credits));
+							}
+						}
+						else
+						{
+							$credits = $credits_parent;
+						}
+
+						// DESCRIPTION
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+						{
+							$description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+						{
+							$description = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						else
+						{
+							$description = $description_parent;
+						}
+
+						// HASHES
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+							{
+								$value = null;
+								$algo = null;
+								if (isset($hash['data']))
+								{
+									$value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($hash['attribs']['']['algo']))
+								{
+									$algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$algo = 'md5';
+								}
+								$hashes[] = $algo.':'.$value;
+							}
+							if (is_array($hashes))
+							{
+								$hashes = array_values(SimplePie_Misc::array_unique($hashes));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+						{
+							foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+							{
+								$value = null;
+								$algo = null;
+								if (isset($hash['data']))
+								{
+									$value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($hash['attribs']['']['algo']))
+								{
+									$algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$algo = 'md5';
+								}
+								$hashes[] = $algo.':'.$value;
+							}
+							if (is_array($hashes))
+							{
+								$hashes = array_values(SimplePie_Misc::array_unique($hashes));
+							}
+						}
+						else
+						{
+							$hashes = $hashes_parent;
+						}
+
+						// KEYWORDS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+						{
+							if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+							{
+								$temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+								foreach ($temp as $word)
+								{
+									$keywords[] = trim($word);
+								}
+								unset($temp);
+							}
+							if (is_array($keywords))
+							{
+								$keywords = array_values(SimplePie_Misc::array_unique($keywords));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+						{
+							if (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+							{
+								$temp = explode(',', $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+								foreach ($temp as $word)
+								{
+									$keywords[] = trim($word);
+								}
+								unset($temp);
+							}
+							if (is_array($keywords))
+							{
+								$keywords = array_values(SimplePie_Misc::array_unique($keywords));
+							}
+						}
+						else
+						{
+							$keywords = $keywords_parent;
+						}
+
+						// PLAYER
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+						{
+							$player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+						{
+							$player = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+						}
+						else
+						{
+							$player = $player_parent;
+						}
+
+						// RATINGS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+							{
+								$rating_scheme = null;
+								$rating_value = null;
+								if (isset($rating['attribs']['']['scheme']))
+								{
+									$rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$rating_scheme = 'urn:simple';
+								}
+								if (isset($rating['data']))
+								{
+									$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+							}
+							if (is_array($ratings))
+							{
+								$ratings = array_values(SimplePie_Misc::array_unique($ratings));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+						{
+							foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+							{
+								$rating_scheme = null;
+								$rating_value = null;
+								if (isset($rating['attribs']['']['scheme']))
+								{
+									$rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$rating_scheme = 'urn:simple';
+								}
+								if (isset($rating['data']))
+								{
+									$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+							}
+							if (is_array($ratings))
+							{
+								$ratings = array_values(SimplePie_Misc::array_unique($ratings));
+							}
+						}
+						else
+						{
+							$ratings = $ratings_parent;
+						}
+
+						// RESTRICTIONS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+							{
+								$restriction_relationship = null;
+								$restriction_type = null;
+								$restriction_value = null;
+								if (isset($restriction['attribs']['']['relationship']))
+								{
+									$restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($restriction['attribs']['']['type']))
+								{
+									$restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($restriction['data']))
+								{
+									$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+							}
+							if (is_array($restrictions))
+							{
+								$restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+						{
+							foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+							{
+								$restriction_relationship = null;
+								$restriction_type = null;
+								$restriction_value = null;
+								if (isset($restriction['attribs']['']['relationship']))
+								{
+									$restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($restriction['attribs']['']['type']))
+								{
+									$restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($restriction['data']))
+								{
+									$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+							}
+							if (is_array($restrictions))
+							{
+								$restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+							}
+						}
+						else
+						{
+							$restrictions = $restrictions_parent;
+						}
+
+						// THUMBNAILS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+							{
+								$thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+							}
+							if (is_array($thumbnails))
+							{
+								$thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+							}
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+						{
+							foreach ($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+							{
+								$thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+							}
+							if (is_array($thumbnails))
+							{
+								$thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+							}
+						}
+						else
+						{
+							$thumbnails = $thumbnails_parent;
+						}
+
+						// TITLES
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+						{
+							$title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						elseif (isset($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+						{
+							$title = $this->sanitize($group['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						else
+						{
+							$title = $title_parent;
+						}
+
+						$this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
+					}
+				}
+			}
+
+			// If we have standalone media:content tags, loop through them.
+			if (isset($this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content']))
+			{
+				foreach ((array) $this->data['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['content'] as $content)
+				{
+					if (isset($content['attribs']['']['url']))
+					{
+						// Attributes
+						$bitrate = null;
+						$channels = null;
+						$duration = null;
+						$expression = null;
+						$framerate = null;
+						$height = null;
+						$javascript = null;
+						$lang = null;
+						$length = null;
+						$medium = null;
+						$samplingrate = null;
+						$type = null;
+						$url = null;
+						$width = null;
+
+						// Elements
+						$captions = null;
+						$categories = null;
+						$copyrights = null;
+						$credits = null;
+						$description = null;
+						$hashes = null;
+						$keywords = null;
+						$player = null;
+						$ratings = null;
+						$restrictions = null;
+						$thumbnails = null;
+						$title = null;
+
+						// Start checking the attributes of media:content
+						if (isset($content['attribs']['']['bitrate']))
+						{
+							$bitrate = $this->sanitize($content['attribs']['']['bitrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['channels']))
+						{
+							$channels = $this->sanitize($content['attribs']['']['channels'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['duration']))
+						{
+							$duration = $this->sanitize($content['attribs']['']['duration'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						else
+						{
+							$duration = $duration_parent;
+						}
+						if (isset($content['attribs']['']['expression']))
+						{
+							$expression = $this->sanitize($content['attribs']['']['expression'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['framerate']))
+						{
+							$framerate = $this->sanitize($content['attribs']['']['framerate'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['height']))
+						{
+							$height = $this->sanitize($content['attribs']['']['height'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['lang']))
+						{
+							$lang = $this->sanitize($content['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['fileSize']))
+						{
+							$length = ceil($content['attribs']['']['fileSize']);
+						}
+						if (isset($content['attribs']['']['medium']))
+						{
+							$medium = $this->sanitize($content['attribs']['']['medium'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['samplingrate']))
+						{
+							$samplingrate = $this->sanitize($content['attribs']['']['samplingrate'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['type']))
+						{
+							$type = $this->sanitize($content['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						if (isset($content['attribs']['']['width']))
+						{
+							$width = $this->sanitize($content['attribs']['']['width'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						$url = $this->sanitize($content['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+
+						// Checking the other optional media: elements. Priority: media:content, media:group, item, channel
+
+						// CAPTIONS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['text'] as $caption)
+							{
+								$caption_type = null;
+								$caption_lang = null;
+								$caption_startTime = null;
+								$caption_endTime = null;
+								$caption_text = null;
+								if (isset($caption['attribs']['']['type']))
+								{
+									$caption_type = $this->sanitize($caption['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['lang']))
+								{
+									$caption_lang = $this->sanitize($caption['attribs']['']['lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['start']))
+								{
+									$caption_startTime = $this->sanitize($caption['attribs']['']['start'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['attribs']['']['end']))
+								{
+									$caption_endTime = $this->sanitize($caption['attribs']['']['end'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($caption['data']))
+								{
+									$caption_text = $this->sanitize($caption['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$captions[] =& new $this->feed->caption_class($caption_type, $caption_lang, $caption_startTime, $caption_endTime, $caption_text);
+							}
+							if (is_array($captions))
+							{
+								$captions = array_values(SimplePie_Misc::array_unique($captions));
+							}
+						}
+						else
+						{
+							$captions = $captions_parent;
+						}
+
+						// CATEGORIES
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category']))
+						{
+							foreach ((array) $content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['category'] as $category)
+							{
+								$term = null;
+								$scheme = null;
+								$label = null;
+								if (isset($category['data']))
+								{
+									$term = $this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($category['attribs']['']['scheme']))
+								{
+									$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$scheme = 'http://search.yahoo.com/mrss/category_schema';
+								}
+								if (isset($category['attribs']['']['label']))
+								{
+									$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$categories[] =& new $this->feed->category_class($term, $scheme, $label);
+							}
+						}
+						if (is_array($categories) && is_array($categories_parent))
+						{
+							$categories = array_values(SimplePie_Misc::array_unique(array_merge($categories, $categories_parent)));
+						}
+						elseif (is_array($categories))
+						{
+							$categories = array_values(SimplePie_Misc::array_unique($categories));
+						}
+						elseif (is_array($categories_parent))
+						{
+							$categories = array_values(SimplePie_Misc::array_unique($categories_parent));
+						}
+						else
+						{
+							$categories = null;
+						}
+
+						// COPYRIGHTS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright']))
+						{
+							$copyright_url = null;
+							$copyright_label = null;
+							if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url']))
+							{
+								$copyright_url = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_TEXT);
+							}
+							if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data']))
+							{
+								$copyright_label = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['copyright'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+							}
+							$copyrights =& new $this->feed->copyright_class($copyright_url, $copyright_label);
+						}
+						else
+						{
+							$copyrights = $copyrights_parent;
+						}
+
+						// CREDITS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['credit'] as $credit)
+							{
+								$credit_role = null;
+								$credit_scheme = null;
+								$credit_name = null;
+								if (isset($credit['attribs']['']['role']))
+								{
+									$credit_role = $this->sanitize($credit['attribs']['']['role'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($credit['attribs']['']['scheme']))
+								{
+									$credit_scheme = $this->sanitize($credit['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$credit_scheme = 'urn:ebu';
+								}
+								if (isset($credit['data']))
+								{
+									$credit_name = $this->sanitize($credit['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$credits[] =& new $this->feed->credit_class($credit_role, $credit_scheme, $credit_name);
+							}
+							if (is_array($credits))
+							{
+								$credits = array_values(SimplePie_Misc::array_unique($credits));
+							}
+						}
+						else
+						{
+							$credits = $credits_parent;
+						}
+
+						// DESCRIPTION
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description']))
+						{
+							$description = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['description'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						else
+						{
+							$description = $description_parent;
+						}
+
+						// HASHES
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['hash'] as $hash)
+							{
+								$value = null;
+								$algo = null;
+								if (isset($hash['data']))
+								{
+									$value = $this->sanitize($hash['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($hash['attribs']['']['algo']))
+								{
+									$algo = $this->sanitize($hash['attribs']['']['algo'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$algo = 'md5';
+								}
+								$hashes[] = $algo.':'.$value;
+							}
+							if (is_array($hashes))
+							{
+								$hashes = array_values(SimplePie_Misc::array_unique($hashes));
+							}
+						}
+						else
+						{
+							$hashes = $hashes_parent;
+						}
+
+						// KEYWORDS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords']))
+						{
+							if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data']))
+							{
+								$temp = explode(',', $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['keywords'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT));
+								foreach ($temp as $word)
+								{
+									$keywords[] = trim($word);
+								}
+								unset($temp);
+							}
+							if (is_array($keywords))
+							{
+								$keywords = array_values(SimplePie_Misc::array_unique($keywords));
+							}
+						}
+						else
+						{
+							$keywords = $keywords_parent;
+						}
+
+						// PLAYER
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player']))
+						{
+							$player = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['player'][0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+						}
+						else
+						{
+							$player = $player_parent;
+						}
+
+						// RATINGS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['rating'] as $rating)
+							{
+								$rating_scheme = null;
+								$rating_value = null;
+								if (isset($rating['attribs']['']['scheme']))
+								{
+									$rating_scheme = $this->sanitize($rating['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								else
+								{
+									$rating_scheme = 'urn:simple';
+								}
+								if (isset($rating['data']))
+								{
+									$rating_value = $this->sanitize($rating['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$ratings[] =& new $this->feed->rating_class($rating_scheme, $rating_value);
+							}
+							if (is_array($ratings))
+							{
+								$ratings = array_values(SimplePie_Misc::array_unique($ratings));
+							}
+						}
+						else
+						{
+							$ratings = $ratings_parent;
+						}
+
+						// RESTRICTIONS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['restriction'] as $restriction)
+							{
+								$restriction_relationship = null;
+								$restriction_type = null;
+								$restriction_value = null;
+								if (isset($restriction['attribs']['']['relationship']))
+								{
+									$restriction_relationship = $this->sanitize($restriction['attribs']['']['relationship'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($restriction['attribs']['']['type']))
+								{
+									$restriction_type = $this->sanitize($restriction['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								if (isset($restriction['data']))
+								{
+									$restriction_value = $this->sanitize($restriction['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+								}
+								$restrictions[] =& new $this->feed->restriction_class($restriction_relationship, $restriction_type, $restriction_value);
+							}
+							if (is_array($restrictions))
+							{
+								$restrictions = array_values(SimplePie_Misc::array_unique($restrictions));
+							}
+						}
+						else
+						{
+							$restrictions = $restrictions_parent;
+						}
+
+						// THUMBNAILS
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail']))
+						{
+							foreach ($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['thumbnail'] as $thumbnail)
+							{
+								$thumbnails[] = $this->sanitize($thumbnail['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI);
+							}
+							if (is_array($thumbnails))
+							{
+								$thumbnails = array_values(SimplePie_Misc::array_unique($thumbnails));
+							}
+						}
+						else
+						{
+							$thumbnails = $thumbnails_parent;
+						}
+
+						// TITLES
+						if (isset($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title']))
+						{
+							$title = $this->sanitize($content['child'][SIMPLEPIE_NAMESPACE_MEDIARSS]['title'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+						}
+						else
+						{
+							$title = $title_parent;
+						}
+
+						$this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions, $categories, $channels, $copyrights, $credits, $description, $duration, $expression, $framerate, $hashes, $height, $keywords, $lang, $medium, $player, $ratings, $restrictions, $samplingrate, $thumbnails, $title, $width);
+					}
+				}
+			}
+
+			foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link') as $link)
+			{
+				if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure')
+				{
+					// Attributes
+					$bitrate = null;
+					$channels = null;
+					$duration = null;
+					$expression = null;
+					$framerate = null;
+					$height = null;
+					$javascript = null;
+					$lang = null;
+					$length = null;
+					$medium = null;
+					$samplingrate = null;
+					$type = null;
+					$url = null;
+					$width = null;
+
+					$url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+					if (isset($link['attribs']['']['type']))
+					{
+						$type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($link['attribs']['']['length']))
+					{
+						$length = ceil($link['attribs']['']['length']);
+					}
+
+					// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+					$this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+				}
+			}
+
+			foreach ((array) $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link') as $link)
+			{
+				if (isset($link['attribs']['']['href']) && !empty($link['attribs']['']['rel']) && $link['attribs']['']['rel'] == 'enclosure')
+				{
+					// Attributes
+					$bitrate = null;
+					$channels = null;
+					$duration = null;
+					$expression = null;
+					$framerate = null;
+					$height = null;
+					$javascript = null;
+					$lang = null;
+					$length = null;
+					$medium = null;
+					$samplingrate = null;
+					$type = null;
+					$url = null;
+					$width = null;
+
+					$url = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+					if (isset($link['attribs']['']['type']))
+					{
+						$type = $this->sanitize($link['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($link['attribs']['']['length']))
+					{
+						$length = ceil($link['attribs']['']['length']);
+					}
+
+					// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+					$this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+				}
+			}
+
+			if ($enclosure = $this->get_item_tags('', 'enclosure'))
+			{
+				if (isset($enclosure[0]['attribs']['']['url']))
+				{
+					// Attributes
+					$bitrate = null;
+					$channels = null;
+					$duration = null;
+					$expression = null;
+					$framerate = null;
+					$height = null;
+					$javascript = null;
+					$lang = null;
+					$length = null;
+					$medium = null;
+					$samplingrate = null;
+					$type = null;
+					$url = null;
+					$width = null;
+
+					$url = $this->sanitize($enclosure[0]['attribs']['']['url'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($enclosure[0]));
+					if (isset($enclosure[0]['attribs']['']['type']))
+					{
+						$type = $this->sanitize($enclosure[0]['attribs']['']['type'], SIMPLEPIE_CONSTRUCT_TEXT);
+					}
+					if (isset($enclosure[0]['attribs']['']['length']))
+					{
+						$length = ceil($enclosure[0]['attribs']['']['length']);
+					}
+
+					// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+					$this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+				}
+			}
+
+			if (sizeof($this->data['enclosures']) == 0 && ($url || $type || $length || $bitrate || $captions_parent || $categories_parent || $channels || $copyrights_parent || $credits_parent || $description_parent || $duration_parent || $expression || $framerate || $hashes_parent || $height || $keywords_parent || $lang || $medium || $player_parent || $ratings_parent || $restrictions_parent || $samplingrate || $thumbnails_parent || $title_parent || $width))
+			{
+				// Since we don't have group or content for these, we'll just pass the '*_parent' variables directly to the constructor
+				$this->data['enclosures'][] =& new $this->feed->enclosure_class($url, $type, $length, $this->feed->javascript, $bitrate, $captions_parent, $categories_parent, $channels, $copyrights_parent, $credits_parent, $description_parent, $duration_parent, $expression, $framerate, $hashes_parent, $height, $keywords_parent, $lang, $medium, $player_parent, $ratings_parent, $restrictions_parent, $samplingrate, $thumbnails_parent, $title_parent, $width);
+			}
+
+			$this->data['enclosures'] = array_values(SimplePie_Misc::array_unique($this->data['enclosures']));
+		}
+		if (!empty($this->data['enclosures']))
+		{
+			return $this->data['enclosures'];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_latitude()
+	{
+		if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+		{
+			return (float) $match[1];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_longitude()
+	{
+		if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif (($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+		{
+			return (float) $match[2];
+		}
+		else
+		{
+			return null;
+		}
+	}
+	
+	function get_source()
+	{
+		if ($return = $this->get_item_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'source'))
+		{
+			return new $this->feed->source_class($this, $return[0]);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * Creates the add_to_* methods' return data
+	 *
+	 * @access private
+	 * @param string $item_url String to prefix to the item permalink
+	 * @param string $title_url String to prefix to the item title
+	 * (and suffix to the item permalink)
+	 * @return mixed URL if feed exists, false otherwise
+	 */
+	function add_to_service($item_url, $title_url = null, $summary_url = null)
+	{
+		if ($this->get_permalink() !== null)
+		{
+			$return = $this->sanitize($item_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_permalink());
+			if ($title_url !== null && $this->get_title() !== null)
+			{
+				$return .= $this->sanitize($title_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_title());
+			}
+			if ($summary_url !== null && $this->get_description() !== null)
+			{
+				$return .= $this->sanitize($summary_url, SIMPLEPIE_CONSTRUCT_IRI) . rawurlencode($this->get_description());
+			}
+			return $return;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function add_to_blinklist()
+	{
+		return $this->add_to_service('http://www.blinklist.com/index.php?Action=Blink/addblink.php&Description=&Url=', '&Title=');
+	}
+
+	function add_to_blogmarks()
+	{
+		return $this->add_to_service('http://blogmarks.net/my/new.php?mini=1&simple=1&url=', '&title=');
+	}
+
+	function add_to_delicious()
+	{
+		return $this->add_to_service('http://del.icio.us/post/?v=4&url=', '&title=');
+	}
+
+	function add_to_digg()
+	{
+		return $this->add_to_service('http://digg.com/submit?url=', '&title=', '&bodytext=');
+	}
+
+	function add_to_furl()
+	{
+		return $this->add_to_service('http://www.furl.net/storeIt.jsp?u=', '&t=');
+	}
+
+	function add_to_magnolia()
+	{
+		return $this->add_to_service('http://ma.gnolia.com/bookmarklet/add?url=', '&title=');
+	}
+
+	function add_to_myweb20()
+	{
+		return $this->add_to_service('http://myweb2.search.yahoo.com/myresults/bookmarklet?u=', '&t=');
+	}
+
+	function add_to_newsvine()
+	{
+		return $this->add_to_service('http://www.newsvine.com/_wine/save?u=', '&h=');
+	}
+
+	function add_to_reddit()
+	{
+		return $this->add_to_service('http://reddit.com/submit?url=', '&title=');
+	}
+
+	function add_to_segnalo()
+	{
+		return $this->add_to_service('http://segnalo.com/post.html.php?url=', '&title=');
+	}
+
+	function add_to_simpy()
+	{
+		return $this->add_to_service('http://www.simpy.com/simpy/LinkAdd.do?href=', '&title=');
+	}
+
+	function add_to_spurl()
+	{
+		return $this->add_to_service('http://www.spurl.net/spurl.php?v=3&url=', '&title=');
+	}
+
+	function add_to_wists()
+	{
+		return $this->add_to_service('http://wists.com/r.php?c=&r=', '&title=');
+	}
+
+	function search_technorati()
+	{
+		return $this->add_to_service('http://www.technorati.com/search/');
+	}
+}
+
+class SimplePie_Source
+{
+	var $item;
+	var $data = array();
+
+	function SimplePie_Source($item, $data)
+	{
+		$this->item = $item;
+		$this->data = $data;
+	}
+
+	function __toString()
+	{
+		return md5(serialize($this->data));
+	}
+	
+	/**
+	 * Remove items that link back to this before destroying this object
+	 */
+	function __destruct()
+	{
+		unset($this->item);
+	}
+
+	function get_source_tags($namespace, $tag)
+	{
+		if (isset($this->data['child'][$namespace][$tag]))
+		{
+			return $this->data['child'][$namespace][$tag];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_base($element = array())
+	{
+		return $this->item->get_base($element);
+	}
+
+	function sanitize($data, $type, $base = '')
+	{
+		return $this->item->sanitize($data, $type, $base);
+	}
+
+	function get_item()
+	{
+		return $this->item;
+	}
+
+	function get_title()
+	{
+		if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags('', 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'title'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_category($key = 0)
+	{
+		$categories = $this->get_categories();
+		if (isset($categories[$key]))
+		{
+			return $categories[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_categories()
+	{
+		$categories = array();
+
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'category') as $category)
+		{
+			$term = null;
+			$scheme = null;
+			$label = null;
+			if (isset($category['attribs']['']['term']))
+			{
+				$term = $this->sanitize($category['attribs']['']['term'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($category['attribs']['']['scheme']))
+			{
+				$scheme = $this->sanitize($category['attribs']['']['scheme'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($category['attribs']['']['label']))
+			{
+				$label = $this->sanitize($category['attribs']['']['label'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			$categories[] =& new $this->item->feed->category_class($term, $scheme, $label);
+		}
+		foreach ((array) $this->get_source_tags('', 'category') as $category)
+		{
+			$categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'subject') as $category)
+		{
+			$categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'subject') as $category)
+		{
+			$categories[] =& new $this->item->feed->category_class($this->sanitize($category['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+
+		if (!empty($categories))
+		{
+			return SimplePie_Misc::array_unique($categories);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_author($key = 0)
+	{
+		$authors = $this->get_authors();
+		if (isset($authors[$key]))
+		{
+			return $authors[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_authors()
+	{
+		$authors = array();
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'author') as $author)
+		{
+			$name = null;
+			$uri = null;
+			$email = null;
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+			{
+				$name = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+			{
+				$uri = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+			}
+			if (isset($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+			{
+				$email = $this->sanitize($author['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $uri !== null)
+			{
+				$authors[] =& new $this->item->feed->author_class($name, $uri, $email);
+			}
+		}
+		if ($author = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'author'))
+		{
+			$name = null;
+			$url = null;
+			$email = null;
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+			{
+				$name = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+			{
+				$url = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+			}
+			if (isset($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+			{
+				$email = $this->sanitize($author[0]['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $url !== null)
+			{
+				$authors[] =& new $this->item->feed->author_class($name, $url, $email);
+			}
+		}
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'creator') as $author)
+		{
+			$authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'creator') as $author)
+		{
+			$authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'author') as $author)
+		{
+			$authors[] =& new $this->item->feed->author_class($this->sanitize($author['data'], SIMPLEPIE_CONSTRUCT_TEXT), null, null);
+		}
+
+		if (!empty($authors))
+		{
+			return SimplePie_Misc::array_unique($authors);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_contributor($key = 0)
+	{
+		$contributors = $this->get_contributors();
+		if (isset($contributors[$key]))
+		{
+			return $contributors[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_contributors()
+	{
+		$contributors = array();
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'contributor') as $contributor)
+		{
+			$name = null;
+			$uri = null;
+			$email = null;
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data']))
+			{
+				$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data']))
+			{
+				$uri = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['uri'][0]));
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data']))
+			{
+				$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_10]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $uri !== null)
+			{
+				$contributors[] =& new $this->item->feed->author_class($name, $uri, $email);
+			}
+		}
+		foreach ((array) $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'contributor') as $contributor)
+		{
+			$name = null;
+			$url = null;
+			$email = null;
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data']))
+			{
+				$name = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['name'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data']))
+			{
+				$url = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['url'][0]));
+			}
+			if (isset($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data']))
+			{
+				$email = $this->sanitize($contributor['child'][SIMPLEPIE_NAMESPACE_ATOM_03]['email'][0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+			}
+			if ($name !== null || $email !== null || $url !== null)
+			{
+				$contributors[] =& new $this->item->feed->author_class($name, $url, $email);
+			}
+		}
+
+		if (!empty($contributors))
+		{
+			return SimplePie_Misc::array_unique($contributors);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_link($key = 0, $rel = 'alternate')
+	{
+		$links = $this->get_links($rel);
+		if (isset($links[$key]))
+		{
+			return $links[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	/**
+	 * Added for parity between the parent-level and the item/entry-level.
+	 */
+	function get_permalink()
+	{
+		return $this->get_link(0);
+	}
+
+	function get_links($rel = 'alternate')
+	{
+		if (!isset($this->data['links']))
+		{
+			$this->data['links'] = array();
+			if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'link'))
+			{
+				foreach ($links as $link)
+				{
+					if (isset($link['attribs']['']['href']))
+					{
+						$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+						$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+					}
+				}
+			}
+			if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'link'))
+			{
+				foreach ($links as $link)
+				{
+					if (isset($link['attribs']['']['href']))
+					{
+						$link_rel = (isset($link['attribs']['']['rel'])) ? $link['attribs']['']['rel'] : 'alternate';
+						$this->data['links'][$link_rel][] = $this->sanitize($link['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($link));
+
+					}
+				}
+			}
+			if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+			if ($links = $this->get_source_tags('', 'link'))
+			{
+				$this->data['links']['alternate'][] = $this->sanitize($links[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($links[0]));
+			}
+
+			$keys = array_keys($this->data['links']);
+			foreach ($keys as $key)
+			{
+				if (SimplePie_Misc::is_isegment_nz_nc($key))
+				{
+					if (isset($this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]))
+					{
+						$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] = array_merge($this->data['links'][$key], $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key]);
+						$this->data['links'][$key] =& $this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key];
+					}
+					else
+					{
+						$this->data['links'][SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY . $key] =& $this->data['links'][$key];
+					}
+				}
+				elseif (substr($key, 0, 41) == SIMPLEPIE_IANA_LINK_RELATIONS_REGISTRY)
+				{
+					$this->data['links'][substr($key, 41)] =& $this->data['links'][$key];
+				}
+				$this->data['links'][$key] = array_unique($this->data['links'][$key]);
+			}
+		}
+
+		if (isset($this->data['links'][$rel]))
+		{
+			return $this->data['links'][$rel];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_description()
+	{
+		if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'subtitle'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'tagline'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_10, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_RSS_090, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags('', 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_MAYBE_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'description'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'summary'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'subtitle'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_HTML, $this->get_base($return[0]));
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_copyright()
+	{
+		if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_10_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_03, 'copyright'))
+		{
+			return $this->sanitize($return[0]['data'], SimplePie_Misc::atom_03_construct_type($return[0]['attribs']), $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags('', 'copyright'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'rights'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_language()
+	{
+		if ($return = $this->get_source_tags('', 'language'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_11, 'language'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_DC_10, 'language'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		elseif (isset($this->data['xml_lang']))
+		{
+			return $this->sanitize($this->data['xml_lang'], SIMPLEPIE_CONSTRUCT_TEXT);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_latitude()
+	{
+		if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lat'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+		{
+			return (float) $match[1];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_longitude()
+	{
+		if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'long'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_W3C_BASIC_GEO, 'lon'))
+		{
+			return (float) $return[0]['data'];
+		}
+		elseif (($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_GEORSS, 'point')) && preg_match('/^((?:-)?[0-9]+(?:\.[0-9]+)) ((?:-)?[0-9]+(?:\.[0-9]+))$/', $return[0]['data'], $match))
+		{
+			return (float) $match[2];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_image_url()
+	{
+		if ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ITUNES, 'image'))
+		{
+			return $this->sanitize($return[0]['attribs']['']['href'], SIMPLEPIE_CONSTRUCT_IRI);
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'logo'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		elseif ($return = $this->get_source_tags(SIMPLEPIE_NAMESPACE_ATOM_10, 'icon'))
+		{
+			return $this->sanitize($return[0]['data'], SIMPLEPIE_CONSTRUCT_IRI, $this->get_base($return[0]));
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+class SimplePie_Author
+{
+	var $name;
+	var $link;
+	var $email;
+
+	// Constructor, used to input the data
+	function SimplePie_Author($name = null, $link = null, $email = null)
+	{
+		$this->name = $name;
+		$this->link = $link;
+		$this->email = $email;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_name()
+	{
+		if ($this->name !== null)
+		{
+			return $this->name;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_link()
+	{
+		if ($this->link !== null)
+		{
+			return $this->link;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_email()
+	{
+		if ($this->email !== null)
+		{
+			return $this->email;
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+class SimplePie_Category
+{
+	var $term;
+	var $scheme;
+	var $label;
+
+	// Constructor, used to input the data
+	function SimplePie_Category($term = null, $scheme = null, $label = null)
+	{
+		$this->term = $term;
+		$this->scheme = $scheme;
+		$this->label = $label;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_term()
+	{
+		if ($this->term !== null)
+		{
+			return $this->term;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_scheme()
+	{
+		if ($this->scheme !== null)
+		{
+			return $this->scheme;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_label()
+	{
+		if ($this->label !== null)
+		{
+			return $this->label;
+		}
+		else
+		{
+			return $this->get_term();
+		}
+	}
+}
+
+class SimplePie_Enclosure
+{
+	var $bitrate;
+	var $captions;
+	var $categories;
+	var $channels;
+	var $copyright;
+	var $credits;
+	var $description;
+	var $duration;
+	var $expression;
+	var $framerate;
+	var $handler;
+	var $hashes;
+	var $height;
+	var $javascript;
+	var $keywords;
+	var $lang;
+	var $length;
+	var $link;
+	var $medium;
+	var $player;
+	var $ratings;
+	var $restrictions;
+	var $samplingrate;
+	var $thumbnails;
+	var $title;
+	var $type;
+	var $width;
+
+	// Constructor, used to input the data
+	function SimplePie_Enclosure($link = null, $type = null, $length = null, $javascript = null, $bitrate = null, $captions = null, $categories = null, $channels = null, $copyright = null, $credits = null, $description = null, $duration = null, $expression = null, $framerate = null, $hashes = null, $height = null, $keywords = null, $lang = null, $medium = null, $player = null, $ratings = null, $restrictions = null, $samplingrate = null, $thumbnails = null, $title = null, $width = null)
+	{
+		$this->bitrate = $bitrate;
+		$this->captions = $captions;
+		$this->categories = $categories;
+		$this->channels = $channels;
+		$this->copyright = $copyright;
+		$this->credits = $credits;
+		$this->description = $description;
+		$this->duration = $duration;
+		$this->expression = $expression;
+		$this->framerate = $framerate;
+		$this->hashes = $hashes;
+		$this->height = $height;
+		$this->javascript = $javascript;
+		$this->keywords = $keywords;
+		$this->lang = $lang;
+		$this->length = $length;
+		$this->link = $link;
+		$this->medium = $medium;
+		$this->player = $player;
+		$this->ratings = $ratings;
+		$this->restrictions = $restrictions;
+		$this->samplingrate = $samplingrate;
+		$this->thumbnails = $thumbnails;
+		$this->title = $title;
+		$this->type = $type;
+		$this->width = $width;
+		if (class_exists('idna_convert'))
+		{
+			$idn =& new idna_convert;
+			$parsed = SimplePie_Misc::parse_url($link);
+			$this->link = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+		}
+		$this->handler = $this->get_handler(); // Needs to load last
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_bitrate()
+	{
+		if ($this->bitrate !== null)
+		{
+			return $this->bitrate;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_caption($key = 0)
+	{
+		$captions = $this->get_captions();
+		if (isset($captions[$key]))
+		{
+			return $captions[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_captions()
+	{
+		if ($this->captions !== null)
+		{
+			return $this->captions;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_category($key = 0)
+	{
+		$categories = $this->get_categories();
+		if (isset($categories[$key]))
+		{
+			return $categories[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_categories()
+	{
+		if ($this->categories !== null)
+		{
+			return $this->categories;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_channels()
+	{
+		if ($this->channels !== null)
+		{
+			return $this->channels;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_copyright()
+	{
+		if ($this->copyright !== null)
+		{
+			return $this->copyright;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_credit($key = 0)
+	{
+		$credits = $this->get_credits();
+		if (isset($credits[$key]))
+		{
+			return $credits[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_credits()
+	{
+		if ($this->credits !== null)
+		{
+			return $this->credits;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_description()
+	{
+		if ($this->description !== null)
+		{
+			return $this->description;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_duration($convert = false)
+	{
+		if ($this->duration !== null)
+		{
+			if ($convert)
+			{
+				$time = SimplePie_Misc::time_hms($this->duration);
+				return $time;
+			}
+			else
+			{
+				return $this->duration;
+			}
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_expression()
+	{
+		if ($this->expression !== null)
+		{
+			return $this->expression;
+		}
+		else
+		{
+			return 'full';
+		}
+	}
+
+	function get_extension()
+	{
+		if ($this->link !== null)
+		{
+			$url = SimplePie_Misc::parse_url($this->link);
+			if ($url['path'] !== '')
+			{
+				return pathinfo($url['path'], PATHINFO_EXTENSION);
+			}
+		}
+		return null;
+	}
+
+	function get_framerate()
+	{
+		if ($this->framerate !== null)
+		{
+			return $this->framerate;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_handler()
+	{
+		return $this->get_real_type(true);
+	}
+
+	function get_hash($key = 0)
+	{
+		$hashes = $this->get_hashes();
+		if (isset($hashes[$key]))
+		{
+			return $hashes[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_hashes()
+	{
+		if ($this->hashes !== null)
+		{
+			return $this->hashes;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_height()
+	{
+		if ($this->height !== null)
+		{
+			return $this->height;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_language()
+	{
+		if ($this->lang !== null)
+		{
+			return $this->lang;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_keyword($key = 0)
+	{
+		$keywords = $this->get_keywords();
+		if (isset($keywords[$key]))
+		{
+			return $keywords[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_keywords()
+	{
+		if ($this->keywords !== null)
+		{
+			return $this->keywords;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_length()
+	{
+		if ($this->length !== null)
+		{
+			return $this->length;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_link()
+	{
+		if ($this->link !== null)
+		{
+			return urldecode($this->link);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_medium()
+	{
+		if ($this->medium !== null)
+		{
+			return $this->medium;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_player()
+	{
+		if ($this->player !== null)
+		{
+			return $this->player;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_rating($key = 0)
+	{
+		$ratings = $this->get_ratings();
+		if (isset($ratings[$key]))
+		{
+			return $ratings[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_ratings()
+	{
+		if ($this->ratings !== null)
+		{
+			return $this->ratings;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_restriction($key = 0)
+	{
+		$restrictions = $this->get_restrictions();
+		if (isset($restrictions[$key]))
+		{
+			return $restrictions[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_restrictions()
+	{
+		if ($this->restrictions !== null)
+		{
+			return $this->restrictions;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_sampling_rate()
+	{
+		if ($this->samplingrate !== null)
+		{
+			return $this->samplingrate;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_size()
+	{
+		$length = $this->get_length();
+		if ($length !== null)
+		{
+			return round($length/1048576, 2);
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_thumbnail($key = 0)
+	{
+		$thumbnails = $this->get_thumbnails();
+		if (isset($thumbnails[$key]))
+		{
+			return $thumbnails[$key];
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_thumbnails()
+	{
+		if ($this->thumbnails !== null)
+		{
+			return $this->thumbnails;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_title()
+	{
+		if ($this->title !== null)
+		{
+			return $this->title;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_type()
+	{
+		if ($this->type !== null)
+		{
+			return $this->type;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_width()
+	{
+		if ($this->width !== null)
+		{
+			return $this->width;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function native_embed($options='')
+	{
+		return $this->embed($options, true);
+	}
+
+	/**
+	 * @todo If the dimensions for media:content are defined, use them when width/height are set to 'auto'.
+	 */
+	function embed($options = '', $native = false)
+	{
+		// Set up defaults
+		$audio = '';
+		$video = '';
+		$alt = '';
+		$altclass = '';
+		$loop = 'false';
+		$width = 'auto';
+		$height = 'auto';
+		$bgcolor = '#ffffff';
+		$mediaplayer = '';
+		$widescreen = false;
+		$handler = $this->get_handler();
+		$type = $this->get_real_type();
+
+		// Process options and reassign values as necessary
+		if (is_array($options))
+		{
+			extract($options);
+		}
+		else
+		{
+			$options = explode(',', $options);
+			foreach($options as $option)
+			{
+				$opt = explode(':', $option, 2);
+				if (isset($opt[0], $opt[1]))
+				{
+					$opt[0] = trim($opt[0]);
+					$opt[1] = trim($opt[1]);
+					switch ($opt[0])
+					{
+						case 'audio':
+							$audio = $opt[1];
+							break;
+
+						case 'video':
+							$video = $opt[1];
+							break;
+
+						case 'alt':
+							$alt = $opt[1];
+							break;
+
+						case 'altclass':
+							$altclass = $opt[1];
+							break;
+
+						case 'loop':
+							$loop = $opt[1];
+							break;
+
+						case 'width':
+							$width = $opt[1];
+							break;
+
+						case 'height':
+							$height = $opt[1];
+							break;
+
+						case 'bgcolor':
+							$bgcolor = $opt[1];
+							break;
+
+						case 'mediaplayer':
+							$mediaplayer = $opt[1];
+							break;
+
+						case 'widescreen':
+							$widescreen = $opt[1];
+							break;
+					}
+				}
+			}
+		}
+
+		$mime = explode('/', $type, 2);
+		$mime = $mime[0];
+
+		// Process values for 'auto'
+		if ($width == 'auto')
+		{
+			if ($mime == 'video')
+			{
+				if ($height == 'auto')
+				{
+					$width = 480;
+				}
+				elseif ($widescreen)
+				{
+					$width = round((intval($height)/9)*16);
+				}
+				else
+				{
+					$width = round((intval($height)/3)*4);
+				}
+			}
+			else
+			{
+				$width = '100%';
+			}
+		}
+
+		if ($height == 'auto')
+		{
+			if ($mime == 'audio')
+			{
+				$height = 0;
+			}
+			elseif ($mime == 'video')
+			{
+				if ($width == 'auto')
+				{
+					if ($widescreen)
+					{
+						$height = 270;
+					}
+					else
+					{
+						$height = 360;
+					}
+				}
+				elseif ($widescreen)
+				{
+					$height = round((intval($width)/16)*9);
+				}
+				else
+				{
+					$height = round((intval($width)/4)*3);
+				}
+			}
+			else
+			{
+				$height = 376;
+			}
+		}
+		elseif ($mime == 'audio')
+		{
+			$height = 0;
+		}
+
+		// Set proper placeholder value
+		if ($mime == 'audio')
+		{
+			$placeholder = $audio;
+		}
+		elseif ($mime == 'video')
+		{
+			$placeholder = $video;
+		}
+
+		$embed = '';
+
+		// Make sure the JS library is included
+		if (!$native)
+		{
+			static $javascript_outputted = null;
+			if (!$javascript_outputted && $this->javascript)
+			{
+				$embed .= '<script type="text/javascript" src="?' . htmlspecialchars($this->javascript) . '"></script>';
+				$javascript_outputted = true;
+			}
+		}
+
+		// Odeo Feed MP3's
+		if ($handler == 'odeo')
+		{
+			if ($native)
+			{
+				$embed .= '<embed src="http://odeo.com/flash/audio_player_fullsize.swf" pluginspage="http://adobe.com/go/getflashplayer" type="application/x-shockwave-flash" quality="high" width="440" height="80" wmode="transparent" allowScriptAccess="any" flashvars="valid_sample_rate=true&external_url=' . $this->get_link() . '"></embed>';
+			}
+			else
+			{
+				$embed .= '<script type="text/javascript">embed_odeo("' . $this->get_link() . '");</script>';
+			}
+		}
+
+		// Flash
+		elseif ($handler == 'flash')
+		{
+			if ($native)
+			{
+				$embed .= "<embed src=\"" . $this->get_link() . "\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"$type\" quality=\"high\" width=\"$width\" height=\"$height\" bgcolor=\"$bgcolor\" loop=\"$loop\"></embed>";
+			}
+			else
+			{
+				$embed .= "<script type='text/javascript'>embed_flash('$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$loop', '$type');</script>";
+			}
+		}
+
+		// Flash Media Player file types.
+		// Preferred handler for MP3 file types.
+		elseif ($handler == 'fmedia' || ($handler == 'mp3' && $mediaplayer != ''))
+		{
+			$height += 20;
+			if ($native)
+			{
+				$embed .= "<embed src=\"$mediaplayer\" pluginspage=\"http://adobe.com/go/getflashplayer\" type=\"application/x-shockwave-flash\" quality=\"high\" width=\"$width\" height=\"$height\" wmode=\"transparent\" flashvars=\"file=" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "&autostart=false&repeat=$loop&showdigits=true&showfsbutton=false\"></embed>";
+			}
+			else
+			{
+				$embed .= "<script type='text/javascript'>embed_flv('$width', '$height', '" . rawurlencode($this->get_link().'?file_extension=.'.$this->get_extension()) . "', '$placeholder', '$loop', '$mediaplayer');</script>";
+			}
+		}
+
+		// QuickTime 7 file types.  Need to test with QuickTime 6.
+		// Only handle MP3's if the Flash Media Player is not present.
+		elseif ($handler == 'quicktime' || ($handler == 'mp3' && $mediaplayer == ''))
+		{
+			$height += 16;
+			if ($native)
+			{
+				if ($placeholder != ""){
+					$embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" href=\"" . $this->get_link() . "\" src=\"$placeholder\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"false\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+				}
+				else {
+					$embed .= "<embed type=\"$type\" style=\"cursor:hand; cursor:pointer;\" src=\"" . $this->get_link() . "\" width=\"$width\" height=\"$height\" autoplay=\"false\" target=\"myself\" controller=\"true\" loop=\"$loop\" scale=\"aspect\" bgcolor=\"$bgcolor\" pluginspage=\"http://apple.com/quicktime/download/\"></embed>";
+				}
+			}
+			else
+			{
+				$embed .= "<script type='text/javascript'>embed_quicktime('$type', '$bgcolor', '$width', '$height', '" . $this->get_link() . "', '$placeholder', '$loop');</script>";
+			}
+		}
+
+		// Windows Media
+		elseif ($handler == 'wmedia')
+		{
+			$height += 45;
+			if ($native)
+			{
+				$embed .= "<embed type=\"application/x-mplayer2\" src=\"" . $this->get_link() . "\" autosize=\"1\" width=\"$width\" height=\"$height\" showcontrols=\"1\" showstatusbar=\"0\" showdisplay=\"0\" autostart=\"0\"></embed>";
+			}
+			else
+			{
+				$embed .= "<script type='text/javascript'>embed_wmedia('$width', '$height', '" . $this->get_link() . "');</script>";
+			}
+		}
+
+		// Everything else
+		else $embed .= '<a href="' . $this->get_link() . '" class="' . $altclass . '">' . $alt . '</a>';
+
+		return $embed;
+	}
+
+	function get_real_type($find_handler = false)
+	{
+		// If it's Odeo, let's get it out of the way.
+		if (substr(strtolower($this->get_link()), 0, 15) == 'http://odeo.com')
+		{
+			return 'odeo';
+		}
+
+		// Mime-types by handler.
+		$types_flash = array('application/x-shockwave-flash', 'application/futuresplash'); // Flash
+		$types_fmedia = array('video/flv', 'video/x-flv'); // Flash Media Player
+		$types_quicktime = array('audio/3gpp', 'audio/3gpp2', 'audio/aac', 'audio/x-aac', 'audio/aiff', 'audio/x-aiff', 'audio/mid', 'audio/midi', 'audio/x-midi', 'audio/mp4', 'audio/m4a', 'audio/x-m4a', 'audio/wav', 'audio/x-wav', 'video/3gpp', 'video/3gpp2', 'video/m4v', 'video/x-m4v', 'video/mp4', 'video/mpeg', 'video/x-mpeg', 'video/quicktime', 'video/sd-video'); // QuickTime
+		$types_wmedia = array('application/asx', 'application/x-mplayer2', 'audio/x-ms-wma', 'audio/x-ms-wax', 'video/x-ms-asf-plugin', 'video/x-ms-asf', 'video/x-ms-wm', 'video/x-ms-wmv', 'video/x-ms-wvx'); // Windows Media
+		$types_mp3 = array('audio/mp3', 'audio/x-mp3', 'audio/mpeg', 'audio/x-mpeg'); // MP3
+
+		if ($this->get_type() !== null)
+		{
+			$type = strtolower($this->type);
+		}
+		else
+		{
+			$type = null;
+		}
+
+		// If we encounter an unsupported mime-type, check the file extension and guess intelligently.
+		if (!in_array($type, array_merge($types_flash, $types_fmedia, $types_quicktime, $types_wmedia, $types_mp3)))
+		{
+			switch (strtolower($this->get_extension()))
+			{
+				// Audio mime-types
+				case 'aac':
+				case 'adts':
+					$type = 'audio/acc';
+					break;
+
+				case 'aif':
+				case 'aifc':
+				case 'aiff':
+				case 'cdda':
+					$type = 'audio/aiff';
+					break;
+
+				case 'bwf':
+					$type = 'audio/wav';
+					break;
+
+				case 'kar':
+				case 'mid':
+				case 'midi':
+				case 'smf':
+					$type = 'audio/midi';
+					break;
+
+				case 'm4a':
+					$type = 'audio/x-m4a';
+					break;
+
+				case 'mp3':
+				case 'swa':
+					$type = 'audio/mp3';
+					break;
+
+				case 'wav':
+					$type = 'audio/wav';
+					break;
+
+				case 'wax':
+					$type = 'audio/x-ms-wax';
+					break;
+
+				case 'wma':
+					$type = 'audio/x-ms-wma';
+					break;
+
+				// Video mime-types
+				case '3gp':
+				case '3gpp':
+					$type = 'video/3gpp';
+					break;
+
+				case '3g2':
+				case '3gp2':
+					$type = 'video/3gpp2';
+					break;
+
+				case 'asf':
+					$type = 'video/x-ms-asf';
+					break;
+
+				case 'flv':
+					$type = 'video/x-flv';
+					break;
+
+				case 'm1a':
+				case 'm1s':
+				case 'm1v':
+				case 'm15':
+				case 'm75':
+				case 'mp2':
+				case 'mpa':
+				case 'mpeg':
+				case 'mpg':
+				case 'mpm':
+				case 'mpv':
+					$type = 'video/mpeg';
+					break;
+
+				case 'm4v':
+					$type = 'video/x-m4v';
+					break;
+
+				case 'mov':
+				case 'qt':
+					$type = 'video/quicktime';
+					break;
+
+				case 'mp4':
+				case 'mpg4':
+					$type = 'video/mp4';
+					break;
+
+				case 'sdv':
+					$type = 'video/sd-video';
+					break;
+
+				case 'wm':
+					$type = 'video/x-ms-wm';
+					break;
+
+				case 'wmv':
+					$type = 'video/x-ms-wmv';
+					break;
+
+				case 'wvx':
+					$type = 'video/x-ms-wvx';
+					break;
+
+				// Flash mime-types
+				case 'spl':
+					$type = 'application/futuresplash';
+					break;
+
+				case 'swf':
+					$type = 'application/x-shockwave-flash';
+					break;
+			}
+		}
+
+		if ($find_handler)
+		{
+			if (in_array($type, $types_flash))
+			{
+				return 'flash';
+			}
+			elseif (in_array($type, $types_fmedia))
+			{
+				return 'fmedia';
+			}
+			elseif (in_array($type, $types_quicktime))
+			{
+				return 'quicktime';
+			}
+			elseif (in_array($type, $types_wmedia))
+			{
+				return 'wmedia';
+			}
+			elseif (in_array($type, $types_mp3))
+			{
+				return 'mp3';
+			}
+			else
+			{
+				return null;
+			}
+		}
+		else
+		{
+			return $type;
+		}
+	}
+}
+
+class SimplePie_Caption
+{
+	var $type;
+	var $lang;
+	var $startTime;
+	var $endTime;
+	var $text;
+
+	// Constructor, used to input the data
+	function SimplePie_Caption($type = null, $lang = null, $startTime = null, $endTime = null, $text = null)
+	{
+		$this->type = $type;
+		$this->lang = $lang;
+		$this->startTime = $startTime;
+		$this->endTime = $endTime;
+		$this->text = $text;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_endtime()
+	{
+		if ($this->endTime !== null)
+		{
+			return $this->endTime;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_language()
+	{
+		if ($this->lang !== null)
+		{
+			return $this->lang;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_starttime()
+	{
+		if ($this->startTime !== null)
+		{
+			return $this->startTime;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_text()
+	{
+		if ($this->text !== null)
+		{
+			return $this->text;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_type()
+	{
+		if ($this->type !== null)
+		{
+			return $this->type;
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+class SimplePie_Credit
+{
+	var $role;
+	var $scheme;
+	var $name;
+
+	// Constructor, used to input the data
+	function SimplePie_Credit($role = null, $scheme = null, $name = null)
+	{
+		$this->role = $role;
+		$this->scheme = $scheme;
+		$this->name = $name;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_role()
+	{
+		if ($this->role !== null)
+		{
+			return $this->role;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_scheme()
+	{
+		if ($this->scheme !== null)
+		{
+			return $this->scheme;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_name()
+	{
+		if ($this->name !== null)
+		{
+			return $this->name;
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+class SimplePie_Copyright
+{
+	var $url;
+	var $label;
+
+	// Constructor, used to input the data
+	function SimplePie_Copyright($url = null, $label = null)
+	{
+		$this->url = $url;
+		$this->label = $label;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_url()
+	{
+		if ($this->url !== null)
+		{
+			return $this->url;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_attribution()
+	{
+		if ($this->label !== null)
+		{
+			return $this->label;
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+class SimplePie_Rating
+{
+	var $scheme;
+	var $value;
+
+	// Constructor, used to input the data
+	function SimplePie_Rating($scheme = null, $value = null)
+	{
+		$this->scheme = $scheme;
+		$this->value = $value;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_scheme()
+	{
+		if ($this->scheme !== null)
+		{
+			return $this->scheme;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_value()
+	{
+		if ($this->value !== null)
+		{
+			return $this->value;
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+class SimplePie_Restriction
+{
+	var $relationship;
+	var $type;
+	var $value;
+
+	// Constructor, used to input the data
+	function SimplePie_Restriction($relationship = null, $type = null, $value = null)
+	{
+		$this->relationship = $relationship;
+		$this->type = $type;
+		$this->value = $value;
+	}
+
+	function __toString()
+	{
+		// There is no $this->data here
+		return md5(serialize($this));
+	}
+
+	function get_relationship()
+	{
+		if ($this->relationship !== null)
+		{
+			return $this->relationship;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_type()
+	{
+		if ($this->type !== null)
+		{
+			return $this->type;
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	function get_value()
+	{
+		if ($this->value !== null)
+		{
+			return $this->value;
+		}
+		else
+		{
+			return null;
+		}
+	}
+}
+
+/**
+ * @todo Move to properly supporting RFC2616 (HTTP/1.1)
+ */
+class SimplePie_File
+{
+	var $url;
+	var $useragent;
+	var $success = true;
+	var $headers = array();
+	var $body;
+	var $status_code;
+	var $redirects = 0;
+	var $error;
+	var $method = SIMPLEPIE_FILE_SOURCE_NONE;
+
+	function SimplePie_File($url, $timeout = 10, $redirects = 5, $headers = null, $useragent = null, $force_fsockopen = false)
+	{
+		if (class_exists('idna_convert'))
+		{
+			$idn =& new idna_convert;
+			$parsed = SimplePie_Misc::parse_url($url);
+			$url = SimplePie_Misc::compress_parse_url($parsed['scheme'], $idn->encode($parsed['authority']), $parsed['path'], $parsed['query'], $parsed['fragment']);
+		}
+		$this->url = $url;
+		$this->useragent = $useragent;
+		if (preg_match('/^http(s)?:\/\//i', $url))
+		{
+			if ($useragent === null)
+			{
+				$useragent = ini_get('user_agent');
+				$this->useragent = $useragent;
+			}
+			if (!is_array($headers))
+			{
+				$headers = array();
+			}
+			if (!$force_fsockopen && function_exists('curl_exec'))
+			{
+				$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_CURL;
+				$fp = curl_init();
+				$headers2 = array();
+				foreach ($headers as $key => $value)
+				{
+					$headers2[] = "$key: $value";
+				}
+				if (version_compare(SimplePie_Misc::get_curl_version(), '7.10.5', '>='))
+				{
+					curl_setopt($fp, CURLOPT_ENCODING, '');
+				}
+				curl_setopt($fp, CURLOPT_URL, $url);
+				curl_setopt($fp, CURLOPT_HEADER, 1);
+				curl_setopt($fp, CURLOPT_RETURNTRANSFER, 1);
+				curl_setopt($fp, CURLOPT_TIMEOUT, $timeout);
+				curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
+				curl_setopt($fp, CURLOPT_REFERER, $url);
+				curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
+				curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
+				if (!ini_get('open_basedir') && !ini_get('safe_mode') && version_compare(SimplePie_Misc::get_curl_version(), '7.15.2', '>='))
+				{
+					curl_setopt($fp, CURLOPT_FOLLOWLOCATION, 1);
+					curl_setopt($fp, CURLOPT_MAXREDIRS, $redirects);
+				}
+
+				$this->headers = curl_exec($fp);
+				if (curl_errno($fp) == 23 || curl_errno($fp) == 61)
+				{
+					curl_setopt($fp, CURLOPT_ENCODING, 'none');
+					$this->headers = curl_exec($fp);
+				}
+				if (curl_errno($fp))
+				{
+					$this->error = 'cURL error ' . curl_errno($fp) . ': ' . curl_error($fp);
+					$this->success = false;
+				}
+				else
+				{
+					$info = curl_getinfo($fp);
+					curl_close($fp);
+					$this->headers = explode("\r\n\r\n", $this->headers, $info['redirect_count'] + 1);
+					$this->headers = array_pop($this->headers);
+					$parser =& new SimplePie_HTTP_Parser($this->headers);
+					if ($parser->parse())
+					{
+						$this->headers = $parser->headers;
+						$this->body = $parser->body;
+						$this->status_code = $parser->status_code;
+						if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+						{
+							$this->redirects++;
+							$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+							return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+						}
+					}
+				}
+			}
+			else
+			{
+				$this->method = SIMPLEPIE_FILE_SOURCE_REMOTE | SIMPLEPIE_FILE_SOURCE_FSOCKOPEN;
+				$url_parts = parse_url($url);
+				if (isset($url_parts['scheme']) && strtolower($url_parts['scheme']) == 'https')
+				{
+					$url_parts['host'] = "ssl://$url_parts[host]";
+					$url_parts['port'] = 443;
+				}
+				if (!isset($url_parts['port']))
+				{
+					$url_parts['port'] = 80;
+				}
+				$fp = @fsockopen($url_parts['host'], $url_parts['port'], $errno, $errstr, $timeout);
+				if (!$fp)
+				{
+					$this->error = 'fsockopen error: ' . $errstr;
+					$this->success = false;
+				}
+				else
+				{
+					stream_set_timeout($fp, $timeout);
+					if (isset($url_parts['path']))
+					{
+						if (isset($url_parts['query']))
+						{
+							$get = "$url_parts[path]?$url_parts[query]";
+						}
+						else
+						{
+							$get = $url_parts['path'];
+						}
+					}
+					else
+					{
+						$get = '/';
+					}
+					$out = "GET $get HTTP/1.0\r\n";
+					$out .= "Host: $url_parts[host]\r\n";
+					$out .= "User-Agent: $useragent\r\n";
+					if (function_exists('gzinflate'))
+					{
+						$out .= "Accept-Encoding: gzip,deflate\r\n";
+					}
+
+					if (isset($url_parts['user']) && isset($url_parts['pass']))
+					{
+						$out .= "Authorization: Basic " . base64_encode("$url_parts[user]:$url_parts[pass]") . "\r\n";
+					}
+					foreach ($headers as $key => $value)
+					{
+						$out .= "$key: $value\r\n";
+					}
+					$out .= "Connection: Close\r\n\r\n";
+					fwrite($fp, $out);
+
+					$info = stream_get_meta_data($fp);
+
+					$this->headers = '';
+					while (!$info['eof'] && !$info['timed_out'])
+					{
+						$this->headers .= fread($fp, 1160);
+						$info = stream_get_meta_data($fp);
+					}
+					if (!$info['timed_out'])
+					{
+						$parser =& new SimplePie_HTTP_Parser($this->headers);
+						if ($parser->parse())
+						{
+							$this->headers = $parser->headers;
+							$this->body = $parser->body;
+							$this->status_code = $parser->status_code;
+							if (($this->status_code == 300 || $this->status_code == 301 || $this->status_code == 302 || $this->status_code == 303 || $this->status_code == 307 || $this->status_code > 307 && $this->status_code < 400) && isset($this->headers['location']) && $this->redirects < $redirects)
+							{
+								$this->redirects++;
+								$location = SimplePie_Misc::absolutize_url($this->headers['location'], $url);
+								return $this->SimplePie_File($location, $timeout, $redirects, $headers, $useragent, $force_fsockopen);
+							}
+							if (isset($this->headers['content-encoding']) && ($this->headers['content-encoding'] == 'gzip' || $this->headers['content-encoding'] == 'deflate'))
+							{
+								if (substr($this->body, 0, 8) == "\x1f\x8b\x08\x00\x00\x00\x00\x00")
+								{
+									$this->body = substr($this->body, 10);
+								}
+								$this->body = gzinflate($this->body);
+							}
+						}
+					}
+					else
+					{
+						$this->error = 'fsocket timed out';
+						$this->success = false;
+					}
+					fclose($fp);
+				}
+			}
+		}
+		else
+		{
+			$this->method = SIMPLEPIE_FILE_SOURCE_LOCAL | SIMPLEPIE_FILE_SOURCE_FILE_GET_CONTENTS;
+			if (!$this->body = file_get_contents($url))
+			{
+				$this->error = 'file_get_contents could not read the file';
+				$this->success = false;
+			}
+		}
+	}
+}
+
+/**
+ * HTTP Response Parser
+ *
+ * @package SimplePie
+ */
+class SimplePie_HTTP_Parser
+{
+	/**
+	 * HTTP Version
+	 *
+	 * @access public
+	 * @var float
+	 */
+	var $http_version = 0.0;
+
+	/**
+	 * Status code
+	 *
+	 * @access public
+	 * @var int
+	 */
+	var $status_code = 0;
+
+	/**
+	 * Reason phrase
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $reason = '';
+
+	/**
+	 * Key/value pairs of the headers
+	 *
+	 * @access public
+	 * @var array
+	 */
+	var $headers = array();
+
+	/**
+	 * Body of the response
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $body = '';
+
+	/**
+	 * Current state of the state machine
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $state = 'http_version';
+
+	/**
+	 * Input data
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $data = '';
+
+	/**
+	 * Input data length (to avoid calling strlen() everytime this is needed)
+	 *
+	 * @access private
+	 * @var int
+	 */
+	var $data_length = 0;
+
+	/**
+	 * Current position of the pointer
+	 *
+	 * @var int
+	 * @access private
+	 */
+	var $position = 0;
+
+	/**
+	 * Name of the hedaer currently being parsed
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $name = '';
+
+	/**
+	 * Value of the hedaer currently being parsed
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $value = '';
+
+	/**
+	 * Create an instance of the class with the input data
+	 *
+	 * @access public
+	 * @param string $data Input data
+	 */
+	function SimplePie_HTTP_Parser($data)
+	{
+		$this->data = $data;
+		$this->data_length = strlen($this->data);
+	}
+
+	/**
+	 * Parse the input data
+	 *
+	 * @access public
+	 * @return bool true on success, false on failure
+	 */
+	function parse()
+	{
+		while ($this->state && $this->state !== 'emit' && $this->has_data())
+		{
+			$state = $this->state;
+			$this->$state();
+		}
+		$this->data = '';
+		if ($this->state === 'emit' || $this->state === 'body')
+		{
+			return true;
+		}
+		else
+		{
+			$this->http_version = '';
+			$this->status_code = '';
+			$this->reason = '';
+			$this->headers = array();
+			$this->body = '';
+			return false;
+		}
+	}
+
+	/**
+	 * Check whether there is data beyond the pointer
+	 *
+	 * @access private
+	 * @return bool true if there is further data, false if not
+	 */
+	function has_data()
+	{
+		return (bool) ($this->position < $this->data_length);
+	}
+
+	/**
+	 * See if the next character is LWS
+	 *
+	 * @access private
+	 * @return bool true if the next character is LWS, false if not
+	 */
+	function is_linear_whitespace()
+	{
+		return (bool) ($this->data[$this->position] === "\x09"
+			|| $this->data[$this->position] === "\x20"
+			|| ($this->data[$this->position] === "\x0A"
+				&& isset($this->data[$this->position + 1])
+				&& ($this->data[$this->position + 1] === "\x09" || $this->data[$this->position + 1] === "\x20")));
+	}
+
+	/**
+	 * Parse the HTTP version
+	 *
+	 * @access private
+	 */
+	function http_version()
+	{
+		if (strpos($this->data, "\x0A") !== false && strtoupper(substr($this->data, 0, 5)) === 'HTTP/')
+		{
+			$len = strspn($this->data, '0123456789.', 5);
+			$this->http_version = substr($this->data, 5, $len);
+			$this->position += 5 + $len;
+			if (substr_count($this->http_version, '.') <= 1)
+			{
+				$this->http_version = (float) $this->http_version;
+				$this->position += strspn($this->data, "\x09\x20", $this->position);
+				$this->state = 'status';
+			}
+			else
+			{
+				$this->state = false;
+			}
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+
+	/**
+	 * Parse the status code
+	 *
+	 * @access private
+	 */
+	function status()
+	{
+		if ($len = strspn($this->data, '0123456789', $this->position))
+		{
+			$this->status_code = (int) substr($this->data, $this->position, $len);
+			$this->position += $len;
+			$this->state = 'reason';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+
+	/**
+	 * Parse the reason phrase
+	 *
+	 * @access private
+	 */
+	function reason()
+	{
+		$len = strcspn($this->data, "\x0A", $this->position);
+		$this->reason = trim(substr($this->data, $this->position, $len), "\x09\x0D\x20");
+		$this->position += $len + 1;
+		$this->state = 'new_line';
+	}
+
+	/**
+	 * Deal with a new line, shifting data around as needed
+	 *
+	 * @access private
+	 */
+	function new_line()
+	{
+		$this->value = trim($this->value, "\x0D\x20");
+		if ($this->name !== '' && $this->value !== '')
+		{
+			$this->name = strtolower($this->name);
+			if (isset($this->headers[$this->name]))
+			{
+				$this->headers[$this->name] .= ', ' . $this->value;
+			}
+			else
+			{
+				$this->headers[$this->name] = $this->value;
+			}
+		}
+		$this->name = '';
+		$this->value = '';
+		if (substr($this->data[$this->position], 0, 2) === "\x0D\x0A")
+		{
+			$this->position += 2;
+			$this->state = 'body';
+		}
+		elseif ($this->data[$this->position] === "\x0A")
+		{
+			$this->position++;
+			$this->state = 'body';
+		}
+		else
+		{
+			$this->state = 'name';
+		}
+	}
+
+	/**
+	 * Parse a header name
+	 *
+	 * @access private
+	 */
+	function name()
+	{
+		$len = strcspn($this->data, "\x0A:", $this->position);
+		if (isset($this->data[$this->position + $len]))
+		{
+			if ($this->data[$this->position + $len] === "\x0A")
+			{
+				$this->position += $len;
+				$this->state = 'new_line';
+			}
+			else
+			{
+				$this->name = substr($this->data, $this->position, $len);
+				$this->position += $len + 1;
+				$this->state = 'value';
+			}
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+
+	/**
+	 * Parse LWS, replacing consecutive LWS characters with a single space
+	 *
+	 * @access private
+	 */
+	function linear_whitespace()
+	{
+		do
+		{
+			if (substr($this->data, $this->position, 2) === "\x0D\x0A")
+			{
+				$this->position += 2;
+			}
+			elseif ($this->data[$this->position] === "\x0A")
+			{
+				$this->position++;
+			}
+			$this->position += strspn($this->data, "\x09\x20", $this->position);
+		} while ($this->has_data() && $this->is_linear_whitespace());
+		$this->value .= "\x20";
+	}
+
+	/**
+	 * See what state to move to while within non-quoted header values
+	 *
+	 * @access private
+	 */
+	function value()
+	{
+		if ($this->is_linear_whitespace())
+		{
+			$this->linear_whitespace();
+		}
+		else
+		{
+			switch ($this->data[$this->position])
+			{
+				case '"':
+					$this->position++;
+					$this->state = 'quote';
+					break;
+
+				case "\x0A":
+					$this->position++;
+					$this->state = 'new_line';
+					break;
+
+				default:
+					$this->state = 'value_char';
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Parse a header value while outside quotes
+	 *
+	 * @access private
+	 */
+	function value_char()
+	{
+		$len = strcspn($this->data, "\x09\x20\x0A\"", $this->position);
+		$this->value .= substr($this->data, $this->position, $len);
+		$this->position += $len;
+		$this->state = 'value';
+	}
+
+	/**
+	 * See what state to move to while within quoted header values
+	 *
+	 * @access private
+	 */
+	function quote()
+	{
+		if ($this->is_linear_whitespace())
+		{
+			$this->linear_whitespace();
+		}
+		else
+		{
+			switch ($this->data[$this->position])
+			{
+				case '"':
+					$this->position++;
+					$this->state = 'value';
+					break;
+
+				case "\x0A":
+					$this->position++;
+					$this->state = 'new_line';
+					break;
+
+				case '\\':
+					$this->position++;
+					$this->state = 'quote_escaped';
+					break;
+
+				default:
+					$this->state = 'quote_char';
+					break;
+			}
+		}
+	}
+
+	/**
+	 * Parse a header value while within quotes
+	 *
+	 * @access private
+	 */
+	function quote_char()
+	{
+		$len = strcspn($this->data, "\x09\x20\x0A\"\\", $this->position);
+		$this->value .= substr($this->data, $this->position, $len);
+		$this->position += $len;
+		$this->state = 'value';
+	}
+
+	/**
+	 * Parse an escaped character within quotes
+	 *
+	 * @access private
+	 */
+	function quote_escaped()
+	{
+		$this->value .= $this->data[$this->position];
+		$this->position++;
+		$this->state = 'quote';
+	}
+
+	/**
+	 * Parse the body
+	 *
+	 * @access private
+	 */
+	function body()
+	{
+		$this->body = substr($this->data, $this->position);
+		$this->state = 'emit';
+	}
+}
+
+class SimplePie_Cache
+{
+	/**
+	 * Don't call the constructor. Please.
+	 *
+	 * @access private
+	 */
+	function SimplePie_Cache()
+	{
+		trigger_error('Please call SimplePie_Cache::create() instead of the constructor', E_USER_ERROR);
+	}
+
+	/**
+	 * Create a new SimplePie_Cache object
+	 *
+	 * @static
+	 * @access public
+	 */
+	function create($location, $filename, $extension)
+	{
+		return new SimplePie_Cache_File($location, $filename, $extension);
+	}
+}
+
+class SimplePie_Cache_File
+{
+	var $location;
+	var $filename;
+	var $extension;
+	var $name;
+
+	function SimplePie_Cache_File($location, $filename, $extension)
+	{
+		$this->location = $location;
+		$this->filename = rawurlencode($filename);
+		$this->extension = rawurlencode($extension);
+		$this->name = "$location/$this->filename.$this->extension";
+	}
+
+	function save($data)
+	{
+		if (file_exists($this->name) && is_writeable($this->name) || file_exists($this->location) && is_writeable($this->location))
+		{
+			if (is_a($data, 'SimplePie'))
+			{
+				$data = $data->data;
+			}
+
+			$data = serialize($data);
+
+			if (function_exists('file_put_contents'))
+			{
+				return (bool) file_put_contents($this->name, $data);
+			}
+			else
+			{
+				$fp = fopen($this->name, 'wb');
+				if ($fp)
+				{
+					fwrite($fp, $data);
+					fclose($fp);
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	function load()
+	{
+		if (file_exists($this->name) && is_readable($this->name))
+		{
+			return unserialize(file_get_contents($this->name));
+		}
+		return false;
+	}
+
+	function mtime()
+	{
+		if (file_exists($this->name))
+		{
+			return filemtime($this->name);
+		}
+		return false;
+	}
+
+	function touch()
+	{
+		if (file_exists($this->name))
+		{
+			return touch($this->name);
+		}
+		return false;
+	}
+
+	function unlink()
+	{
+		if (file_exists($this->name))
+		{
+			return unlink($this->name);
+		}
+		return false;
+	}
+}
+
+class SimplePie_Misc
+{
+	function time_hms($seconds)
+	{
+		$time = '';
+
+		$hours = floor($seconds / 3600);
+		$remainder = $seconds % 3600;
+		if ($hours > 0)
+		{
+			$time .= $hours.':';
+		}
+
+		$minutes = floor($remainder / 60);
+		$seconds = $remainder % 60;
+		if ($minutes < 10 && $hours > 0)
+		{
+			$minutes = '0' . $minutes;
+		}
+		if ($seconds < 10)
+		{
+			$seconds = '0' . $seconds;
+		}
+
+		$time .= $minutes.':';
+		$time .= $seconds;
+
+		return $time;
+	}
+
+	function absolutize_url($relative, $base)
+	{
+		if ($relative !== '')
+		{
+			$relative = SimplePie_Misc::parse_url($relative);
+			if ($relative['scheme'] !== '')
+			{
+				$target = $relative;
+			}
+			elseif ($base !== '')
+			{
+				$base = SimplePie_Misc::parse_url($base);
+				$target = SimplePie_Misc::parse_url('');
+				if ($relative['authority'] !== '')
+				{
+					$target = $relative;
+					$target['scheme'] = $base['scheme'];
+				}
+				else
+				{
+					$target['scheme'] = $base['scheme'];
+					$target['authority'] = $base['authority'];
+					if ($relative['path'] !== '')
+					{
+						if (strpos($relative['path'], '/') === 0)
+						{
+							$target['path'] = $relative['path'];
+						}
+						elseif ($base['authority'] !== '' && $base['path'] === '')
+						{
+							$target['path'] = '/' . $relative['path'];
+						}
+						elseif (($last_segment = strrpos($base['path'], '/')) !== false)
+						{
+							$target['path'] = substr($base['path'], 0, $last_segment + 1) . $relative['path'];
+						}
+						else
+						{
+							$target['path'] = $relative['path'];
+						}
+						$target['query'] = $relative['query'];
+					}
+					else
+					{
+						$target['path'] = $base['path'];
+						if ($relative['query'] !== '')
+						{
+							$target['query'] = $relative['query'];
+						}
+						elseif ($base['query'] !== '')
+						{
+							$target['query'] = $base['query'];
+						}
+					}
+				}
+				$target['fragment'] = $relative['fragment'];
+			}
+			else
+			{
+				// No base URL, just return the relative URL
+				$target = $relative;
+			}
+			$return = SimplePie_Misc::compress_parse_url($target['scheme'], $target['authority'], $target['path'], $target['query'], $target['fragment']);
+		}
+		else
+		{
+			$return = $base;
+		}
+		$return = SimplePie_Misc::normalize_url($return);
+		return $return;
+	}
+
+	function remove_dot_segments($input)
+	{
+		$output = '';
+		while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input == '.' || $input == '..')
+		{
+			// A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise,
+			if (strpos($input, '../') === 0)
+			{
+				$input = substr($input, 3);
+			}
+			elseif (strpos($input, './') === 0)
+			{
+				$input = substr($input, 2);
+			}
+			// B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise,
+			elseif (strpos($input, '/./') === 0)
+			{
+				$input = substr_replace($input, '/', 0, 3);
+			}
+			elseif ($input == '/.')
+			{
+				$input = '/';
+			}
+			// C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise,
+			elseif (strpos($input, '/../') === 0)
+			{
+				$input = substr_replace($input, '/', 0, 4);
+				$output = substr_replace($output, '', strrpos($output, '/'));
+			}
+			elseif ($input == '/..')
+			{
+				$input = '/';
+				$output = substr_replace($output, '', strrpos($output, '/'));
+			}
+			// D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise,
+			elseif ($input == '.' || $input == '..')
+			{
+				$input = '';
+			}
+			// E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer
+			elseif (($pos = strpos($input, '/', 1)) !== false)
+			{
+				$output .= substr($input, 0, $pos);
+				$input = substr_replace($input, '', 0, $pos);
+			}
+			else
+			{
+				$output .= $input;
+				$input = '';
+			}
+		}
+		return $output . $input;
+	}
+
+	function get_element($realname, $string)
+	{
+		$return = array();
+		$name = preg_quote($realname, '/');
+		if (preg_match_all("/<($name)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$name>|(\/)?>)/siU", $string, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE))
+		{
+			for ($i = 0, $total_matches = count($matches); $i < $total_matches; $i++)
+			{
+				$return[$i]['tag'] = $realname;
+				$return[$i]['full'] = $matches[$i][0][0];
+				$return[$i]['offset'] = $matches[$i][0][1];
+				if (strlen($matches[$i][3][0]) <= 2)
+				{
+					$return[$i]['self_closing'] = true;
+				}
+				else
+				{
+					$return[$i]['self_closing'] = false;
+					$return[$i]['content'] = $matches[$i][4][0];
+				}
+				$return[$i]['attribs'] = array();
+				if (isset($matches[$i][2][0]) && preg_match_all('/[\x09\x0A\x0B\x0C\x0D\x20]+([^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3D\x3E]*)(?:[\x09\x0A\x0B\x0C\x0D\x20]*=[\x09\x0A\x0B\x0C\x0D\x20]*(?:"([^"]*)"|\'([^\']*)\'|([^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?/', ' ' . $matches[$i][2][0] . ' ', $attribs, PREG_SET_ORDER))
+				{
+					for ($j = 0, $total_attribs = count($attribs); $j < $total_attribs; $j++)
+					{
+						if (count($attribs[$j]) == 2)
+						{
+							$attribs[$j][2] = $attribs[$j][1];
+						}
+						$return[$i]['attribs'][strtolower($attribs[$j][1])]['data'] = SimplePie_Misc::entities_decode(end($attribs[$j]), 'UTF-8');
+					}
+				}
+			}
+		}
+		return $return;
+	}
+
+	function element_implode($element)
+	{
+		$full = "<$element[tag]";
+		foreach ($element['attribs'] as $key => $value)
+		{
+			$key = strtolower($key);
+			$full .= " $key=\"" . htmlspecialchars($value['data']) . '"';
+		}
+		if ($element['self_closing'])
+		{
+			$full .= ' />';
+		}
+		else
+		{
+			$full .= ">$element[content]</$element[tag]>";
+		}
+		return $full;
+	}
+
+	function error($message, $level, $file, $line)
+	{
+		switch ($level)
+		{
+			case E_USER_ERROR:
+				$note = 'PHP Error';
+				break;
+			case E_USER_WARNING:
+				$note = 'PHP Warning';
+				break;
+			case E_USER_NOTICE:
+				$note = 'PHP Notice';
+				break;
+			default:
+				$note = 'Unknown Error';
+				break;
+		}
+		error_log("$note: $message in $file on line $line", 0);
+		return $message;
+	}
+
+	/**
+	 * If a file has been cached, retrieve and display it.
+	 *
+	 * This is most useful for caching images (get_favicon(), etc.),
+	 * however it works for all cached files.  This WILL NOT display ANY
+	 * file/image/page/whatever, but rather only display what has already
+	 * been cached by SimplePie.
+	 *
+	 * @access public
+	 * @see SimplePie::get_favicon()
+	 * @param str $identifier_url URL that is used to identify the content.
+	 * This may or may not be the actual URL of the live content.
+	 * @param str $cache_location Location of SimplePie's cache.  Defaults
+	 * to './cache'.
+	 * @param str $cache_extension The file extension that the file was
+	 * cached with.  Defaults to 'spc'.
+	 * @param str $cache_class Name of the cache-handling class being used
+	 * in SimplePie.  Defaults to 'SimplePie_Cache', and should be left
+	 * as-is unless you've overloaded the class.
+	 * @param str $cache_name_function Obsolete. Exists for backwards
+	 * compatibility reasons only.
+	 */
+	function display_cached_file($identifier_url, $cache_location = './cache', $cache_extension = 'spc', $cache_class = 'SimplePie_Cache', $cache_name_function = 'md5')
+	{
+		$cache = call_user_func(array($cache_class, 'create'), $cache_location, $identifier_url, $cache_extension);
+
+		if ($file = $cache->load())
+		{
+			if (isset($file['headers']['content-type']))
+			{
+				header('Content-type:' . $file['headers']['content-type']);
+			}
+			else
+			{
+				header('Content-type: application/octet-stream');
+			}
+			header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 604800) . ' GMT'); // 7 days
+			echo $file['body'];
+			exit;
+		}
+
+		die('Cached file for ' . $identifier_url . ' cannot be found.');
+	}
+
+	function fix_protocol($url, $http = 1)
+	{
+		$url = SimplePie_Misc::normalize_url($url);
+		$parsed = SimplePie_Misc::parse_url($url);
+		if ($parsed['scheme'] !== '' && $parsed['scheme'] != 'http' && $parsed['scheme'] != 'https')
+		{
+			return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['authority'], $parsed['path'], $parsed['query'], $parsed['fragment']), $http);
+		}
+
+		if ($parsed['scheme'] === '' && $parsed['authority'] === '' && !file_exists($url))
+		{
+			return SimplePie_Misc::fix_protocol(SimplePie_Misc::compress_parse_url('http', $parsed['path'], '', $parsed['query'], $parsed['fragment']), $http);
+		}
+
+		if ($http == 2 && $parsed['scheme'] !== '')
+		{
+			return "feed:$url";
+		}
+		elseif ($http == 3 && strtolower($parsed['scheme']) == 'http')
+		{
+			return substr_replace($url, 'podcast', 0, 4);
+		}
+		elseif ($http == 4 && strtolower($parsed['scheme']) == 'http')
+		{
+			return substr_replace($url, 'itpc', 0, 4);
+		}
+		else
+		{
+			return $url;
+		}
+	}
+
+	function parse_url($url)
+	{
+		static $cache = array();
+		if (isset($cache[$url]))
+		{
+			return $cache[$url];
+		}
+		elseif (preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $url, $match))
+		{
+			for ($i = count($match); $i <= 9; $i++)
+			{
+				$match[$i] = '';
+			}
+			return $cache[$url] = array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]);
+		}
+		else
+		{
+			return $cache[$url] = array('scheme' => '', 'authority' => '', 'path' => '', 'query' => '', 'fragment' => '');
+		}
+	}
+
+	function compress_parse_url($scheme = '', $authority = '', $path = '', $query = '', $fragment = '')
+	{
+		$return = '';
+		if ($scheme !== '')
+		{
+			$return .= "$scheme:";
+		}
+		if ($authority !== '')
+		{
+			$return .= "//$authority";
+		}
+		if ($path !== '')
+		{
+			$return .= $path;
+		}
+		if ($query !== '')
+		{
+			$return .= "?$query";
+		}
+		if ($fragment !== '')
+		{
+			$return .= "#$fragment";
+		}
+		return $return;
+	}
+
+	function normalize_url($url)
+	{
+		$url = preg_replace_callback('/%([0-9A-Fa-f]{2})/', array('SimplePie_Misc', 'percent_encoding_normalization'), $url);
+		$url = SimplePie_Misc::parse_url($url);
+		$url['scheme'] = strtolower($url['scheme']);
+		if ($url['authority'] !== '')
+		{
+			$url['authority'] = strtolower($url['authority']);
+			$url['path'] = SimplePie_Misc::remove_dot_segments($url['path']);
+		}
+		return SimplePie_Misc::compress_parse_url($url['scheme'], $url['authority'], $url['path'], $url['query'], $url['fragment']);
+	}
+
+	function percent_encoding_normalization($match)
+	{
+		$integer = hexdec($match[1]);
+		if ($integer >= 0x41 && $integer <= 0x5A || $integer >= 0x61 && $integer <= 0x7A || $integer >= 0x30 && $integer <= 0x39 || $integer == 0x2D || $integer == 0x2E || $integer == 0x5F || $integer == 0x7E)
+		{
+			return chr($integer);
+		}
+		else
+		{
+			return strtoupper($match[0]);
+		}
+	}
+
+	/**
+	 * Remove bad UTF-8 bytes
+	 *
+	 * PCRE Pattern to locate bad bytes in a UTF-8 string comes from W3C
+	 * FAQ: Multilingual Forms (modified to include full ASCII range)
+	 *
+	 * @author Geoffrey Sneddon
+	 * @see http://www.w3.org/International/questions/qa-forms-utf-8
+	 * @param string $str String to remove bad UTF-8 bytes from
+	 * @return string UTF-8 string
+	 */
+	function utf8_bad_replace($str)
+	{
+		if (function_exists('iconv') && ($return = @iconv('UTF-8', 'UTF-8//IGNORE', $str)))
+		{
+			return $return;
+		}
+		elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($str, 'UTF-8', 'UTF-8')))
+		{
+			return $return;
+		}
+		elseif (preg_match_all('/(?:[\x00-\x7F]|[\xC2-\xDF][\x80-\xBF]|\xE0[\xA0-\xBF][\x80-\xBF]|[\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}|\xED[\x80-\x9F][\x80-\xBF]|\xF0[\x90-\xBF][\x80-\xBF]{2}|[\xF1-\xF3][\x80-\xBF]{3}|\xF4[\x80-\x8F][\x80-\xBF]{2})+/', $str, $matches))
+		{
+			return implode("\xEF\xBF\xBD", $matches[0]);
+		}
+		elseif ($str !== '')
+		{
+			return "\xEF\xBF\xBD";
+		}
+		else
+		{
+			return '';
+		}
+	}
+	
+	/**
+	 * Converts a Windows-1252 encoded string to a UTF-8 encoded string
+	 *
+	 * @static
+	 * @access public
+	 * @param string $string Windows-1252 encoded string
+	 * @return string UTF-8 encoded string
+	 */
+	function windows_1252_to_utf8($string)
+	{
+		static $convert_table = array("\x80" => "\xE2\x82\xAC", "\x81" => "\xEF\xBF\xBD", "\x82" => "\xE2\x80\x9A", "\x83" => "\xC6\x92", "\x84" => "\xE2\x80\x9E", "\x85" => "\xE2\x80\xA6", "\x86" => "\xE2\x80\xA0", "\x87" => "\xE2\x80\xA1", "\x88" => "\xCB\x86", "\x89" => "\xE2\x80\xB0", "\x8A" => "\xC5\xA0", "\x8B" => "\xE2\x80\xB9", "\x8C" => "\xC5\x92", "\x8D" => "\xEF\xBF\xBD", "\x8E" => "\xC5\xBD", "\x8F" => "\xEF\xBF\xBD", "\x90" => "\xEF\xBF\xBD", "\x91" => "\xE2\x80\x98", "\x92" => "\xE2\x80\x99", "\x93" => "\xE2\x80\x9C", "\x94" => "\xE2\x80\x9D", "\x95" => "\xE2\x80\xA2", "\x96" => "\xE2\x80\x93", "\x97" => "\xE2\x80\x94", "\x98" => "\xCB\x9C", "\x99" => "\xE2\x84\xA2", "\x9A" => "\xC5\xA1", "\x9B" => "\xE2\x80\xBA", "\x9C" => "\xC5\x93", "\x9D" => "\xEF\xBF\xBD", "\x9E" => "\xC5\xBE", "\x9F" => "\xC5\xB8", "\xA0" => "\xC2\xA0", "\xA1" => "\xC2\xA1", "\xA2" => "\xC2\xA2", "\xA3" => "\xC2\xA3", "\xA4" => "\xC2\xA4", "\xA5" => "\xC2\xA5", "\xA6" => "\xC2\xA6", "\xA7" => "\xC2\xA7", "\xA8" => "\xC2\xA8", "\xA9" => "\xC2\xA9", "\xAA" => "\xC2\xAA", "\xAB" => "\xC2\xAB", "\xAC" => "\xC2\xAC", "\xAD" => "\xC2\xAD", "\xAE" => "\xC2\xAE", "\xAF" => "\xC2\xAF", "\xB0" => "\xC2\xB0", "\xB1" => "\xC2\xB1", "\xB2" => "\xC2\xB2", "\xB3" => "\xC2\xB3", "\xB4" => "\xC2\xB4", "\xB5" => "\xC2\xB5", "\xB6" => "\xC2\xB6", "\xB7" => "\xC2\xB7", "\xB8" => "\xC2\xB8", "\xB9" => "\xC2\xB9", "\xBA" => "\xC2\xBA", "\xBB" => "\xC2\xBB", "\xBC" => "\xC2\xBC", "\xBD" => "\xC2\xBD", "\xBE" => "\xC2\xBE", "\xBF" => "\xC2\xBF", "\xC0" => "\xC3\x80", "\xC1" => "\xC3\x81", "\xC2" => "\xC3\x82", "\xC3" => "\xC3\x83", "\xC4" => "\xC3\x84", "\xC5" => "\xC3\x85", "\xC6" => "\xC3\x86", "\xC7" => "\xC3\x87", "\xC8" => "\xC3\x88", "\xC9" => "\xC3\x89", "\xCA" => "\xC3\x8A", "\xCB" => "\xC3\x8B", "\xCC" => "\xC3\x8C", "\xCD" => "\xC3\x8D", "\xCE" => "\xC3\x8E", "\xCF" => "\xC3\x8F", "\xD0" => "\xC3\x90", "\xD1" => "\xC3\x91", "\xD2" => "\xC3\x92", "\xD3" => "\xC3\x93", "\xD4" => "\xC3\x94", "\xD5" => "\xC3\x95", "\xD6" => "\xC3\x96", "\xD7" => "\xC3\x97", "\xD8" => "\xC3\x98", "\xD9" => "\xC3\x99", "\xDA" => "\xC3\x9A", "\xDB" => "\xC3\x9B", "\xDC" => "\xC3\x9C", "\xDD" => "\xC3\x9D", "\xDE" => "\xC3\x9E", "\xDF" => "\xC3\x9F", "\xE0" => "\xC3\xA0", "\xE1" => "\xC3\xA1", "\xE2" => "\xC3\xA2", "\xE3" => "\xC3\xA3", "\xE4" => "\xC3\xA4", "\xE5" => "\xC3\xA5", "\xE6" => "\xC3\xA6", "\xE7" => "\xC3\xA7", "\xE8" => "\xC3\xA8", "\xE9" => "\xC3\xA9", "\xEA" => "\xC3\xAA", "\xEB" => "\xC3\xAB", "\xEC" => "\xC3\xAC", "\xED" => "\xC3\xAD", "\xEE" => "\xC3\xAE", "\xEF" => "\xC3\xAF", "\xF0" => "\xC3\xB0", "\xF1" => "\xC3\xB1", "\xF2" => "\xC3\xB2", "\xF3" => "\xC3\xB3", "\xF4" => "\xC3\xB4", "\xF5" => "\xC3\xB5", "\xF6" => "\xC3\xB6", "\xF7" => "\xC3\xB7", "\xF8" => "\xC3\xB8", "\xF9" => "\xC3\xB9", "\xFA" => "\xC3\xBA", "\xFB" => "\xC3\xBB", "\xFC" => "\xC3\xBC", "\xFD" => "\xC3\xBD", "\xFE" => "\xC3\xBE", "\xFF" => "\xC3\xBF");
+		
+		return strtr($string, $convert_table);
+	}
+
+	function change_encoding($data, $input, $output)
+	{
+		$input = SimplePie_Misc::encoding($input);
+		$output = SimplePie_Misc::encoding($output);
+		
+		// We fail to fail on non US-ASCII bytes
+		if ($input === 'US-ASCII')
+		{
+			static $non_ascii_octects = '';
+			if (!$non_ascii_octects)
+			{
+				for ($i = 0x80; $i <= 0xFF; $i++)
+				{
+					$non_ascii_octects .= chr($i);
+				}
+			}
+			$data = substr($data, 0, strcspn($data, $non_ascii_octects));
+		}
+
+		if (function_exists('iconv') && ($return = @iconv($input, $output, $data)))
+		{
+			return $return;
+		}
+		elseif (function_exists('mb_convert_encoding') && ($return = @mb_convert_encoding($data, $output, $input)))
+		{
+			return $return;
+		}
+		elseif ($input == 'windows-1252' && $output == 'UTF-8')
+		{
+			return SimplePie_Misc::windows_1252_to_utf8($data);
+		}
+		elseif ($input == 'UTF-8' && $output == 'windows-1252')
+		{
+			return utf8_decode($data);
+		}
+		return $data;
+	}
+
+	function encoding($encoding)
+	{
+		// Character sets are case-insensitive (though we'll return them in the form given in their registration)
+		switch (strtoupper($encoding))
+		{
+			case 'ANSI_X3.110-1983':
+			case 'CSA_T500-1983':
+			case 'CSISO99NAPLPS':
+			case 'ISO-IR-99':
+			case 'NAPLPS':
+				return 'ANSI_X3.110-1983';
+	
+			case 'ARABIC7':
+			case 'ASMO_449':
+			case 'CSISO89ASMO449':
+			case 'ISO-IR-89':
+			case 'ISO_9036':
+				return 'ASMO_449';
+	
+			case 'ADOBE-STANDARD-ENCODING':
+			case 'CSADOBESTANDARDENCODING':
+				return 'Adobe-Standard-Encoding';
+	
+			case 'ADOBE-SYMBOL-ENCODING':
+			case 'CSHPPSMATH':
+				return 'Adobe-Symbol-Encoding';
+	
+			case 'AMI-1251':
+			case 'AMI1251':
+			case 'AMIGA-1251':
+			case 'AMIGA1251':
+				return 'Amiga-1251';
+	
+			case 'BOCU-1':
+			case 'CSBOCU-1':
+				return 'BOCU-1';
+	
+			case 'BRF':
+			case 'CSBRF':
+				return 'BRF';
+	
+			case 'BS_4730':
+			case 'CSISO4UNITEDKINGDOM':
+			case 'GB':
+			case 'ISO-IR-4':
+			case 'ISO646-GB':
+			case 'UK':
+				return 'BS_4730';
+	
+			case 'BS_VIEWDATA':
+			case 'CSISO47BSVIEWDATA':
+			case 'ISO-IR-47':
+				return 'BS_viewdata';
+	
+			case 'BIG5':
+			case 'CSBIG5':
+				return 'Big5';
+	
+			case 'BIG5-HKSCS':
+				return 'Big5-HKSCS';
+	
+			case 'CESU-8':
+			case 'CSCESU-8':
+				return 'CESU-8';
+	
+			case 'CA':
+			case 'CSA7-1':
+			case 'CSA_Z243.4-1985-1':
+			case 'CSISO121CANADIAN1':
+			case 'ISO-IR-121':
+			case 'ISO646-CA':
+				return 'CSA_Z243.4-1985-1';
+	
+			case 'CSA7-2':
+			case 'CSA_Z243.4-1985-2':
+			case 'CSISO122CANADIAN2':
+			case 'ISO-IR-122':
+			case 'ISO646-CA2':
+				return 'CSA_Z243.4-1985-2';
+	
+			case 'CSA_Z243.4-1985-GR':
+			case 'CSISO123CSAZ24341985GR':
+			case 'ISO-IR-123':
+				return 'CSA_Z243.4-1985-gr';
+	
+			case 'CSISO139CSN369103':
+			case 'CSN_369103':
+			case 'ISO-IR-139':
+				return 'CSN_369103';
+	
+			case 'CSDECMCS':
+			case 'DEC':
+			case 'DEC-MCS':
+				return 'DEC-MCS';
+	
+			case 'CSISO21GERMAN':
+			case 'DE':
+			case 'DIN_66003':
+			case 'ISO-IR-21':
+			case 'ISO646-DE':
+				return 'DIN_66003';
+	
+			case 'CSISO646DANISH':
+			case 'DK':
+			case 'DS2089':
+			case 'DS_2089':
+			case 'ISO646-DK':
+				return 'DS_2089';
+	
+			case 'CSIBMEBCDICATDE':
+			case 'EBCDIC-AT-DE':
+				return 'EBCDIC-AT-DE';
+	
+			case 'CSEBCDICATDEA':
+			case 'EBCDIC-AT-DE-A':
+				return 'EBCDIC-AT-DE-A';
+	
+			case 'CSEBCDICCAFR':
+			case 'EBCDIC-CA-FR':
+				return 'EBCDIC-CA-FR';
+	
+			case 'CSEBCDICDKNO':
+			case 'EBCDIC-DK-NO':
+				return 'EBCDIC-DK-NO';
+	
+			case 'CSEBCDICDKNOA':
+			case 'EBCDIC-DK-NO-A':
+				return 'EBCDIC-DK-NO-A';
+	
+			case 'CSEBCDICES':
+			case 'EBCDIC-ES':
+				return 'EBCDIC-ES';
+	
+			case 'CSEBCDICESA':
+			case 'EBCDIC-ES-A':
+				return 'EBCDIC-ES-A';
+	
+			case 'CSEBCDICESS':
+			case 'EBCDIC-ES-S':
+				return 'EBCDIC-ES-S';
+	
+			case 'CSEBCDICFISE':
+			case 'EBCDIC-FI-SE':
+				return 'EBCDIC-FI-SE';
+	
+			case 'CSEBCDICFISEA':
+			case 'EBCDIC-FI-SE-A':
+				return 'EBCDIC-FI-SE-A';
+	
+			case 'CSEBCDICFR':
+			case 'EBCDIC-FR':
+				return 'EBCDIC-FR';
+	
+			case 'CSEBCDICIT':
+			case 'EBCDIC-IT':
+				return 'EBCDIC-IT';
+	
+			case 'CSEBCDICPT':
+			case 'EBCDIC-PT':
+				return 'EBCDIC-PT';
+	
+			case 'CSEBCDICUK':
+			case 'EBCDIC-UK':
+				return 'EBCDIC-UK';
+	
+			case 'CSEBCDICUS':
+			case 'EBCDIC-US':
+				return 'EBCDIC-US';
+	
+			case 'CSISO111ECMACYRILLIC':
+			case 'ECMA-CYRILLIC':
+			case 'ISO-IR-111':
+			case 'KOI8-E':
+				return 'ECMA-cyrillic';
+	
+			case 'CSISO17SPANISH':
+			case 'ES':
+			case 'ISO-IR-17':
+			case 'ISO646-ES':
+				return 'ES';
+	
+			case 'CSISO85SPANISH2':
+			case 'ES2':
+			case 'ISO-IR-85':
+			case 'ISO646-ES2':
+				return 'ES2';
+	
+			case 'CSEUCPKDFMTJAPANESE':
+			case 'EUC-JP':
+			case 'EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE':
+				return 'EUC-JP';
+	
+			case 'CSEUCKR':
+			case 'EUC-KR':
+				return 'EUC-KR';
+	
+			case 'CSEUCFIXWIDJAPANESE':
+			case 'EXTENDED_UNIX_CODE_FIXED_WIDTH_FOR_JAPANESE':
+				return 'Extended_UNIX_Code_Fixed_Width_for_Japanese';
+	
+			case 'GB18030':
+				return 'GB18030';
+	
+			case 'CSGB2312':
+			case 'GB2312':
+				return 'GB2312';
+	
+			case 'CP936':
+			case 'GBK':
+			case 'MS936':
+			case 'WINDOWS-936':
+				return 'GBK';
+	
+			case 'CN':
+			case 'CSISO57GB1988':
+			case 'GB_1988-80':
+			case 'ISO-IR-57':
+			case 'ISO646-CN':
+				return 'GB_1988-80';
+	
+			case 'CHINESE':
+			case 'CSISO58GB231280':
+			case 'GB_2312-80':
+			case 'ISO-IR-58':
+				return 'GB_2312-80';
+	
+			case 'CSISO153GOST1976874':
+			case 'GOST_19768-74':
+			case 'ISO-IR-153':
+			case 'ST_SEV_358-88':
+				return 'GOST_19768-74';
+	
+			case 'CSHPDESKTOP':
+			case 'HP-DESKTOP':
+				return 'HP-DeskTop';
+	
+			case 'CSHPLEGAL':
+			case 'HP-LEGAL':
+				return 'HP-Legal';
+	
+			case 'CSHPMATH8':
+			case 'HP-MATH8':
+				return 'HP-Math8';
+	
+			case 'CSHPPIFONT':
+			case 'HP-PI-FONT':
+				return 'HP-Pi-font';
+	
+			case 'HZ-GB-2312':
+				return 'HZ-GB-2312';
+	
+			case 'CSIBMSYMBOLS':
+			case 'IBM-SYMBOLS':
+				return 'IBM-Symbols';
+	
+			case 'CSIBMTHAI':
+			case 'IBM-THAI':
+				return 'IBM-Thai';
+	
+			case 'CCSID00858':
+			case 'CP00858':
+			case 'IBM00858':
+			case 'PC-MULTILINGUAL-850+EURO':
+				return 'IBM00858';
+	
+			case 'CCSID00924':
+			case 'CP00924':
+			case 'EBCDIC-LATIN9--EURO':
+			case 'IBM00924':
+				return 'IBM00924';
+	
+			case 'CCSID01140':
+			case 'CP01140':
+			case 'EBCDIC-US-37+EURO':
+			case 'IBM01140':
+				return 'IBM01140';
+	
+			case 'CCSID01141':
+			case 'CP01141':
+			case 'EBCDIC-DE-273+EURO':
+			case 'IBM01141':
+				return 'IBM01141';
+	
+			case 'CCSID01142':
+			case 'CP01142':
+			case 'EBCDIC-DK-277+EURO':
+			case 'EBCDIC-NO-277+EURO':
+			case 'IBM01142':
+				return 'IBM01142';
+	
+			case 'CCSID01143':
+			case 'CP01143':
+			case 'EBCDIC-FI-278+EURO':
+			case 'EBCDIC-SE-278+EURO':
+			case 'IBM01143':
+				return 'IBM01143';
+	
+			case 'CCSID01144':
+			case 'CP01144':
+			case 'EBCDIC-IT-280+EURO':
+			case 'IBM01144':
+				return 'IBM01144';
+	
+			case 'CCSID01145':
+			case 'CP01145':
+			case 'EBCDIC-ES-284+EURO':
+			case 'IBM01145':
+				return 'IBM01145';
+	
+			case 'CCSID01146':
+			case 'CP01146':
+			case 'EBCDIC-GB-285+EURO':
+			case 'IBM01146':
+				return 'IBM01146';
+	
+			case 'CCSID01147':
+			case 'CP01147':
+			case 'EBCDIC-FR-297+EURO':
+			case 'IBM01147':
+				return 'IBM01147';
+	
+			case 'CCSID01148':
+			case 'CP01148':
+			case 'EBCDIC-INTERNATIONAL-500+EURO':
+			case 'IBM01148':
+				return 'IBM01148';
+	
+			case 'CCSID01149':
+			case 'CP01149':
+			case 'EBCDIC-IS-871+EURO':
+			case 'IBM01149':
+				return 'IBM01149';
+	
+			case 'CP037':
+			case 'CSIBM037':
+			case 'EBCDIC-CP-CA':
+			case 'EBCDIC-CP-NL':
+			case 'EBCDIC-CP-US':
+			case 'EBCDIC-CP-WT':
+			case 'IBM037':
+				return 'IBM037';
+	
+			case 'CP038':
+			case 'CSIBM038':
+			case 'EBCDIC-INT':
+			case 'IBM038':
+				return 'IBM038';
+	
+			case 'CP1026':
+			case 'CSIBM1026':
+			case 'IBM1026':
+				return 'IBM1026';
+	
+			case 'IBM-1047':
+			case 'IBM1047':
+				return 'IBM1047';
+	
+			case 'CP273':
+			case 'CSIBM273':
+			case 'IBM273':
+				return 'IBM273';
+	
+			case 'CP274':
+			case 'CSIBM274':
+			case 'EBCDIC-BE':
+			case 'IBM274':
+				return 'IBM274';
+	
+			case 'CP275':
+			case 'CSIBM275':
+			case 'EBCDIC-BR':
+			case 'IBM275':
+				return 'IBM275';
+	
+			case 'CSIBM277':
+			case 'EBCDIC-CP-DK':
+			case 'EBCDIC-CP-NO':
+			case 'IBM277':
+				return 'IBM277';
+	
+			case 'CP278':
+			case 'CSIBM278':
+			case 'EBCDIC-CP-FI':
+			case 'EBCDIC-CP-SE':
+			case 'IBM278':
+				return 'IBM278';
+	
+			case 'CP280':
+			case 'CSIBM280':
+			case 'EBCDIC-CP-IT':
+			case 'IBM280':
+				return 'IBM280';
+	
+			case 'CP281':
+			case 'CSIBM281':
+			case 'EBCDIC-JP-E':
+			case 'IBM281':
+				return 'IBM281';
+	
+			case 'CP284':
+			case 'CSIBM284':
+			case 'EBCDIC-CP-ES':
+			case 'IBM284':
+				return 'IBM284';
+	
+			case 'CP285':
+			case 'CSIBM285':
+			case 'EBCDIC-CP-GB':
+			case 'IBM285':
+				return 'IBM285';
+	
+			case 'CP290':
+			case 'CSIBM290':
+			case 'EBCDIC-JP-KANA':
+			case 'IBM290':
+				return 'IBM290';
+	
+			case 'CP297':
+			case 'CSIBM297':
+			case 'EBCDIC-CP-FR':
+			case 'IBM297':
+				return 'IBM297';
+	
+			case 'CP420':
+			case 'CSIBM420':
+			case 'EBCDIC-CP-AR1':
+			case 'IBM420':
+				return 'IBM420';
+	
+			case 'CP423':
+			case 'CSIBM423':
+			case 'EBCDIC-CP-GR':
+			case 'IBM423':
+				return 'IBM423';
+	
+			case 'CP424':
+			case 'CSIBM424':
+			case 'EBCDIC-CP-HE':
+			case 'IBM424':
+				return 'IBM424';
+	
+			case '437':
+			case 'CP437':
+			case 'CSPC8CODEPAGE437':
+			case 'IBM437':
+				return 'IBM437';
+	
+			case 'CP500':
+			case 'CSIBM500':
+			case 'EBCDIC-CP-BE':
+			case 'EBCDIC-CP-CH':
+			case 'IBM500':
+				return 'IBM500';
+	
+			case 'CP775':
+			case 'CSPC775BALTIC':
+			case 'IBM775':
+				return 'IBM775';
+	
+			case '850':
+			case 'CP850':
+			case 'CSPC850MULTILINGUAL':
+			case 'IBM850':
+				return 'IBM850';
+	
+			case '851':
+			case 'CP851':
+			case 'CSIBM851':
+			case 'IBM851':
+				return 'IBM851';
+	
+			case '852':
+			case 'CP852':
+			case 'CSPCP852':
+			case 'IBM852':
+				return 'IBM852';
+	
+			case '855':
+			case 'CP855':
+			case 'CSIBM855':
+			case 'IBM855':
+				return 'IBM855';
+	
+			case '857':
+			case 'CP857':
+			case 'CSIBM857':
+			case 'IBM857':
+				return 'IBM857';
+	
+			case '860':
+			case 'CP860':
+			case 'CSIBM860':
+			case 'IBM860':
+				return 'IBM860';
+	
+			case '861':
+			case 'CP-IS':
+			case 'CP861':
+			case 'CSIBM861':
+			case 'IBM861':
+				return 'IBM861';
+	
+			case '862':
+			case 'CP862':
+			case 'CSPC862LATINHEBREW':
+			case 'IBM862':
+				return 'IBM862';
+	
+			case '863':
+			case 'CP863':
+			case 'CSIBM863':
+			case 'IBM863':
+				return 'IBM863';
+	
+			case 'CP864':
+			case 'CSIBM864':
+			case 'IBM864':
+				return 'IBM864';
+	
+			case '865':
+			case 'CP865':
+			case 'CSIBM865':
+			case 'IBM865':
+				return 'IBM865';
+	
+			case '866':
+			case 'CP866':
+			case 'CSIBM866':
+			case 'IBM866':
+				return 'IBM866';
+	
+			case 'CP-AR':
+			case 'CP868':
+			case 'CSIBM868':
+			case 'IBM868':
+				return 'IBM868';
+	
+			case '869':
+			case 'CP-GR':
+			case 'CP869':
+			case 'CSIBM869':
+			case 'IBM869':
+				return 'IBM869';
+	
+			case 'CP870':
+			case 'CSIBM870':
+			case 'EBCDIC-CP-ROECE':
+			case 'EBCDIC-CP-YU':
+			case 'IBM870':
+				return 'IBM870';
+	
+			case 'CP871':
+			case 'CSIBM871':
+			case 'EBCDIC-CP-IS':
+			case 'IBM871':
+				return 'IBM871';
+	
+			case 'CP880':
+			case 'CSIBM880':
+			case 'EBCDIC-CYRILLIC':
+			case 'IBM880':
+				return 'IBM880';
+	
+			case 'CP891':
+			case 'CSIBM891':
+			case 'IBM891':
+				return 'IBM891';
+	
+			case 'CP903':
+			case 'CSIBM903':
+			case 'IBM903':
+				return 'IBM903';
+	
+			case '904':
+			case 'CP904':
+			case 'CSIBBM904':
+			case 'IBM904':
+				return 'IBM904';
+	
+			case 'CP905':
+			case 'CSIBM905':
+			case 'EBCDIC-CP-TR':
+			case 'IBM905':
+				return 'IBM905';
+	
+			case 'CP918':
+			case 'CSIBM918':
+			case 'EBCDIC-CP-AR2':
+			case 'IBM918':
+				return 'IBM918';
+	
+			case 'CSISO143IECP271':
+			case 'IEC_P27-1':
+			case 'ISO-IR-143':
+				return 'IEC_P27-1';
+	
+			case 'CSISO49INIS':
+			case 'INIS':
+			case 'ISO-IR-49':
+				return 'INIS';
+	
+			case 'CSISO50INIS8':
+			case 'INIS-8':
+			case 'ISO-IR-50':
+				return 'INIS-8';
+	
+			case 'CSISO51INISCYRILLIC':
+			case 'INIS-CYRILLIC':
+			case 'ISO-IR-51':
+				return 'INIS-cyrillic';
+	
+			case 'CSINVARIANT':
+			case 'INVARIANT':
+				return 'INVARIANT';
+	
+			case 'ISO-10646-J-1':
+				return 'ISO-10646-J-1';
+	
+			case 'CSUNICODE':
+			case 'ISO-10646-UCS-2':
+				return 'ISO-10646-UCS-2';
+	
+			case 'CSUCS4':
+			case 'ISO-10646-UCS-4':
+				return 'ISO-10646-UCS-4';
+	
+			case 'CSUNICODEASCII':
+			case 'ISO-10646-UCS-BASIC':
+				return 'ISO-10646-UCS-Basic';
+	
+			case 'CSISO10646UTF1':
+			case 'ISO-10646-UTF-1':
+				return 'ISO-10646-UTF-1';
+	
+			case 'CSUNICODELATIN1':
+			case 'ISO-10646':
+			case 'ISO-10646-UNICODE-LATIN1':
+				return 'ISO-10646-Unicode-Latin1';
+	
+			case 'CSISO115481':
+			case 'ISO-11548-1':
+			case 'ISO_11548-1':
+			case 'ISO_TR_11548-1':
+				return 'ISO-11548-1';
+	
+			case 'ISO-2022-CN':
+				return 'ISO-2022-CN';
+	
+			case 'ISO-2022-CN-EXT':
+				return 'ISO-2022-CN-EXT';
+	
+			case 'CSISO2022JP':
+			case 'ISO-2022-JP':
+				return 'ISO-2022-JP';
+	
+			case 'CSISO2022JP2':
+			case 'ISO-2022-JP-2':
+				return 'ISO-2022-JP-2';
+	
+			case 'CSISO2022KR':
+			case 'ISO-2022-KR':
+				return 'ISO-2022-KR';
+	
+			case 'CSWINDOWS30LATIN1':
+			case 'ISO-8859-1-WINDOWS-3.0-LATIN-1':
+				return 'ISO-8859-1-Windows-3.0-Latin-1';
+	
+			case 'CSWINDOWS31LATIN1':
+			case 'ISO-8859-1-WINDOWS-3.1-LATIN-1':
+				return 'ISO-8859-1-Windows-3.1-Latin-1';
+	
+			case 'CSISOLATIN6':
+			case 'ISO-8859-10':
+			case 'ISO-IR-157':
+			case 'ISO_8859-10:1992':
+			case 'L6':
+			case 'LATIN6':
+				return 'ISO-8859-10';
+	
+			case 'ISO-8859-13':
+				return 'ISO-8859-13';
+	
+			case 'ISO-8859-14':
+			case 'ISO-CELTIC':
+			case 'ISO-IR-199':
+			case 'ISO_8859-14':
+			case 'ISO_8859-14:1998':
+			case 'L8':
+			case 'LATIN8':
+				return 'ISO-8859-14';
+	
+			case 'ISO-8859-15':
+			case 'ISO_8859-15':
+			case 'LATIN-9':
+				return 'ISO-8859-15';
+	
+			case 'ISO-8859-16':
+			case 'ISO-IR-226':
+			case 'ISO_8859-16':
+			case 'ISO_8859-16:2001':
+			case 'L10':
+			case 'LATIN10':
+				return 'ISO-8859-16';
+	
+			case 'CSISOLATIN2':
+			case 'ISO-8859-2':
+			case 'ISO-IR-101':
+			case 'ISO_8859-2':
+			case 'ISO_8859-2:1987':
+			case 'L2':
+			case 'LATIN2':
+				return 'ISO-8859-2';
+	
+			case 'CSWINDOWS31LATIN2':
+			case 'ISO-8859-2-WINDOWS-LATIN-2':
+				return 'ISO-8859-2-Windows-Latin-2';
+	
+			case 'CSISOLATIN3':
+			case 'ISO-8859-3':
+			case 'ISO-IR-109':
+			case 'ISO_8859-3':
+			case 'ISO_8859-3:1988':
+			case 'L3':
+			case 'LATIN3':
+				return 'ISO-8859-3';
+	
+			case 'CSISOLATIN4':
+			case 'ISO-8859-4':
+			case 'ISO-IR-110':
+			case 'ISO_8859-4':
+			case 'ISO_8859-4:1988':
+			case 'L4':
+			case 'LATIN4':
+				return 'ISO-8859-4';
+	
+			case 'CSISOLATINCYRILLIC':
+			case 'CYRILLIC':
+			case 'ISO-8859-5':
+			case 'ISO-IR-144':
+			case 'ISO_8859-5':
+			case 'ISO_8859-5:1988':
+				return 'ISO-8859-5';
+	
+			case 'ARABIC':
+			case 'ASMO-708':
+			case 'CSISOLATINARABIC':
+			case 'ECMA-114':
+			case 'ISO-8859-6':
+			case 'ISO-IR-127':
+			case 'ISO_8859-6':
+			case 'ISO_8859-6:1987':
+				return 'ISO-8859-6';
+	
+			case 'CSISO88596E':
+			case 'ISO-8859-6-E':
+			case 'ISO_8859-6-E':
+				return 'ISO-8859-6-E';
+	
+			case 'CSISO88596I':
+			case 'ISO-8859-6-I':
+			case 'ISO_8859-6-I':
+				return 'ISO-8859-6-I';
+	
+			case 'CSISOLATINGREEK':
+			case 'ECMA-118':
+			case 'ELOT_928':
+			case 'GREEK':
+			case 'GREEK8':
+			case 'ISO-8859-7':
+			case 'ISO-IR-126':
+			case 'ISO_8859-7':
+			case 'ISO_8859-7:1987':
+				return 'ISO-8859-7';
+	
+			case 'CSISOLATINHEBREW':
+			case 'HEBREW':
+			case 'ISO-8859-8':
+			case 'ISO-IR-138':
+			case 'ISO_8859-8':
+			case 'ISO_8859-8:1988':
+				return 'ISO-8859-8';
+	
+			case 'CSISO88598E':
+			case 'ISO-8859-8-E':
+			case 'ISO_8859-8-E':
+				return 'ISO-8859-8-E';
+	
+			case 'CSISO88598I':
+			case 'ISO-8859-8-I':
+			case 'ISO_8859-8-I':
+				return 'ISO-8859-8-I';
+	
+			case 'CSISOLATIN5':
+			case 'ISO-8859-9':
+			case 'ISO-IR-148':
+			case 'ISO_8859-9':
+			case 'ISO_8859-9:1989':
+			case 'L5':
+			case 'LATIN5':
+				return 'ISO-8859-9';
+	
+			case 'CSWINDOWS31LATIN5':
+			case 'ISO-8859-9-WINDOWS-LATIN-5':
+				return 'ISO-8859-9-Windows-Latin-5';
+	
+			case 'CSUNICODEIBM1261':
+			case 'ISO-UNICODE-IBM-1261':
+				return 'ISO-Unicode-IBM-1261';
+	
+			case 'CSUNICODEIBM1264':
+			case 'ISO-UNICODE-IBM-1264':
+				return 'ISO-Unicode-IBM-1264';
+	
+			case 'CSUNICODEIBM1265':
+			case 'ISO-UNICODE-IBM-1265':
+				return 'ISO-Unicode-IBM-1265';
+	
+			case 'CSUNICODEIBM1268':
+			case 'ISO-UNICODE-IBM-1268':
+				return 'ISO-Unicode-IBM-1268';
+	
+			case 'CSUNICODEIBM1276':
+			case 'ISO-UNICODE-IBM-1276':
+				return 'ISO-Unicode-IBM-1276';
+	
+			case 'CSISO10367BOX':
+			case 'ISO-IR-155':
+			case 'ISO_10367-BOX':
+				return 'ISO_10367-box';
+	
+			case 'CSISO2033':
+			case 'E13B':
+			case 'ISO-IR-98':
+			case 'ISO_2033-1983':
+				return 'ISO_2033-1983';
+	
+			case 'CSISO5427CYRILLIC':
+			case 'ISO-IR-37':
+			case 'ISO_5427':
+				return 'ISO_5427';
+	
+			case 'ISO-IR-54':
+			case 'ISO5427CYRILLIC1981':
+			case 'ISO_5427:1981':
+				return 'ISO_5427:1981';
+	
+			case 'CSISO5428GREEK':
+			case 'ISO-IR-55':
+			case 'ISO_5428:1980':
+				return 'ISO_5428:1980';
+	
+			case 'CSISO646BASIC1983':
+			case 'ISO_646.BASIC:1983':
+			case 'REF':
+				return 'ISO_646.basic:1983';
+	
+			case 'CSISO2INTLREFVERSION':
+			case 'IRV':
+			case 'ISO-IR-2':
+			case 'ISO_646.IRV:1983':
+				return 'ISO_646.irv:1983';
+	
+			case 'CSISO6937ADD':
+			case 'ISO-IR-152':
+			case 'ISO_6937-2-25':
+				return 'ISO_6937-2-25';
+	
+			case 'CSISOTEXTCOMM':
+			case 'ISO-IR-142':
+			case 'ISO_6937-2-ADD':
+				return 'ISO_6937-2-add';
+	
+			case 'CSISO8859SUPP':
+			case 'ISO-IR-154':
+			case 'ISO_8859-SUPP':
+			case 'LATIN1-2-5':
+				return 'ISO_8859-supp';
+	
+			case 'CSISO15ITALIAN':
+			case 'ISO-IR-15':
+			case 'ISO646-IT':
+			case 'IT':
+				return 'IT';
+	
+			case 'CSISO13JISC6220JP':
+			case 'ISO-IR-13':
+			case 'JIS_C6220-1969':
+			case 'JIS_C6220-1969-JP':
+			case 'KATAKANA':
+			case 'X0201-7':
+				return 'JIS_C6220-1969-jp';
+	
+			case 'CSISO14JISC6220RO':
+			case 'ISO-IR-14':
+			case 'ISO646-JP':
+			case 'JIS_C6220-1969-RO':
+			case 'JP':
+				return 'JIS_C6220-1969-ro';
+	
+			case 'CSISO42JISC62261978':
+			case 'ISO-IR-42':
+			case 'JIS_C6226-1978':
+				return 'JIS_C6226-1978';
+	
+			case 'CSISO87JISX0208':
+			case 'ISO-IR-87':
+			case 'JIS_C6226-1983':
+			case 'JIS_X0208-1983':
+			case 'X0208':
+				return 'JIS_C6226-1983';
+	
+			case 'CSISO91JISC62291984A':
+			case 'ISO-IR-91':
+			case 'JIS_C6229-1984-A':
+			case 'JP-OCR-A':
+				return 'JIS_C6229-1984-a';
+	
+			case 'CSISO92JISC62991984B':
+			case 'ISO-IR-92':
+			case 'ISO646-JP-OCR-B':
+			case 'JIS_C6229-1984-B':
+			case 'JP-OCR-B':
+				return 'JIS_C6229-1984-b';
+	
+			case 'CSISO93JIS62291984BADD':
+			case 'ISO-IR-93':
+			case 'JIS_C6229-1984-B-ADD':
+			case 'JP-OCR-B-ADD':
+				return 'JIS_C6229-1984-b-add';
+	
+			case 'CSISO94JIS62291984HAND':
+			case 'ISO-IR-94':
+			case 'JIS_C6229-1984-HAND':
+			case 'JP-OCR-HAND':
+				return 'JIS_C6229-1984-hand';
+	
+			case 'CSISO95JIS62291984HANDADD':
+			case 'ISO-IR-95':
+			case 'JIS_C6229-1984-HAND-ADD':
+			case 'JP-OCR-HAND-ADD':
+				return 'JIS_C6229-1984-hand-add';
+	
+			case 'CSISO96JISC62291984KANA':
+			case 'ISO-IR-96':
+			case 'JIS_C6229-1984-KANA':
+				return 'JIS_C6229-1984-kana';
+	
+			case 'CSJISENCODING':
+			case 'JIS_ENCODING':
+				return 'JIS_Encoding';
+	
+			case 'CSHALFWIDTHKATAKANA':
+			case 'JIS_X0201':
+			case 'X0201':
+				return 'JIS_X0201';
+	
+			case 'CSISO159JISX02121990':
+			case 'ISO-IR-159':
+			case 'JIS_X0212-1990':
+			case 'X0212':
+				return 'JIS_X0212-1990';
+	
+			case 'CSISO141JUSIB1002':
+			case 'ISO-IR-141':
+			case 'ISO646-YU':
+			case 'JS':
+			case 'JUS_I.B1.002':
+			case 'YU':
+				return 'JUS_I.B1.002';
+	
+			case 'CSISO147MACEDONIAN':
+			case 'ISO-IR-147':
+			case 'JUS_I.B1.003-MAC':
+			case 'MACEDONIAN':
+				return 'JUS_I.B1.003-mac';
+	
+			case 'CSISO146SERBIAN':
+			case 'ISO-IR-146':
+			case 'JUS_I.B1.003-SERB':
+			case 'SERBIAN':
+				return 'JUS_I.B1.003-serb';
+	
+			case 'KOI7-SWITCHED':
+				return 'KOI7-switched';
+	
+			case 'CSKOI8R':
+			case 'KOI8-R':
+				return 'KOI8-R';
+	
+			case 'KOI8-U':
+				return 'KOI8-U';
+	
+			case 'CSKSC5636':
+			case 'ISO646-KR':
+			case 'KSC5636':
+				return 'KSC5636';
+	
+			case 'CSKSC56011987':
+			case 'ISO-IR-149':
+			case 'KOREAN':
+			case 'KSC_5601':
+			case 'KS_C_5601-1987':
+			case 'KS_C_5601-1989':
+				return 'KS_C_5601-1987';
+	
+			case 'CSKZ1048':
+			case 'KZ-1048':
+			case 'RK1048':
+			case 'STRK1048-2002':
+				return 'KZ-1048';
+	
+			case 'CSISO27LATINGREEK1':
+			case 'ISO-IR-27':
+			case 'LATIN-GREEK-1':
+				return 'Latin-greek-1';
+	
+			case 'CSMNEM':
+			case 'MNEM':
+				return 'MNEM';
+	
+			case 'CSMNEMONIC':
+			case 'MNEMONIC':
+				return 'MNEMONIC';
+	
+			case 'CSISO86HUNGARIAN':
+			case 'HU':
+			case 'ISO-IR-86':
+			case 'ISO646-HU':
+			case 'MSZ_7795.3':
+				return 'MSZ_7795.3';
+	
+			case 'CSMICROSOFTPUBLISHING':
+			case 'MICROSOFT-PUBLISHING':
+				return 'Microsoft-Publishing';
+	
+			case 'CSNATSDANO':
+			case 'ISO-IR-9-1':
+			case 'NATS-DANO':
+				return 'NATS-DANO';
+	
+			case 'CSNATSDANOADD':
+			case 'ISO-IR-9-2':
+			case 'NATS-DANO-ADD':
+				return 'NATS-DANO-ADD';
+	
+			case 'CSNATSSEFI':
+			case 'ISO-IR-8-1':
+			case 'NATS-SEFI':
+				return 'NATS-SEFI';
+	
+			case 'CSNATSSEFIADD':
+			case 'ISO-IR-8-2':
+			case 'NATS-SEFI-ADD':
+				return 'NATS-SEFI-ADD';
+	
+			case 'CSISO151CUBA':
+			case 'CUBA':
+			case 'ISO-IR-151':
+			case 'ISO646-CU':
+			case 'NC_NC00-10:81':
+				return 'NC_NC00-10:81';
+	
+			case 'CSISO69FRENCH':
+			case 'FR':
+			case 'ISO-IR-69':
+			case 'ISO646-FR':
+			case 'NF_Z_62-010':
+				return 'NF_Z_62-010';
+	
+			case 'CSISO25FRENCH':
+			case 'ISO-IR-25':
+			case 'ISO646-FR1':
+			case 'NF_Z_62-010_(1973)':
+				return 'NF_Z_62-010_(1973)';
+	
+			case 'CSISO60DANISHNORWEGIAN':
+			case 'CSISO60NORWEGIAN1':
+			case 'ISO-IR-60':
+			case 'ISO646-NO':
+			case 'NO':
+			case 'NS_4551-1':
+				return 'NS_4551-1';
+	
+			case 'CSISO61NORWEGIAN2':
+			case 'ISO-IR-61':
+			case 'ISO646-NO2':
+			case 'NO2':
+			case 'NS_4551-2':
+				return 'NS_4551-2';
+	
+			case 'OSD_EBCDIC_DF03_IRV':
+				return 'OSD_EBCDIC_DF03_IRV';
+	
+			case 'OSD_EBCDIC_DF04_1':
+				return 'OSD_EBCDIC_DF04_1';
+	
+			case 'OSD_EBCDIC_DF04_15':
+				return 'OSD_EBCDIC_DF04_15';
+	
+			case 'CSPC8DANISHNORWEGIAN':
+			case 'PC8-DANISH-NORWEGIAN':
+				return 'PC8-Danish-Norwegian';
+	
+			case 'CSPC8TURKISH':
+			case 'PC8-TURKISH':
+				return 'PC8-Turkish';
+	
+			case 'CSISO16PORTUGUESE':
+			case 'ISO-IR-16':
+			case 'ISO646-PT':
+			case 'PT':
+				return 'PT';
+	
+			case 'CSISO84PORTUGUESE2':
+			case 'ISO-IR-84':
+			case 'ISO646-PT2':
+			case 'PT2':
+				return 'PT2';
+	
+			case 'CP154':
+			case 'CSPTCP154':
+			case 'CYRILLIC-ASIAN':
+			case 'PT154':
+			case 'PTCP154':
+				return 'PTCP154';
+	
+			case 'SCSU':
+				return 'SCSU';
+	
+			case 'CSISO10SWEDISH':
+			case 'FI':
+			case 'ISO-IR-10':
+			case 'ISO646-FI':
+			case 'ISO646-SE':
+			case 'SE':
+			case 'SEN_850200_B':
+				return 'SEN_850200_B';
+	
+			case 'CSISO11SWEDISHFORNAMES':
+			case 'ISO-IR-11':
+			case 'ISO646-SE2':
+			case 'SE2':
+			case 'SEN_850200_C':
+				return 'SEN_850200_C';
+	
+			case 'CSSHIFTJIS':
+			case 'MS_KANJI':
+			case 'SHIFT_JIS':
+				return 'Shift_JIS';
+	
+			case 'CSISO128T101G2':
+			case 'ISO-IR-128':
+			case 'T.101-G2':
+				return 'T.101-G2';
+	
+			case 'CSISO102T617BIT':
+			case 'ISO-IR-102':
+			case 'T.61-7BIT':
+				return 'T.61-7bit';
+	
+			case 'CSISO103T618BIT':
+			case 'ISO-IR-103':
+			case 'T.61':
+			case 'T.61-8BIT':
+				return 'T.61-8bit';
+	
+			case 'CSTSCII':
+			case 'TSCII':
+				return 'TSCII';
+	
+			case 'CSUNICODE11':
+			case 'UNICODE-1-1':
+				return 'UNICODE-1-1';
+	
+			case 'CSUNICODE11UTF7':
+			case 'UNICODE-1-1-UTF-7':
+				return 'UNICODE-1-1-UTF-7';
+	
+			case 'CSUNKNOWN8BIT':
+			case 'UNKNOWN-8BIT':
+				return 'UNKNOWN-8BIT';
+	
+			case 'ANSI':
+			case 'ANSI_X3.4-1968':
+			case 'ANSI_X3.4-1986':
+			case 'ASCII':
+			case 'CP367':
+			case 'CSASCII':
+			case 'IBM367':
+			case 'ISO-IR-6':
+			case 'ISO646-US':
+			case 'ISO_646.IRV:1991':
+			case 'US':
+			case 'US-ASCII':
+				return 'US-ASCII';
+	
+			case 'UTF-16':
+				return 'UTF-16';
+	
+			case 'UTF-16BE':
+				return 'UTF-16BE';
+	
+			case 'UTF-16LE':
+				return 'UTF-16LE';
+	
+			case 'UTF-32':
+				return 'UTF-32';
+	
+			case 'UTF-32BE':
+				return 'UTF-32BE';
+	
+			case 'UTF-32LE':
+				return 'UTF-32LE';
+	
+			case 'UTF-7':
+				return 'UTF-7';
+	
+			case 'UTF-8':
+				return 'UTF-8';
+	
+			case 'CSVIQR':
+			case 'VIQR':
+				return 'VIQR';
+	
+			case 'CSVISCII':
+			case 'VISCII':
+				return 'VISCII';
+	
+			case 'CSVENTURAINTERNATIONAL':
+			case 'VENTURA-INTERNATIONAL':
+				return 'Ventura-International';
+	
+			case 'CSVENTURAMATH':
+			case 'VENTURA-MATH':
+				return 'Ventura-Math';
+	
+			case 'CSVENTURAUS':
+			case 'VENTURA-US':
+				return 'Ventura-US';
+	
+			case 'CSWINDOWS31J':
+			case 'WINDOWS-31J':
+				return 'Windows-31J';
+	
+			case 'CSDKUS':
+			case 'DK-US':
+				return 'dk-us';
+	
+			case 'CSISO150':
+			case 'CSISO150GREEKCCITT':
+			case 'GREEK-CCITT':
+			case 'ISO-IR-150':
+				return 'greek-ccitt';
+	
+			case 'CSISO88GREEK7':
+			case 'GREEK7':
+			case 'ISO-IR-88':
+				return 'greek7';
+	
+			case 'CSISO18GREEK7OLD':
+			case 'GREEK7-OLD':
+			case 'ISO-IR-18':
+				return 'greek7-old';
+	
+			case 'CSHPROMAN8':
+			case 'HP-ROMAN8':
+			case 'R8':
+			case 'ROMAN8':
+				return 'hp-roman8';
+	
+			case 'CSISO90':
+			case 'ISO-IR-90':
+				return 'iso-ir-90';
+	
+			case 'CSISO19LATINGREEK':
+			case 'ISO-IR-19':
+			case 'LATIN-GREEK':
+				return 'latin-greek';
+	
+			case 'CSISO158LAP':
+			case 'ISO-IR-158':
+			case 'LAP':
+			case 'LATIN-LAP':
+				return 'latin-lap';
+	
+			case 'CSMACINTOSH':
+			case 'MAC':
+			case 'MACINTOSH':
+				return 'macintosh';
+	
+			case 'CSUSDK':
+			case 'US-DK':
+				return 'us-dk';
+	
+			case 'CSISO70VIDEOTEXSUPP1':
+			case 'ISO-IR-70':
+			case 'VIDEOTEX-SUPPL':
+				return 'videotex-suppl';
+	
+			case 'WINDOWS-1250':
+				return 'windows-1250';
+	
+			case 'WINDOWS-1251':
+				return 'windows-1251';
+	
+			case 'CP819':
+			case 'CSISOLATIN1':
+			case 'IBM819':
+			case 'ISO-8859-1':
+			case 'ISO-IR-100':
+			case 'ISO_8859-1':
+			case 'ISO_8859-1:1987':
+			case 'L1':
+			case 'LATIN1':
+			case 'WINDOWS-1252':
+				return 'windows-1252';
+	
+			case 'WINDOWS-1253':
+				return 'windows-1253';
+	
+			case 'WINDOWS-1254':
+				return 'windows-1254';
+	
+			case 'WINDOWS-1255':
+				return 'windows-1255';
+	
+			case 'WINDOWS-1256':
+				return 'windows-1256';
+	
+			case 'WINDOWS-1257':
+				return 'windows-1257';
+	
+			case 'WINDOWS-1258':
+				return 'windows-1258';
+	
+			default:
+				return $encoding;
+		}
+	}
+
+	function get_curl_version()
+	{
+		if (is_array($curl = curl_version()))
+		{
+			$curl = $curl['version'];
+		}
+		elseif (substr($curl, 0, 5) == 'curl/')
+		{
+			$curl = substr($curl, 5, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 5));
+		}
+		elseif (substr($curl, 0, 8) == 'libcurl/')
+		{
+			$curl = substr($curl, 8, strcspn($curl, "\x09\x0A\x0B\x0C\x0D", 8));
+		}
+		else
+		{
+			$curl = 0;
+		}
+		return $curl;
+	}
+
+	function is_subclass_of($class1, $class2)
+	{
+		if (func_num_args() != 2)
+		{
+			trigger_error('Wrong parameter count for SimplePie_Misc::is_subclass_of()', E_USER_WARNING);
+		}
+		elseif (version_compare(PHP_VERSION, '5.0.3', '>=') || is_object($class1))
+		{
+			return is_subclass_of($class1, $class2);
+		}
+		elseif (is_string($class1) && is_string($class2))
+		{
+			if (class_exists($class1))
+			{
+				if (class_exists($class2))
+				{
+					$class2 = strtolower($class2);
+					while ($class1 = strtolower(get_parent_class($class1)))
+					{
+						if ($class1 == $class2)
+						{
+							return true;
+						}
+					}
+				}
+			}
+			else
+			{
+				trigger_error('Unknown class passed as parameter', E_USER_WARNNG);
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Strip HTML comments
+	 *
+	 * @access public
+	 * @param string $data Data to strip comments from
+	 * @return string Comment stripped string
+	 */
+	function strip_comments($data)
+	{
+		$output = '';
+		while (($start = strpos($data, '<!--')) !== false)
+		{
+			$output .= substr($data, 0, $start);
+			if (($end = strpos($data, '-->', $start)) !== false)
+			{
+				$data = substr_replace($data, '', 0, $end + 3);
+			}
+			else
+			{
+				$data = '';
+			}
+		}
+		return $output . $data;
+	}
+
+	function parse_date($dt)
+	{
+		$parser = SimplePie_Parse_Date::get();
+		return $parser->parse($dt);
+	}
+
+	/**
+	 * Decode HTML entities
+	 *
+	 * @static
+	 * @access public
+	 * @param string $data Input data
+	 * @return string Output data
+	 */
+	function entities_decode($data)
+	{
+		$decoder = new SimplePie_Decode_HTML_Entities($data);
+		return $decoder->parse();
+	}
+
+	/**
+	 * Remove RFC822 comments
+	 *
+	 * @access public
+	 * @param string $data Data to strip comments from
+	 * @return string Comment stripped string
+	 */
+	function uncomment_rfc822($string)
+	{
+		$string = (string) $string;
+		$position = 0;
+		$length = strlen($string);
+		$depth = 0;
+		
+		$output = '';
+		
+		while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
+		{
+			$output .= substr($string, $position, $pos - $position);
+			$position = $pos + 1;
+			if ($string[$pos - 1] !== '\\')
+			{
+				$depth++;
+				while ($depth && $position < $length)
+				{
+					$position += strcspn($string, '()', $position);
+					if ($string[$position - 1] === '\\')
+					{
+						$position++;
+						continue;
+					}
+					elseif (isset($string[$position]))
+					{
+						switch ($string[$position])
+						{
+							case '(':
+								$depth++;
+								break;
+							
+							case ')':
+								$depth--;
+								break;
+						}
+						$position++;
+					}
+					else
+					{
+						break;
+					}
+				}
+			}
+			else
+			{
+				$output .= '(';
+			}
+		}
+		$output .= substr($string, $position);
+		
+		return $output;
+	}
+
+	function parse_mime($mime)
+	{
+		if (($pos = strpos($mime, ';')) === false)
+		{
+			return trim($mime);
+		}
+		else
+		{
+			return trim(substr($mime, 0, $pos));
+		}
+	}
+
+	function htmlspecialchars_decode($string, $quote_style)
+	{
+		if (function_exists('htmlspecialchars_decode'))
+		{
+			return htmlspecialchars_decode($string, $quote_style);
+		}
+		else
+		{
+			return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
+		}
+	}
+
+	function atom_03_construct_type($attribs)
+	{
+		if (isset($attribs['']['mode']) && strtolower(trim($attribs['']['mode']) == 'base64'))
+		{
+			$mode = SIMPLEPIE_CONSTRUCT_BASE64;
+		}
+		else
+		{
+			$mode = SIMPLEPIE_CONSTRUCT_NONE;
+		}
+		if (isset($attribs['']['type']))
+		{
+			switch (strtolower(trim($attribs['']['type'])))
+			{
+				case 'text':
+				case 'text/plain':
+					return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
+
+				case 'html':
+				case 'text/html':
+					return SIMPLEPIE_CONSTRUCT_HTML | $mode;
+
+				case 'xhtml':
+				case 'application/xhtml+xml':
+					return SIMPLEPIE_CONSTRUCT_XHTML | $mode;
+
+				default:
+					return SIMPLEPIE_CONSTRUCT_NONE | $mode;
+			}
+		}
+		else
+		{
+			return SIMPLEPIE_CONSTRUCT_TEXT | $mode;
+		}
+	}
+
+	function atom_10_construct_type($attribs)
+	{
+		if (isset($attribs['']['type']))
+		{
+			switch (strtolower(trim($attribs['']['type'])))
+			{
+				case 'text':
+					return SIMPLEPIE_CONSTRUCT_TEXT;
+
+				case 'html':
+					return SIMPLEPIE_CONSTRUCT_HTML;
+
+				case 'xhtml':
+					return SIMPLEPIE_CONSTRUCT_XHTML;
+
+				default:
+					return SIMPLEPIE_CONSTRUCT_NONE;
+			}
+		}
+		return SIMPLEPIE_CONSTRUCT_TEXT;
+	}
+
+	function atom_10_content_construct_type($attribs)
+	{
+		if (isset($attribs['']['type']))
+		{
+			$type = strtolower(trim($attribs['']['type']));
+			switch ($type)
+			{
+				case 'text':
+					return SIMPLEPIE_CONSTRUCT_TEXT;
+
+				case 'html':
+					return SIMPLEPIE_CONSTRUCT_HTML;
+
+				case 'xhtml':
+					return SIMPLEPIE_CONSTRUCT_XHTML;
+			}
+			if (in_array(substr($type, -4), array('+xml', '/xml')) || substr($type, 0, 5) == 'text/')
+			{
+				return SIMPLEPIE_CONSTRUCT_NONE;
+			}
+			else
+			{
+				return SIMPLEPIE_CONSTRUCT_BASE64;
+			}
+		}
+		else
+		{
+			return SIMPLEPIE_CONSTRUCT_TEXT;
+		}
+	}
+
+	function is_isegment_nz_nc($string)
+	{
+		return (bool) preg_match('/^([A-Za-z0-9\-._~\x{A0}-\x{D7FF}\x{F900}-\x{FDCF}\x{FDF0}-\x{FFEF}\x{10000}-\x{1FFFD}\x{20000}-\x{2FFFD}\x{30000}-\x{3FFFD}\x{40000}-\x{4FFFD}\x{50000}-\x{5FFFD}\x{60000}-\x{6FFFD}\x{70000}-\x{7FFFD}\x{80000}-\x{8FFFD}\x{90000}-\x{9FFFD}\x{A0000}-\x{AFFFD}\x{B0000}-\x{BFFFD}\x{C0000}-\x{CFFFD}\x{D0000}-\x{DFFFD}\x{E1000}-\x{EFFFD}!$&\'()*+,;=@]|(%[0-9ABCDEF]{2}))+$/u', $string);
+	}
+
+	function space_seperated_tokens($string)
+	{
+		$space_characters = "\x20\x09\x0A\x0B\x0C\x0D";
+		$string_length = strlen($string);
+
+		$position = strspn($string, $space_characters);
+		$tokens = array();
+
+		while ($position < $string_length)
+		{
+			$len = strcspn($string, $space_characters, $position);
+			$tokens[] = substr($string, $position, $len);
+			$position += $len;
+			$position += strspn($string, $space_characters, $position);
+		}
+
+		return $tokens;
+	}
+
+	function array_unique($array)
+	{
+		if (version_compare(PHP_VERSION, '5.2', '>='))
+		{
+			return array_unique($array);
+		}
+		else
+		{
+			$array = (array) $array;
+			$new_array = array();
+			$new_array_strings = array();
+			foreach ($array as $key => $value)
+			{
+				if (is_object($value))
+				{
+					if (method_exists($value, '__toString'))
+					{
+						$cmp = $value->__toString();
+					}
+					else
+					{
+						trigger_error('Object of class ' . get_class($value) . ' could not be converted to string', E_USER_ERROR);
+					}
+				}
+				elseif (is_array($value))
+				{
+					$cmp = (string) reset($value);
+				}
+				else
+				{
+					$cmp = (string) $value;
+				}
+				if (!in_array($cmp, $new_array_strings))
+				{
+					$new_array[$key] = $value;
+					$new_array_strings[] = $cmp;
+				}
+			}
+			return $new_array;
+		}
+	}
+
+	/**
+	 * Converts a unicode codepoint to a UTF-8 character
+	 *
+	 * @static
+	 * @access public
+	 * @param int $codepoint Unicode codepoint
+	 * @return string UTF-8 character
+	 */
+	function codepoint_to_utf8($codepoint)
+	{
+		static $cache = array();
+		$codepoint = (int) $codepoint;
+		if (isset($cache[$codepoint]))
+		{
+			return $cache[$codepoint];
+		}
+		elseif ($codepoint < 0)
+		{
+			return $cache[$codepoint] = false;
+		}
+		else if ($codepoint <= 0x7f)
+		{
+			return $cache[$codepoint] = chr($codepoint);
+		}
+		else if ($codepoint <= 0x7ff)
+		{
+			return $cache[$codepoint] = chr(0xc0 | ($codepoint >> 6)) . chr(0x80 | ($codepoint & 0x3f));
+		}
+		else if ($codepoint <= 0xffff)
+		{
+			return $cache[$codepoint] = chr(0xe0 | ($codepoint >> 12)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
+		}
+		else if ($codepoint <= 0x10ffff)
+		{
+			return $cache[$codepoint] = chr(0xf0 | ($codepoint >> 18)) . chr(0x80 | (($codepoint >> 12) & 0x3f)) . chr(0x80 | (($codepoint >> 6) & 0x3f)) . chr(0x80 | ($codepoint & 0x3f));
+		}
+		else
+		{
+			// U+FFFD REPLACEMENT CHARACTER
+			return $cache[$codepoint] = "\xEF\xBF\xBD";
+		}
+	}
+
+	/**
+	 * Re-implementation of PHP 5's stripos()
+	 *
+	 * Returns the numeric position of the first occurrence of needle in the
+	 * haystack string.
+	 *
+	 * @static
+	 * @access string
+	 * @param object $haystack
+	 * @param string $needle Note that the needle may be a string of one or more
+	 *     characters. If needle is not a string, it is converted to an integer
+	 *     and applied as the ordinal value of a character.
+	 * @param int $offset The optional offset parameter allows you to specify which
+	 *     character in haystack to start searching. The position returned is still
+	 *     relative to the beginning of haystack.
+	 * @return bool If needle is not found, stripos() will return boolean false.
+	 */
+	function stripos($haystack, $needle, $offset = 0)
+	{
+		if (function_exists('stripos'))
+		{
+			return stripos($haystack, $needle, $offset);
+		}
+		else
+		{
+			if (is_string($needle))
+			{
+				$needle = strtolower($needle);
+			}
+			elseif (is_int($needle) || is_bool($needle) || is_double($needle))
+			{
+				$needle = strtolower(chr($needle));
+			}
+			else
+			{
+				trigger_error('needle is not a string or an integer', E_USER_WARNING);
+				return false;
+			}
+	
+			return strpos(strtolower($haystack), $needle, $offset);
+		}
+	}
+
+	/**
+	 * Similar to parse_str()
+	 *
+	 * Returns an associative array of name/value pairs, where the value is an
+	 * array of values that have used the same name
+	 *
+	 * @static
+	 * @access string
+	 * @param string $str The input string.
+	 * @return array
+	 */
+	function parse_str($str)
+	{
+		$return = array();
+		$str = explode('&', $str);
+
+		foreach ($str as $section)
+		{
+			if (strpos($section, '=') !== false)
+			{
+				list($name, $value) = explode('=', $section, 2);
+				$return[urldecode($name)][] = urldecode($value);
+			}
+			else
+			{
+				$return[urldecode($section)][] = null;
+			}
+		}
+
+		return $return;
+	}
+	
+	/**
+	 * Detect XML encoding, as per XML 1.0 Appendix F.1
+	 *
+	 * @todo Add support for EBCDIC
+	 * @param string $data XML data
+	 * @return array Possible encodings
+	 */
+	function xml_encoding($data)
+	{
+		// UTF-32 Big Endian BOM
+		if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+		{
+			$encoding[] = 'UTF-32BE';
+		}
+		// UTF-32 Little Endian BOM
+		elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+		{
+			$encoding[] = 'UTF-32LE';
+		}
+		// UTF-16 Big Endian BOM
+		elseif (substr($data, 0, 2) === "\xFE\xFF")
+		{
+			$encoding[] = 'UTF-16BE';
+		}
+		// UTF-16 Little Endian BOM
+		elseif (substr($data, 0, 2) === "\xFF\xFE")
+		{
+			$encoding[] = 'UTF-16LE';
+		}
+		// UTF-8 BOM
+		elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+		{
+			$encoding[] = 'UTF-8';
+		}
+		// UTF-32 Big Endian Without BOM
+		elseif (substr($data, 0, 20) === "\x00\x00\x00\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C")
+		{
+			if ($pos = strpos($data, "\x00\x00\x00\x3F\x00\x00\x00\x3E"))
+			{
+				$parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32BE', 'UTF-8'));
+				if ($parser->parse())
+				{
+					$encoding[] = $parser->encoding;
+				}
+			}
+			$encoding[] = 'UTF-32BE';
+		}
+		// UTF-32 Little Endian Without BOM
+		elseif (substr($data, 0, 20) === "\x3C\x00\x00\x00\x3F\x00\x00\x00\x78\x00\x00\x00\x6D\x00\x00\x00\x6C\x00\x00\x00")
+		{
+			if ($pos = strpos($data, "\x3F\x00\x00\x00\x3E\x00\x00\x00"))
+			{
+				$parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 20), 'UTF-32LE', 'UTF-8'));
+				if ($parser->parse())
+				{
+					$encoding[] = $parser->encoding;
+				}
+			}
+			$encoding[] = 'UTF-32LE';
+		}
+		// UTF-16 Big Endian Without BOM
+		elseif (substr($data, 0, 10) === "\x00\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C")
+		{
+			if ($pos = strpos($data, "\x00\x3F\x00\x3E"))
+			{
+				$parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16BE', 'UTF-8'));
+				if ($parser->parse())
+				{
+					$encoding[] = $parser->encoding;
+				}
+			}
+			$encoding[] = 'UTF-16BE';
+		}
+		// UTF-16 Little Endian Without BOM
+		elseif (substr($data, 0, 10) === "\x3C\x00\x3F\x00\x78\x00\x6D\x00\x6C\x00")
+		{
+			if ($pos = strpos($data, "\x3F\x00\x3E\x00"))
+			{
+				$parser = new SimplePie_XML_Declaration_Parser(SimplePie_Misc::change_encoding(substr($data, 20, $pos - 10), 'UTF-16LE', 'UTF-8'));
+				if ($parser->parse())
+				{
+					$encoding[] = $parser->encoding;
+				}
+			}
+			$encoding[] = 'UTF-16LE';
+		}
+		// US-ASCII (or superset)
+		elseif (substr($data, 0, 5) === "\x3C\x3F\x78\x6D\x6C")
+		{
+			if ($pos = strpos($data, "\x3F\x3E"))
+			{
+				$parser = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+				if ($parser->parse())
+				{
+					$encoding[] = $parser->encoding;
+				}
+			}
+			$encoding[] = 'UTF-8';
+		}
+		// Fallback to UTF-8
+		else
+		{
+			$encoding[] = 'UTF-8';
+		}
+		return $encoding;
+	}
+}
+
+/**
+ * Decode HTML Entities
+ *
+ * This implements HTML5 as of revision 967 (2007-06-28)
+ *
+ * @package SimplePie
+ */
+class SimplePie_Decode_HTML_Entities
+{
+	/**
+	 * Data to be parsed
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $data = '';
+
+	/**
+	 * Currently consumed bytes
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $consumed = '';
+
+	/**
+	 * Position of the current byte being parsed
+	 *
+	 * @access private
+	 * @var int
+	 */
+	var $position = 0;
+
+	/**
+	 * Create an instance of the class with the input data
+	 *
+	 * @access public
+	 * @param string $data Input data
+	 */
+	function SimplePie_Decode_HTML_Entities($data)
+	{
+		$this->data = $data;
+	}
+
+	/**
+	 * Parse the input data
+	 *
+	 * @access public
+	 * @return string Output data
+	 */
+	function parse()
+	{
+		while (($this->position = strpos($this->data, '&', $this->position)) !== false)
+		{
+			$this->consume();
+			$this->entity();
+			$this->consumed = '';
+		}
+		return $this->data;
+	}
+
+	/**
+	 * Consume the next byte
+	 *
+	 * @access private
+	 * @return mixed The next byte, or false, if there is no more data
+	 */
+	function consume()
+	{
+		if (isset($this->data[$this->position]))
+		{
+			$this->consumed .= $this->data[$this->position];
+			return $this->data[$this->position++];
+		}
+		else
+		{
+			$this->consumed = false;
+			return false;
+		}
+	}
+
+	/**
+	 * Consume a range of characters
+	 *
+	 * @access private
+	 * @param string $chars Characters to consume
+	 * @return mixed A series of characters that match the range, or false
+	 */
+	function consume_range($chars)
+	{
+		if ($len = strspn($this->data, $chars, $this->position))
+		{
+			$data = substr($this->data, $this->position, $len);
+			$this->consumed .= $data;
+			$this->position += $len;
+			return $data;
+		}
+		else
+		{
+			$this->consumed = false;
+			return false;
+		}
+	}
+
+	/**
+	 * Unconsume one byte
+	 *
+	 * @access private
+	 */
+	function unconsume()
+	{
+		$this->consumed = substr($this->consumed, 0, -1);
+		$this->position--;
+	}
+
+	/**
+	 * Decode an entity
+	 *
+	 * @access private
+	 */
+	function entity()
+	{
+		switch ($this->consume())
+		{
+			case "\x09":
+			case "\x0A":
+			case "\x0B":
+			case "\x0B":
+			case "\x0C":
+			case "\x20":
+			case "\x3C":
+			case "\x26":
+			case false:
+				break;
+
+			case "\x23":
+				switch ($this->consume())
+				{
+					case "\x78":
+					case "\x58":
+						$range = '0123456789ABCDEFabcdef';
+						$hex = true;
+						break;
+
+					default:
+						$range = '0123456789';
+						$hex = false;
+						$this->unconsume();
+						break;
+				}
+
+				if ($codepoint = $this->consume_range($range))
+				{
+					static $windows_1252_specials = array(0x0D => "\x0A", 0x80 => "\xE2\x82\xAC", 0x81 => "\xEF\xBF\xBD", 0x82 => "\xE2\x80\x9A", 0x83 => "\xC6\x92", 0x84 => "\xE2\x80\x9E", 0x85 => "\xE2\x80\xA6", 0x86 => "\xE2\x80\xA0", 0x87 => "\xE2\x80\xA1", 0x88 => "\xCB\x86", 0x89 => "\xE2\x80\xB0", 0x8A => "\xC5\xA0", 0x8B => "\xE2\x80\xB9", 0x8C => "\xC5\x92", 0x8D => "\xEF\xBF\xBD", 0x8E => "\xC5\xBD", 0x8F => "\xEF\xBF\xBD", 0x90 => "\xEF\xBF\xBD", 0x91 => "\xE2\x80\x98", 0x92 => "\xE2\x80\x99", 0x93 => "\xE2\x80\x9C", 0x94 => "\xE2\x80\x9D", 0x95 => "\xE2\x80\xA2", 0x96 => "\xE2\x80\x93", 0x97 => "\xE2\x80\x94", 0x98 => "\xCB\x9C", 0x99 => "\xE2\x84\xA2", 0x9A => "\xC5\xA1", 0x9B => "\xE2\x80\xBA", 0x9C => "\xC5\x93", 0x9D => "\xEF\xBF\xBD", 0x9E => "\xC5\xBE", 0x9F => "\xC5\xB8");
+
+					if ($hex)
+					{
+						$codepoint = hexdec($codepoint);
+					}
+					else
+					{
+						$codepoint = intval($codepoint);
+					}
+
+					if (isset($windows_1252_specials[$codepoint]))
+					{
+						$replacement = $windows_1252_specials[$codepoint];
+					}
+					else
+					{
+						$replacement = SimplePie_Misc::codepoint_to_utf8($codepoint);
+					}
+
+					if ($this->consume() != ';')
+					{
+						$this->unconsume();
+					}
+
+					$consumed_length = strlen($this->consumed);
+					$this->data = substr_replace($this->data, $replacement, $this->position - $consumed_length, $consumed_length);
+					$this->position += strlen($replacement) - $consumed_length;
+				}
+				break;
+
+			default:
+				static $entities = array('Aacute' => "\xC3\x81", 'aacute' => "\xC3\xA1", 'Aacute;' => "\xC3\x81", 'aacute;' => "\xC3\xA1", 'Acirc' => "\xC3\x82", 'acirc' => "\xC3\xA2", 'Acirc;' => "\xC3\x82", 'acirc;' => "\xC3\xA2", 'acute' => "\xC2\xB4", 'acute;' => "\xC2\xB4", 'AElig' => "\xC3\x86", 'aelig' => "\xC3\xA6", 'AElig;' => "\xC3\x86", 'aelig;' => "\xC3\xA6", 'Agrave' => "\xC3\x80", 'agrave' => "\xC3\xA0", 'Agrave;' => "\xC3\x80", 'agrave;' => "\xC3\xA0", 'alefsym;' => "\xE2\x84\xB5", 'Alpha;' => "\xCE\x91", 'alpha;' => "\xCE\xB1", 'AMP' => "\x26", 'amp' => "\x26", 'AMP;' => "\x26", 'amp;' => "\x26", 'and;' => "\xE2\x88\xA7", 'ang;' => "\xE2\x88\xA0", 'apos;' => "\x27", 'Aring' => "\xC3\x85", 'aring' => "\xC3\xA5", 'Aring;' => "\xC3\x85", 'aring;' => "\xC3\xA5", 'asymp;' => "\xE2\x89\x88", 'Atilde' => "\xC3\x83", 'atilde' => "\xC3\xA3", 'Atilde;' => "\xC3\x83", 'atilde;' => "\xC3\xA3", 'Auml' => "\xC3\x84", 'auml' => "\xC3\xA4", 'Auml;' => "\xC3\x84", 'auml;' => "\xC3\xA4", 'bdquo;' => "\xE2\x80\x9E", 'Beta;' => "\xCE\x92", 'beta;' => "\xCE\xB2", 'brvbar' => "\xC2\xA6", 'brvbar;' => "\xC2\xA6", 'bull;' => "\xE2\x80\xA2", 'cap;' => "\xE2\x88\xA9", 'Ccedil' => "\xC3\x87", 'ccedil' => "\xC3\xA7", 'Ccedil;' => "\xC3\x87", 'ccedil;' => "\xC3\xA7", 'cedil' => "\xC2\xB8", 'cedil;' => "\xC2\xB8", 'cent' => "\xC2\xA2", 'cent;' => "\xC2\xA2", 'Chi;' => "\xCE\xA7", 'chi;' => "\xCF\x87", 'circ;' => "\xCB\x86", 'clubs;' => "\xE2\x99\xA3", 'cong;' => "\xE2\x89\x85", 'COPY' => "\xC2\xA9", 'copy' => "\xC2\xA9", 'COPY;' => "\xC2\xA9", 'copy;' => "\xC2\xA9", 'crarr;' => "\xE2\x86\xB5", 'cup;' => "\xE2\x88\xAA", 'curren' => "\xC2\xA4", 'curren;' => "\xC2\xA4", 'Dagger;' => "\xE2\x80\xA1", 'dagger;' => "\xE2\x80\xA0", 'dArr;' => "\xE2\x87\x93", 'darr;' => "\xE2\x86\x93", 'deg' => "\xC2\xB0", 'deg;' => "\xC2\xB0", 'Delta;' => "\xCE\x94", 'delta;' => "\xCE\xB4", 'diams;' => "\xE2\x99\xA6", 'divide' => "\xC3\xB7", 'divide;' => "\xC3\xB7", 'Eacute' => "\xC3\x89", 'eacute' => "\xC3\xA9", 'Eacute;' => "\xC3\x89", 'eacute;' => "\xC3\xA9", 'Ecirc' => "\xC3\x8A", 'ecirc' => "\xC3\xAA", 'Ecirc;' => "\xC3\x8A", 'ecirc;' => "\xC3\xAA", 'Egrave' => "\xC3\x88", 'egrave' => "\xC3\xA8", 'Egrave;' => "\xC3\x88", 'egrave;' => "\xC3\xA8", 'empty;' => "\xE2\x88\x85", 'emsp;' => "\xE2\x80\x83", 'ensp;' => "\xE2\x80\x82", 'Epsilon;' => "\xCE\x95", 'epsilon;' => "\xCE\xB5", 'equiv;' => "\xE2\x89\xA1", 'Eta;' => "\xCE\x97", 'eta;' => "\xCE\xB7", 'ETH' => "\xC3\x90", 'eth' => "\xC3\xB0", 'ETH;' => "\xC3\x90", 'eth;' => "\xC3\xB0", 'Euml' => "\xC3\x8B", 'euml' => "\xC3\xAB", 'Euml;' => "\xC3\x8B", 'euml;' => "\xC3\xAB", 'euro;' => "\xE2\x82\xAC", 'exist;' => "\xE2\x88\x83", 'fnof;' => "\xC6\x92", 'forall;' => "\xE2\x88\x80", 'frac12' => "\xC2\xBD", 'frac12;' => "\xC2\xBD", 'frac14' => "\xC2\xBC", 'frac14;' => "\xC2\xBC", 'frac34' => "\xC2\xBE", 'frac34;' => "\xC2\xBE", 'frasl;' => "\xE2\x81\x84", 'Gamma;' => "\xCE\x93", 'gamma;' => "\xCE\xB3", 'ge;' => "\xE2\x89\xA5", 'GT' => "\x3E", 'gt' => "\x3E", 'GT;' => "\x3E", 'gt;' => "\x3E", 'hArr;' => "\xE2\x87\x94", 'harr;' => "\xE2\x86\x94", 'hearts;' => "\xE2\x99\xA5", 'hellip;' => "\xE2\x80\xA6", 'Iacute' => "\xC3\x8D", 'iacute' => "\xC3\xAD", 'Iacute;' => "\xC3\x8D", 'iacute;' => "\xC3\xAD", 'Icirc' => "\xC3\x8E", 'icirc' => "\xC3\xAE", 'Icirc;' => "\xC3\x8E", 'icirc;' => "\xC3\xAE", 'iexcl' => "\xC2\xA1", 'iexcl;' => "\xC2\xA1", 'Igrave' => "\xC3\x8C", 'igrave' => "\xC3\xAC", 'Igrave;' => "\xC3\x8C", 'igrave;' => "\xC3\xAC", 'image;' => "\xE2\x84\x91", 'infin;' => "\xE2\x88\x9E", 'int;' => "\xE2\x88\xAB", 'Iota;' => "\xCE\x99", 'iota;' => "\xCE\xB9", 'iquest' => "\xC2\xBF", 'iquest;' => "\xC2\xBF", 'isin;' => "\xE2\x88\x88", 'Iuml' => "\xC3\x8F", 'iuml' => "\xC3\xAF", 'Iuml;' => "\xC3\x8F", 'iuml;' => "\xC3\xAF", 'Kappa;' => "\xCE\x9A", 'kappa;' => "\xCE\xBA", 'Lambda;' => "\xCE\x9B", 'lambda;' => "\xCE\xBB", 'lang;' => "\xE3\x80\x88", 'laquo' => "\xC2\xAB", 'laquo;' => "\xC2\xAB", 'lArr;' => "\xE2\x87\x90", 'larr;' => "\xE2\x86\x90", 'lceil;' => "\xE2\x8C\x88", 'ldquo;' => "\xE2\x80\x9C", 'le;' => "\xE2\x89\xA4", 'lfloor;' => "\xE2\x8C\x8A", 'lowast;' => "\xE2\x88\x97", 'loz;' => "\xE2\x97\x8A", 'lrm;' => "\xE2\x80\x8E", 'lsaquo;' => "\xE2\x80\xB9", 'lsquo;' => "\xE2\x80\x98", 'LT' => "\x3C", 'lt' => "\x3C", 'LT;' => "\x3C", 'lt;' => "\x3C", 'macr' => "\xC2\xAF", 'macr;' => "\xC2\xAF", 'mdash;' => "\xE2\x80\x94", 'micro' => "\xC2\xB5", 'micro;' => "\xC2\xB5", 'middot' => "\xC2\xB7", 'middot;' => "\xC2\xB7", 'minus;' => "\xE2\x88\x92", 'Mu;' => "\xCE\x9C", 'mu;' => "\xCE\xBC", 'nabla;' => "\xE2\x88\x87", 'nbsp' => "\xC2\xA0", 'nbsp;' => "\xC2\xA0", 'ndash;' => "\xE2\x80\x93", 'ne;' => "\xE2\x89\xA0", 'ni;' => "\xE2\x88\x8B", 'not' => "\xC2\xAC", 'not;' => "\xC2\xAC", 'notin;' => "\xE2\x88\x89", 'nsub;' => "\xE2\x8A\x84", 'Ntilde' => "\xC3\x91", 'ntilde' => "\xC3\xB1", 'Ntilde;' => "\xC3\x91", 'ntilde;' => "\xC3\xB1", 'Nu;' => "\xCE\x9D", 'nu;' => "\xCE\xBD", 'Oacute' => "\xC3\x93", 'oacute' => "\xC3\xB3", 'Oacute;' => "\xC3\x93", 'oacute;' => "\xC3\xB3", 'Ocirc' => "\xC3\x94", 'ocirc' => "\xC3\xB4", 'Ocirc;' => "\xC3\x94", 'ocirc;' => "\xC3\xB4", 'OElig;' => "\xC5\x92", 'oelig;' => "\xC5\x93", 'Ograve' => "\xC3\x92", 'ograve' => "\xC3\xB2", 'Ograve;' => "\xC3\x92", 'ograve;' => "\xC3\xB2", 'oline;' => "\xE2\x80\xBE", 'Omega;' => "\xCE\xA9", 'omega;' => "\xCF\x89", 'Omicron;' => "\xCE\x9F", 'omicron;' => "\xCE\xBF", 'oplus;' => "\xE2\x8A\x95", 'or;' => "\xE2\x88\xA8", 'ordf' => "\xC2\xAA", 'ordf;' => "\xC2\xAA", 'ordm' => "\xC2\xBA", 'ordm;' => "\xC2\xBA", 'Oslash' => "\xC3\x98", 'oslash' => "\xC3\xB8", 'Oslash;' => "\xC3\x98", 'oslash;' => "\xC3\xB8", 'Otilde' => "\xC3\x95", 'otilde' => "\xC3\xB5", 'Otilde;' => "\xC3\x95", 'otilde;' => "\xC3\xB5", 'otimes;' => "\xE2\x8A\x97", 'Ouml' => "\xC3\x96", 'ouml' => "\xC3\xB6", 'Ouml;' => "\xC3\x96", 'ouml;' => "\xC3\xB6", 'para' => "\xC2\xB6", 'para;' => "\xC2\xB6", 'part;' => "\xE2\x88\x82", 'permil;' => "\xE2\x80\xB0", 'perp;' => "\xE2\x8A\xA5", 'Phi;' => "\xCE\xA6", 'phi;' => "\xCF\x86", 'Pi;' => "\xCE\xA0", 'pi;' => "\xCF\x80", 'piv;' => "\xCF\x96", 'plusmn' => "\xC2\xB1", 'plusmn;' => "\xC2\xB1", 'pound' => "\xC2\xA3", 'pound;' => "\xC2\xA3", 'Prime;' => "\xE2\x80\xB3", 'prime;' => "\xE2\x80\xB2", 'prod;' => "\xE2\x88\x8F", 'prop;' => "\xE2\x88\x9D", 'Psi;' => "\xCE\xA8", 'psi;' => "\xCF\x88", 'QUOT' => "\x22", 'quot' => "\x22", 'QUOT;' => "\x22", 'quot;' => "\x22", 'radic;' => "\xE2\x88\x9A", 'rang;' => "\xE3\x80\x89", 'raquo' => "\xC2\xBB", 'raquo;' => "\xC2\xBB", 'rArr;' => "\xE2\x87\x92", 'rarr;' => "\xE2\x86\x92", 'rceil;' => "\xE2\x8C\x89", 'rdquo;' => "\xE2\x80\x9D", 'real;' => "\xE2\x84\x9C", 'REG' => "\xC2\xAE", 'reg' => "\xC2\xAE", 'REG;' => "\xC2\xAE", 'reg;' => "\xC2\xAE", 'rfloor;' => "\xE2\x8C\x8B", 'Rho;' => "\xCE\xA1", 'rho;' => "\xCF\x81", 'rlm;' => "\xE2\x80\x8F", 'rsaquo;' => "\xE2\x80\xBA", 'rsquo;' => "\xE2\x80\x99", 'sbquo;' => "\xE2\x80\x9A", 'Scaron;' => "\xC5\xA0", 'scaron;' => "\xC5\xA1", 'sdot;' => "\xE2\x8B\x85", 'sect' => "\xC2\xA7", 'sect;' => "\xC2\xA7", 'shy' => "\xC2\xAD", 'shy;' => "\xC2\xAD", 'Sigma;' => "\xCE\xA3", 'sigma;' => "\xCF\x83", 'sigmaf;' => "\xCF\x82", 'sim;' => "\xE2\x88\xBC", 'spades;' => "\xE2\x99\xA0", 'sub;' => "\xE2\x8A\x82", 'sube;' => "\xE2\x8A\x86", 'sum;' => "\xE2\x88\x91", 'sup;' => "\xE2\x8A\x83", 'sup1' => "\xC2\xB9", 'sup1;' => "\xC2\xB9", 'sup2' => "\xC2\xB2", 'sup2;' => "\xC2\xB2", 'sup3' => "\xC2\xB3", 'sup3;' => "\xC2\xB3", 'supe;' => "\xE2\x8A\x87", 'szlig' => "\xC3\x9F", 'szlig;' => "\xC3\x9F", 'Tau;' => "\xCE\xA4", 'tau;' => "\xCF\x84", 'there4;' => "\xE2\x88\xB4", 'Theta;' => "\xCE\x98", 'theta;' => "\xCE\xB8", 'thetasym;' => "\xCF\x91", 'thinsp;' => "\xE2\x80\x89", 'THORN' => "\xC3\x9E", 'thorn' => "\xC3\xBE", 'THORN;' => "\xC3\x9E", 'thorn;' => "\xC3\xBE", 'tilde;' => "\xCB\x9C", 'times' => "\xC3\x97", 'times;' => "\xC3\x97", 'TRADE;' => "\xE2\x84\xA2", 'trade;' => "\xE2\x84\xA2", 'Uacute' => "\xC3\x9A", 'uacute' => "\xC3\xBA", 'Uacute;' => "\xC3\x9A", 'uacute;' => "\xC3\xBA", 'uArr;' => "\xE2\x87\x91", 'uarr;' => "\xE2\x86\x91", 'Ucirc' => "\xC3\x9B", 'ucirc' => "\xC3\xBB", 'Ucirc;' => "\xC3\x9B", 'ucirc;' => "\xC3\xBB", 'Ugrave' => "\xC3\x99", 'ugrave' => "\xC3\xB9", 'Ugrave;' => "\xC3\x99", 'ugrave;' => "\xC3\xB9", 'uml' => "\xC2\xA8", 'uml;' => "\xC2\xA8", 'upsih;' => "\xCF\x92", 'Upsilon;' => "\xCE\xA5", 'upsilon;' => "\xCF\x85", 'Uuml' => "\xC3\x9C", 'uuml' => "\xC3\xBC", 'Uuml;' => "\xC3\x9C", 'uuml;' => "\xC3\xBC", 'weierp;' => "\xE2\x84\x98", 'Xi;' => "\xCE\x9E", 'xi;' => "\xCE\xBE", 'Yacute' => "\xC3\x9D", 'yacute' => "\xC3\xBD", 'Yacute;' => "\xC3\x9D", 'yacute;' => "\xC3\xBD", 'yen' => "\xC2\xA5", 'yen;' => "\xC2\xA5", 'yuml' => "\xC3\xBF", 'Yuml;' => "\xC5\xB8", 'yuml;' => "\xC3\xBF", 'Zeta;' => "\xCE\x96", 'zeta;' => "\xCE\xB6", 'zwj;' => "\xE2\x80\x8D", 'zwnj;' => "\xE2\x80\x8C");
+
+				for ($i = 0, $match = null; $i < 9 && $this->consume() !== false; $i++)
+				{
+					$consumed = substr($this->consumed, 1);
+					if (isset($entities[$consumed]))
+					{
+						$match = $consumed;
+					}
+				}
+
+				if ($match !== null)
+				{
+ 					$this->data = substr_replace($this->data, $entities[$match], $this->position - strlen($consumed) - 1, strlen($match) + 1);
+					$this->position += strlen($entities[$match]) - strlen($consumed) - 1;
+				}
+				break;
+		}
+	}
+}
+
+/**
+ * Date Parser
+ *
+ * @package SimplePie
+ */
+class SimplePie_Parse_Date
+{
+	/**
+	 * Input data
+	 *
+	 * @access protected
+	 * @var string
+	 */
+	var $date;
+
+	/**
+	 * List of days, calendar day name => ordinal day number in the week
+	 *
+	 * @access protected
+	 * @var array
+	 */
+	var $day = array(
+		// English
+		'mon' => 1,
+		'monday' => 1,
+		'tue' => 2,
+		'tuesday' => 2,
+		'wed' => 3,
+		'wednesday' => 3,
+		'thu' => 4,
+		'thursday' => 4,
+		'fri' => 5,
+		'friday' => 5,
+		'sat' => 6,
+		'saturday' => 6,
+		'sun' => 7,
+		'sunday' => 7,
+		// Dutch
+		'maandag' => 1,
+		'dinsdag' => 2,
+		'woensdag' => 3,
+		'donderdag' => 4,
+		'vrijdag' => 5,
+		'zaterdag' => 6,
+		'zondag' => 7,
+		// French
+		'lundi' => 1,
+		'mardi' => 2,
+		'mercredi' => 3,
+		'jeudi' => 4,
+		'vendredi' => 5,
+		'samedi' => 6,
+		'dimanche' => 7,
+		// German
+		'montag' => 1,
+		'dienstag' => 2,
+		'mittwoch' => 3,
+		'donnerstag' => 4,
+		'freitag' => 5,
+		'samstag' => 6,
+		'sonnabend' => 6,
+		'sonntag' => 7,
+		// Italian
+		'lunedÃ¬' => 1,
+		'martedÃ¬' => 2,
+		'mercoledÃ¬' => 3,
+		'giovedÃ¬' => 4,
+		'venerdÃ¬' => 5,
+		'sabato' => 6,
+		'domenica' => 7,
+		// Spanish
+		'lunes' => 1,
+		'martes' => 2,
+		'miÃ©rcoles' => 3,
+		'jueves' => 4,
+		'viernes' => 5,
+		'sÃ¡bado' => 6,
+		'domingo' => 7,
+		// Finnish
+		'maanantai' => 1,
+		'tiistai' => 2,
+		'keskiviikko' => 3,
+		'torstai' => 4,
+		'perjantai' => 5,
+		'lauantai' => 6,
+		'sunnuntai' => 7,
+		// Hungarian
+		'hÃ©tfÅ' => 1,
+		'kedd' => 2,
+		'szerda' => 3,
+		'csÃŒtÃ¶rtok' => 4,
+		'pÃ©ntek' => 5,
+		'szombat' => 6,
+		'vasÃ¡rnap' => 7,
+		// Greek
+		'ÎÎµÏ
+' => 1,
+		'Î€ÏÎ¹' => 2,
+		'Î€ÎµÏ' => 3,
+		'Î ÎµÎŒ' => 4,
+		'Î Î±Ï' => 5,
+		'Î£Î±Î²' => 6,
+		'ÎÏ
+Ï' => 7,
+	);
+
+	/**
+	 * List of months, calendar month name => calendar month number
+	 *
+	 * @access protected
+	 * @var array
+	 */
+	var $month = array(
+		// English
+		'jan' => 1,
+		'january' => 1,
+		'feb' => 2,
+		'february' => 2,
+		'mar' => 3,
+		'march' => 3,
+		'apr' => 4,
+		'april' => 4,
+		'may' => 5,
+		// No long form of May
+		'jun' => 6,
+		'june' => 6,
+		'jul' => 7,
+		'july' => 7,
+		'aug' => 8,
+		'august' => 8,
+		'sep' => 9,
+		'september' => 8,
+		'oct' => 10,
+		'october' => 10,
+		'nov' => 11,
+		'november' => 11,
+		'dec' => 12,
+		'december' => 12,
+		// Dutch
+		'januari' => 1,
+		'februari' => 2,
+		'maart' => 3,
+		'april' => 4,
+		'mei' => 5,
+		'juni' => 6,
+		'juli' => 7,
+		'augustus' => 8,
+		'september' => 9,
+		'oktober' => 10,
+		'november' => 11,
+		'december' => 12,
+		// French
+		'janvier' => 1,
+		'fÃ©vrier' => 2,
+		'mars' => 3,
+		'avril' => 4,
+		'mai' => 5,
+		'juin' => 6,
+		'juillet' => 7,
+		'aoÃ»t' => 8,
+		'septembre' => 9,
+		'octobre' => 10,
+		'novembre' => 11,
+		'dÃ©cembre' => 12,
+		// German
+		'januar' => 1,
+		'februar' => 2,
+		'mÃ€rz' => 3,
+		'april' => 4,
+		'mai' => 5,
+		'juni' => 6,
+		'juli' => 7,
+		'august' => 8,
+		'september' => 9,
+		'oktober' => 10,
+		'november' => 11,
+		'dezember' => 12,
+		// Italian
+		'gennaio' => 1,
+		'febbraio' => 2,
+		'marzo' => 3,
+		'aprile' => 4,
+		'maggio' => 5,
+		'giugno' => 6,
+		'luglio' => 7,
+		'agosto' => 8,
+		'settembre' => 9,
+		'ottobre' => 10,
+		'novembre' => 11,
+		'dicembre' => 12,
+		// Spanish
+		'enero' => 1,
+		'febrero' => 2,
+		'marzo' => 3,
+		'abril' => 4,
+		'mayo' => 5,
+		'junio' => 6,
+		'julio' => 7,
+		'agosto' => 8,
+		'septiembre' => 9,
+		'setiembre' => 9,
+		'octubre' => 10,
+		'noviembre' => 11,
+		'diciembre' => 12,
+		// Finnish
+		'tammikuu' => 1,
+		'helmikuu' => 2,
+		'maaliskuu' => 3,
+		'huhtikuu' => 4,
+		'toukokuu' => 5,
+		'kesÃ€kuu' => 6,
+		'heinÃ€kuu' => 7,
+		'elokuu' => 8,
+		'suuskuu' => 9,
+		'lokakuu' => 10,
+		'marras' => 11,
+		'joulukuu' => 12,
+		// Hungarian
+		'januÃ¡r' => 1,
+		'februÃ¡r' => 2,
+		'mÃ¡rcius' => 3,
+		'Ã¡prilis' => 4,
+		'mÃ¡jus' => 5,
+		'jÃºnius' => 6,
+		'jÃºlius' => 7,
+		'augusztus' => 8,
+		'szeptember' => 9,
+		'oktÃ³ber' => 10,
+		'november' => 11,
+		'december' => 12,
+		// Greek
+		'ÎÎ±Îœ' => 1,
+		'ÎŠÎµÎ²' => 2,
+		'ÎÎ¬Ï' => 3,
+		'ÎÎ±Ï' => 3,
+		'ÎÏÏ' => 4,
+		'ÎÎ¬Î¹' => 5,
+		'ÎÎ±Ï' => 5,
+		'ÎÎ±Î¹' => 5,
+		'ÎÎ¿ÏÎœ' => 6,
+		'ÎÎ¿Îœ' => 6,
+		'ÎÎ¿ÏÎ»' => 7,
+		'ÎÎ¿Î»' => 7,
+		'ÎÏÎ³' => 8,
+		'ÎÏ
+Î³' => 8,
+		'Î£ÎµÏ' => 9,
+		'ÎÎºÏ' => 10,
+		'ÎÎ¿Î­' => 11,
+		'ÎÎµÎº' => 12,
+	);
+
+	/**
+	 * List of timezones, abbreviation => offset from UTC
+	 *
+	 * @access protected
+	 * @var array
+	 */
+	var $timezone = array(
+		'ACDT' => 37800,
+		'ACIT' => 28800,
+		'ACST' => 34200,
+		'ACT' => -18000,
+		'ACWDT' => 35100,
+		'ACWST' => 31500,
+		'AEDT' => 39600,
+		'AEST' => 36000,
+		'AFT' => 16200,
+		'AKDT' => -28800,
+		'AKST' => -32400,
+		'AMDT' => 18000,
+		'AMT' => -14400,
+		'ANAST' => 46800,
+		'ANAT' => 43200,
+		'ART' => -10800,
+		'AZOST' => -3600,
+		'AZST' => 18000,
+		'AZT' => 14400,
+		'BIOT' => 21600,
+		'BIT' => -43200,
+		'BOT' => -14400,
+		'BRST' => -7200,
+		'BRT' => -10800,
+		'BST' => 3600,
+		'BTT' => 21600,
+		'CAST' => 18000,
+		'CAT' => 7200,
+		'CCT' => 23400,
+		'CDT' => -18000,
+		'CEDT' => 7200,
+		'CET' => 3600,
+		'CGST' => -7200,
+		'CGT' => -10800,
+		'CHADT' => 49500,
+		'CHAST' => 45900,
+		'CIST' => -28800,
+		'CKT' => -36000,
+		'CLDT' => -10800,
+		'CLST' => -14400,
+		'COT' => -18000,
+		'CST' => -21600,
+		'CVT' => -3600,
+		'CXT' => 25200,
+		'DAVT' => 25200,
+		'DTAT' => 36000,
+		'EADT' => -18000,
+		'EAST' => -21600,
+		'EAT' => 10800,
+		'ECT' => -18000,
+		'EDT' => -14400,
+		'EEST' => 10800,
+		'EET' => 7200,
+		'EGT' => -3600,
+		'EKST' => 21600,
+		'EST' => -18000,
+		'FJT' => 43200,
+		'FKDT' => -10800,
+		'FKST' => -14400,
+		'FNT' => -7200,
+		'GALT' => -21600,
+		'GEDT' => 14400,
+		'GEST' => 10800,
+		'GFT' => -10800,
+		'GILT' => 43200,
+		'GIT' => -32400,
+		'GST' => 14400,
+		'GST' => -7200,
+		'GYT' => -14400,
+		'HAA' => -10800,
+		'HAC' => -18000,
+		'HADT' => -32400,
+		'HAE' => -14400,
+		'HAP' => -25200,
+		'HAR' => -21600,
+		'HAST' => -36000,
+		'HAT' => -9000,
+		'HAY' => -28800,
+		'HKST' => 28800,
+		'HMT' => 18000,
+		'HNA' => -14400,
+		'HNC' => -21600,
+		'HNE' => -18000,
+		'HNP' => -28800,
+		'HNR' => -25200,
+		'HNT' => -12600,
+		'HNY' => -32400,
+		'IRDT' => 16200,
+		'IRKST' => 32400,
+		'IRKT' => 28800,
+		'IRST' => 12600,
+		'JFDT' => -10800,
+		'JFST' => -14400,
+		'JST' => 32400,
+		'KGST' => 21600,
+		'KGT' => 18000,
+		'KOST' => 39600,
+		'KOVST' => 28800,
+		'KOVT' => 25200,
+		'KRAST' => 28800,
+		'KRAT' => 25200,
+		'KST' => 32400,
+		'LHDT' => 39600,
+		'LHST' => 37800,
+		'LINT' => 50400,
+		'LKT' => 21600,
+		'MAGST' => 43200,
+		'MAGT' => 39600,
+		'MAWT' => 21600,
+		'MDT' => -21600,
+		'MESZ' => 7200,
+		'MEZ' => 3600,
+		'MHT' => 43200,
+		'MIT' => -34200,
+		'MNST' => 32400,
+		'MSDT' => 14400,
+		'MSST' => 10800,
+		'MST' => -25200,
+		'MUT' => 14400,
+		'MVT' => 18000,
+		'MYT' => 28800,
+		'NCT' => 39600,
+		'NDT' => -9000,
+		'NFT' => 41400,
+		'NMIT' => 36000,
+		'NOVST' => 25200,
+		'NOVT' => 21600,
+		'NPT' => 20700,
+		'NRT' => 43200,
+		'NST' => -12600,
+		'NUT' => -39600,
+		'NZDT' => 46800,
+		'NZST' => 43200,
+		'OMSST' => 25200,
+		'OMST' => 21600,
+		'PDT' => -25200,
+		'PET' => -18000,
+		'PETST' => 46800,
+		'PETT' => 43200,
+		'PGT' => 36000,
+		'PHOT' => 46800,
+		'PHT' => 28800,
+		'PKT' => 18000,
+		'PMDT' => -7200,
+		'PMST' => -10800,
+		'PONT' => 39600,
+		'PST' => -28800,
+		'PWT' => 32400,
+		'PYST' => -10800,
+		'PYT' => -14400,
+		'RET' => 14400,
+		'ROTT' => -10800,
+		'SAMST' => 18000,
+		'SAMT' => 14400,
+		'SAST' => 7200,
+		'SBT' => 39600,
+		'SCDT' => 46800,
+		'SCST' => 43200,
+		'SCT' => 14400,
+		'SEST' => 3600,
+		'SGT' => 28800,
+		'SIT' => 28800,
+		'SRT' => -10800,
+		'SST' => -39600,
+		'SYST' => 10800,
+		'SYT' => 7200,
+		'TFT' => 18000,
+		'THAT' => -36000,
+		'TJT' => 18000,
+		'TKT' => -36000,
+		'TMT' => 18000,
+		'TOT' => 46800,
+		'TPT' => 32400,
+		'TRUT' => 36000,
+		'TVT' => 43200,
+		'TWT' => 28800,
+		'UYST' => -7200,
+		'UYT' => -10800,
+		'UZT' => 18000,
+		'VET' => -14400,
+		'VLAST' => 39600,
+		'VLAT' => 36000,
+		'VOST' => 21600,
+		'VUT' => 39600,
+		'WAST' => 7200,
+		'WAT' => 3600,
+		'WDT' => 32400,
+		'WEST' => 3600,
+		'WFT' => 43200,
+		'WIB' => 25200,
+		'WIT' => 32400,
+		'WITA' => 28800,
+		'WKST' => 18000,
+		'WST' => 28800,
+		'YAKST' => 36000,
+		'YAKT' => 32400,
+		'YAPT' => 36000,
+		'YEKST' => 21600,
+		'YEKT' => 18000,
+	);
+
+	/**
+	 * Cached PCRE for SimplePie_Parse_Date::$day
+	 *
+	 * @access protected
+	 * @var string
+	 */
+	var $day_pcre;
+
+	/**
+	 * Cached PCRE for SimplePie_Parse_Date::$month
+	 *
+	 * @access protected
+	 * @var string
+	 */
+	var $month_pcre;
+
+	/**
+	 * Array of user-added callback methods
+	 *
+	 * @access private
+	 * @var array
+	 */
+	var $built_in = array();
+
+	/**
+	 * Array of user-added callback methods
+	 *
+	 * @access private
+	 * @var array
+	 */
+	var $user = array();
+
+	/**
+	 * Create new SimplePie_Parse_Date object, and set self::day_pcre,
+	 * self::month_pcre, and self::built_in
+	 *
+	 * @access private
+	 */
+	function SimplePie_Parse_Date()
+	{
+		$this->day_pcre = '(' . implode(array_keys($this->day), '|') . ')';
+		$this->month_pcre = '(' . implode(array_keys($this->month), '|') . ')';
+		
+		static $cache;
+		if (!isset($cache[get_class($this)]))
+		{
+			if (extension_loaded('Reflection'))
+			{
+				$class = new ReflectionClass(get_class($this));
+				$methods = $class->getMethods();
+				$all_methods = array();
+				foreach ($methods as $method)
+				{
+					$all_methods[] = $method->getName();
+				}
+			}
+			else
+			{
+				$all_methods = get_class_methods($this);
+			}
+		
+			foreach ($all_methods as $method)
+			{
+				if (strtolower(substr($method, 0, 5)) === 'date_')
+				{
+					$cache[get_class($this)][] = $method;
+				}
+			}
+		}
+		
+		foreach ($cache[get_class($this)] as $method)
+		{
+			$this->built_in[] = $method;
+		}
+	}
+	
+	/**
+	 * Get the object
+	 *
+	 * @access public
+	 */
+	function get()
+	{
+		static $object;
+		if (!$object)
+		{
+			$object = new SimplePie_Parse_Date;
+		}
+		return $object;
+	}
+
+	/**
+	 * Parse a date
+	 *
+	 * @final
+	 * @access public
+	 * @param string $date Date to parse
+	 * @return int Timestamp corresponding to date string, or false on failure
+	 */
+	function parse($date)
+	{
+		foreach ($this->user as $method)
+		{
+			if (($returned = call_user_func($method, $date)) !== false)
+			{
+				return $returned;
+			}
+		}
+		
+		foreach ($this->built_in as $method)
+		{
+			if (($returned = call_user_func(array(&$this, $method), $date)) !== false)
+			{
+				return $returned;
+			}
+		}
+
+		return false;
+	}
+
+	/**
+	 * Add a callback method to parse a date
+	 *
+	 * @final
+	 * @access public
+	 * @param callback $callback
+	 */
+	function add_callback($callback)
+	{
+		if (is_callable($callback))
+		{
+			$this->user[] = $callback;
+		}
+		else
+		{
+			trigger_error('User-supplied function must be a valid callback', E_USER_WARNING);
+		}
+	}
+
+	/**
+	 * Parse a superset of W3C-DTF (allows hyphens and colons to be omitted, as
+	 * well as allowing any of upper or lower case "T", horizontal tabs, or
+	 * spaces to be used as the time seperator (including more than one))
+	 *
+	 * @access protected
+	 * @return int Timestamp
+	 */
+	function date_w3cdtf($date)
+	{
+		static $pcre;
+		if (!$pcre)
+		{
+			$year = '([0-9]{4})';
+			$month = $day = $hour = $minute = $second = '([0-9]{2})';
+			$decimal = '([0-9]*)';
+			$zone = '(?:(Z)|([+\-])([0-9]{1,2}):?([0-9]{1,2}))';
+			$pcre = '/^' . $year . '(?:-?' . $month . '(?:-?' . $day . '(?:[Tt\x09\x20]+' . $hour . '(?::?' . $minute . '(?::?' . $second . '(?:.' . $decimal . ')?)?)?' . $zone . ')?)?)?$/';
+		}
+		if (preg_match($pcre, $date, $match))
+		{
+			/*
+			Capturing subpatterns:
+			1: Year
+			2: Month
+			3: Day
+			4: Hour
+			5: Minute
+			6: Second
+			7: Decimal fraction of a second
+			8: Zulu
+			9: Timezone Â±
+			10: Timezone hours
+			11: Timezone minutes
+			*/
+
+			// Fill in empty matches
+			for ($i = count($match); $i <= 3; $i++)
+			{
+				$match[$i] = '1';
+			}
+
+			for ($i = count($match); $i <= 7; $i++)
+			{
+				$match[$i] = '0';
+			}
+
+			// Numeric timezone
+			if (isset($match[9]) && $match[9] !== '')
+			{
+				$timezone = $match[10] * 3600;
+				$timezone += $match[11] * 60;
+				if ($match[9] === '-')
+				{
+					$timezone = 0 - $timezone;
+				}
+			}
+			else
+			{
+				$timezone = 0;
+			}
+
+			// Convert the number of seconds to an integer, taking decimals into account
+			$second = round($match[6] + $match[7] / pow(10, strlen($match[7])));
+
+			return gmmktime($match[4], $match[5], $second, $match[2], $match[3], $match[1]) - $timezone;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * Remove RFC822 comments
+	 *
+	 * @access protected
+	 * @param string $data Data to strip comments from
+	 * @return string Comment stripped string
+	 */
+	function remove_rfc2822_comments($string)
+	{
+		$string = (string) $string;
+		$position = 0;
+		$length = strlen($string);
+		$depth = 0;
+
+		$output = '';
+
+		while ($position < $length && ($pos = strpos($string, '(', $position)) !== false)
+		{
+			$output .= substr($string, $position, $pos - $position);
+			$position = $pos + 1;
+			if ($string[$pos - 1] !== '\\')
+			{
+				$depth++;
+				while ($depth && $position < $length)
+				{
+					$position += strcspn($string, '()', $position);
+					if ($string[$position - 1] === '\\')
+					{
+						$position++;
+						continue;
+					}
+					elseif (isset($string[$position]))
+					{
+						switch ($string[$position])
+						{
+							case '(':
+								$depth++;
+								break;
+
+							case ')':
+								$depth--;
+								break;
+						}
+						$position++;
+					}
+					else
+					{
+						break;
+					}
+				}
+			}
+			else
+			{
+				$output .= '(';
+			}
+		}
+		$output .= substr($string, $position);
+
+		return $output;
+	}
+
+	/**
+	 * Parse RFC2822's date format
+	 *
+	 * @access protected
+	 * @return int Timestamp
+	 */
+	function date_rfc2822($date)
+	{
+		static $pcre;
+		if (!$pcre)
+		{
+			$wsp = '[\x09\x20]';
+			$fws = '(?:' . $wsp . '+|' . $wsp . '*(?:\x0D\x0A' . $wsp . '+)+)';
+			$optional_fws = $fws . '?';
+			$day_name = $this->day_pcre;
+			$month = $this->month_pcre;
+			$day = '([0-9]{1,2})';
+			$hour = $minute = $second = '([0-9]{2})';
+			$year = '([0-9]{2,4})';
+			$num_zone = '([+\-])([0-9]{2})([0-9]{2})';
+			$character_zone = '([A-Z]{1,5})';
+			$zone = '(?:' . $num_zone . '|' . $character_zone . ')';
+			$pcre = '/(?:' . $optional_fws . $day_name . $optional_fws . ',)?' . $optional_fws . $day . $fws . $month . $fws . $year . $fws . $hour . $optional_fws . ':' . $optional_fws . $minute . '(?:' . $optional_fws . ':' . $optional_fws . $second . ')?' . $fws . $zone . '/i';
+		}
+		if (preg_match($pcre, $this->remove_rfc2822_comments($date), $match))
+		{
+			/*
+			Capturing subpatterns:
+			1: Day name
+			2: Day
+			3: Month
+			4: Year
+			5: Hour
+			6: Minute
+			7: Second
+			8: Timezone Â±
+			9: Timezone hours
+			10: Timezone minutes
+			11: Alphabetic timezone
+			*/
+
+			// Find the month number
+			$month = $this->month[strtolower($match[3])];
+
+			// Numeric timezone
+			if ($match[8] !== '')
+			{
+				$timezone = $match[9] * 3600;
+				$timezone += $match[10] * 60;
+				if ($match[8] === '-')
+				{
+					$timezone = 0 - $timezone;
+				}
+			}
+			// Character timezone
+			elseif (isset($this->timezone[strtoupper($match[11])]))
+			{
+				$timezone = $this->timezone[strtoupper($match[11])];
+			}
+			// Assume everything else to be -0000
+			else
+			{
+				$timezone = 0;
+			}
+
+			// Deal with 2/3 digit years
+			if ($match[4] < 50)
+			{
+				$match[4] += 2000;
+			}
+			elseif ($match[4] < 1000)
+			{
+				$match[4] += 1900;
+			}
+			
+			// Second is optional, if it is empty set it to zero
+			if ($match[7] !== '')
+			{
+				$second = $match[7];
+			}
+			else
+			{
+				$second = 0;
+			}
+
+			return gmmktime($match[5], $match[6], $second, $month, $match[2], $match[4]) - $timezone;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * Parse RFC850's date format
+	 *
+	 * @access protected
+	 * @return int Timestamp
+	 */
+	function date_rfc850($date)
+	{
+		static $pcre;
+		if (!$pcre)
+		{
+			$space = '[\x09\x20]+';
+			$day_name = $this->day_pcre;
+			$month = $this->month_pcre;
+			$day = '([0-9]{1,2})';
+			$year = $hour = $minute = $second = '([0-9]{2})';
+			$zone = '([A-Z]{1,5})';
+			$pcre = '/^' . $day_name . ',' . $space . $day . '-' . $month . '-' . $year . $space . $hour . ':' . $minute . ':' . $second . $space . $zone . '$/i';
+		}
+		if (preg_match($pcre, $date, $match))
+		{
+			/*
+			Capturing subpatterns:
+			1: Day name
+			2: Day
+			3: Month
+			4: Year
+			5: Hour
+			6: Minute
+			7: Second
+			8: Timezone
+			*/
+
+			// Month
+			$month = $this->month[strtolower($match[3])];
+
+			// Character timezone
+			if (isset($this->timezone[strtoupper($match[8])]))
+			{
+				$timezone = $this->timezone[strtoupper($match[8])];
+			}
+			// Assume everything else to be -0000
+			else
+			{
+				$timezone = 0;
+			}
+
+			// Deal with 2 digit year
+			if ($match[4] < 50)
+			{
+				$match[4] += 2000;
+			}
+			else
+			{
+				$match[4] += 1900;
+			}
+
+			return gmmktime($match[5], $match[6], $match[7], $month, $match[2], $match[4]) - $timezone;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * Parse C99's asctime()'s date format
+	 *
+	 * @access protected
+	 * @return int Timestamp
+	 */
+	function date_asctime($date)
+	{
+		static $pcre;
+		if (!$pcre)
+		{
+			$space = '[\x09\x20]+';
+			$wday_name = $this->day_pcre;
+			$mon_name = $this->month_pcre;
+			$day = '([0-9]{1,2})';
+			$hour = $sec = $min = '([0-9]{2})';
+			$year = '([0-9]{4})';
+			$terminator = '\x0A?\x00?';
+			$pcre = '/^' . $wday_name . $space . $mon_name . $space . $day . $space . $hour . ':' . $min . ':' . $sec . $space . $year . $terminator . '$/i';
+		}
+		if (preg_match($pcre, $date, $match))
+		{
+			/*
+			Capturing subpatterns:
+			1: Day name
+			2: Month
+			3: Day
+			4: Hour
+			5: Minute
+			6: Second
+			7: Year
+			*/
+
+			$month = $this->month[strtolower($match[2])];
+			return gmmktime($match[4], $match[5], $match[6], $month, $match[3], $match[7]);
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	/**
+	 * Parse dates using strtotime()
+	 *
+	 * @access protected
+	 * @return int Timestamp
+	 */
+	function date_strtotime($date)
+	{
+		$strtotime = strtotime($date);
+		if ($strtotime === -1 || $strtotime === false)
+		{
+			return false;
+		}
+		else
+		{
+			return $strtotime;
+		}
+	}
+}
+
+/**
+ * Content-type sniffing
+ *
+ * @package SimplePie
+ */
+class SimplePie_Content_Type_Sniffer
+{
+	/**
+	 * File object
+	 *
+	 * @var SimplePie_File
+	 * @access private
+	 */
+	var $file;
+	
+	/**
+	 * Create an instance of the class with the input file
+	 *
+	 * @access public
+	 * @param SimplePie_Content_Type_Sniffer $file Input file
+	 */
+	function SimplePie_Content_Type_Sniffer($file)
+	{
+		$this->file = $file;
+	}
+	
+	/**
+	 * Get the Content-Type of the specified file
+	 *
+	 * @access public
+	 * @return string Actual Content-Type
+	 */
+	function get_type()
+	{
+		if (isset($this->file->headers['content-type']))
+		{
+			if (!isset($this->file->headers['content-encoding'])
+				&& ($this->file->headers['content-type'] === 'text/plain'
+					|| $this->file->headers['content-type'] === 'text/plain; charset=ISO-8859-1'
+					|| $this->file->headers['content-type'] === 'text/plain; charset=iso-8859-1'))
+			{
+				return $this->text_or_binary();
+			}
+			
+			if (($pos = strpos($this->file->headers['content-type'], ';')) !== false)
+			{ 
+				$official = substr($this->file->headers['content-type'], 0, $pos);
+			}
+			else
+			{
+				$official = $this->file->headers['content-type'];
+			}
+			$official = strtolower($official);
+			
+			if ($official === 'unknown/unknown'
+				|| $official === 'application/unknown')
+			{
+				return $this->unknown();
+			}
+			elseif (substr($official, -4) === '+xml'
+				|| $official === 'text/xml'
+				|| $official === 'application/xml')
+			{
+				return $official;
+			}
+			elseif (substr($official, 0, 6) === 'image/')
+			{
+				if ($return = $this->image())
+				{
+					return $return;
+				}
+				else
+				{
+					return $official;
+				}
+			}
+			elseif ($official === 'text/html')
+			{
+				return $this->feed_or_html();
+			}
+			else
+			{
+				return $official;
+			}
+		}
+		else
+		{
+			return $this->unknown();
+		}
+	}
+	
+	/**
+	 * Sniff text or binary
+	 *
+	 * @access private
+	 * @return string Actual Content-Type
+	 */
+	function text_or_binary()
+	{
+		if (substr($this->file->body, 0, 2) === "\xFE\xFF"
+			|| substr($this->file->body, 0, 2) === "\xFF\xFE"
+			|| substr($this->file->body, 0, 4) === "\x00\x00\xFE\xFF"
+			|| substr($this->file->body, 0, 3) === "\xEF\xBB\xBF")
+		{
+			return 'text/plain';
+		}
+		elseif (preg_match('/[\x00-\x08\x0E-\x1A\x1C-\x1F]/', $this->file->body))
+		{
+			return 'application/octect-stream';
+		}
+		else
+		{
+			return 'text/plain';
+		}
+	}
+	
+	/**
+	 * Sniff unknown
+	 *
+	 * @access private
+	 * @return string Actual Content-Type
+	 */
+	function unknown()
+	{
+		$ws = strspn($this->file->body, "\x09\x0A\x0B\x0C\x0D\x20");
+		if (strtolower(substr($this->file->body, $ws, 14)) === '<!doctype html'
+			|| strtolower(substr($this->file->body, $ws, 5)) === '<html'
+			|| strtolower(substr($this->file->body, $ws, 7)) === '<script')
+		{
+			return 'text/html';
+		}
+		elseif (substr($this->file->body, 0, 5) === '%PDF-')
+		{
+			return 'application/pdf';
+		}
+		elseif (substr($this->file->body, 0, 11) === '%!PS-Adobe-')
+		{
+			return 'application/postscript';
+		}
+		elseif (substr($this->file->body, 0, 6) === 'GIF87a'
+			|| substr($this->file->body, 0, 6) === 'GIF89a')
+		{
+			return 'image/gif';
+		}
+		elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+		{
+			return 'image/png';
+		}
+		elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+		{
+			return 'image/jpeg';
+		}
+		elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+		{
+			return 'image/bmp';
+		}
+		else
+		{
+			return $this->text_or_binary();
+		}
+	}
+	
+	/**
+	 * Sniff images
+	 *
+	 * @access private
+	 * @return string Actual Content-Type
+	 */
+	function image()
+	{
+		if (substr($this->file->body, 0, 6) === 'GIF87a'
+			|| substr($this->file->body, 0, 6) === 'GIF89a')
+		{
+			return 'image/gif';
+		}
+		elseif (substr($this->file->body, 0, 8) === "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A")
+		{
+			return 'image/png';
+		}
+		elseif (substr($this->file->body, 0, 3) === "\xFF\xD8\xFF")
+		{
+			return 'image/jpeg';
+		}
+		elseif (substr($this->file->body, 0, 2) === "\x42\x4D")
+		{
+			return 'image/bmp';
+		}
+		else
+		{
+			return false;
+		}
+	}
+	
+	/**
+	 * Sniff HTML
+	 *
+	 * @access private
+	 * @return string Actual Content-Type
+	 */
+	function feed_or_html()
+	{
+		$len = strlen($this->file->body);
+		$pos = strspn($this->file->body, "\x09\x0A\x0D\x20");
+		
+		while ($pos < $len)
+		{
+			switch ($this->file->body[$pos])
+			{
+				case "\x09":
+				case "\x0A":
+				case "\x0D":
+				case "\x20":
+					$pos += strspn($this->file->body, "\x09\x0A\x0D\x20", $pos);
+					continue 2;
+				
+				case '<':
+					$pos++;
+					break;
+				
+				default:
+					return 'text/html';
+			}
+			
+			if (substr($this->file->body, $pos, 3) === '!--')
+			{
+				$pos += 3;
+				if ($pos < $len && ($pos = strpos($this->file->body, '-->', $pos)) !== false)
+				{
+					$pos += 3;
+				}
+				else
+				{
+					return 'text/html';
+				}
+			}
+			elseif (substr($this->file->body, $pos, 1) === '!')
+			{
+				if ($pos < $len && ($pos = strpos($this->file->body, '>', $pos)) !== false)
+				{
+					$pos++;
+				}
+				else
+				{
+					return 'text/html';
+				}
+			}
+			elseif (substr($this->file->body, $pos, 1) === '?')
+			{
+				if ($pos < $len && ($pos = strpos($this->file->body, '?>', $pos)) !== false)
+				{
+					$pos += 2;
+				}
+				else
+				{
+					return 'text/html';
+				}
+			}
+			elseif (substr($this->file->body, $pos, 3) === 'rss'
+				|| substr($this->file->body, $pos, 7) === 'rdf:RDF')
+			{
+				return 'application/rss+xml';
+			}
+			elseif (substr($this->file->body, $pos, 4) === 'feed')
+			{
+				return 'application/atom+xml';
+			}
+			else
+			{
+				return 'text/html';
+			}
+		}
+		
+		return 'text/html';
+	}
+}
+
+/**
+ * Parses the XML Declaration
+ *
+ * @package SimplePie
+ */
+class SimplePie_XML_Declaration_Parser
+{
+	/**
+	 * XML Version
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $version = '1.0';
+	
+	/**
+	 * Encoding
+	 *
+	 * @access public
+	 * @var string
+	 */
+	var $encoding = 'UTF-8';
+	
+	/**
+	 * Standalone
+	 *
+	 * @access public
+	 * @var bool
+	 */
+	var $standalone = false;
+
+	/**
+	 * Current state of the state machine
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $state = 'before_version_name';
+	
+	/**
+	 * Input data
+	 *
+	 * @access private
+	 * @var string
+	 */
+	var $data = '';
+
+	/**
+	 * Input data length (to avoid calling strlen() everytime this is needed)
+	 *
+	 * @access private
+	 * @var int
+	 */
+	var $data_length = 0;
+
+	/**
+	 * Current position of the pointer
+	 *
+	 * @var int
+	 * @access private
+	 */
+	var $position = 0;
+	
+	/**
+	 * Create an instance of the class with the input data
+	 *
+	 * @access public
+	 * @param string $data Input data
+	 */
+	function SimplePie_XML_Declaration_Parser($data)
+	{
+		$this->data = $data;
+		$this->data_length = strlen($this->data);
+	}
+
+	/**
+	 * Parse the input data
+	 *
+	 * @access public
+	 * @return bool true on success, false on failure
+	 */
+	function parse()
+	{
+		while ($this->state && $this->state !== 'emit' && $this->has_data())
+		{
+			$state = $this->state;
+			$this->$state();
+		}
+		$this->data = '';
+		if ($this->state === 'emit')
+		{
+			return true;
+		}
+		else
+		{
+			$this->version = '';
+			$this->encoding = '';
+			$this->standalone = '';
+			return false;
+		}
+	}
+
+	/**
+	 * Check whether there is data beyond the pointer
+	 *
+	 * @access private
+	 * @return bool true if there is further data, false if not
+	 */
+	function has_data()
+	{
+		return (bool) ($this->position < $this->data_length);
+	}
+	
+	/**
+	 * Advance past any whitespace
+	 *
+	 * @return int Number of whitespace characters passed
+	 */
+	function skip_whitespace()
+	{
+		$whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
+		$this->position += $whitespace;
+		return $whitespace;
+	}
+	
+	/**
+	 * Read value
+	 */
+	function get_value()
+	{
+		$quote = substr($this->data, $this->position, 1);
+		if ($quote === '"' || $quote === "'")
+		{
+			$this->position++;
+			$len = strcspn($this->data, $quote, $this->position);
+			if ($this->has_data())
+			{
+				$value = substr($this->data, $this->position, $len);
+				$this->position += $len + 1;
+				return $value;
+			}
+		}
+		return false;
+	}
+	
+	function before_version_name()
+	{
+		if ($this->skip_whitespace())
+		{
+			$this->state = 'version_name';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function version_name()
+	{
+		if (substr($this->data, $this->position, 7) === 'version')
+		{
+			$this->position += 7;
+			$this->skip_whitespace();
+			$this->state = 'version_equals';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function version_equals()
+	{
+		if (substr($this->data, $this->position, 1) === '=')
+		{
+			$this->position++;
+			$this->skip_whitespace();
+			$this->state = 'version_value';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function version_value()
+	{
+		if ($this->version = $this->get_value())
+		{
+			$this->skip_whitespace();
+			if ($this->has_data())
+			{
+				$this->state = 'encoding_name';
+			}
+			else
+			{
+				$this->state = 'emit';
+			}
+		}
+		else
+		{
+			$this->state = 'standalone_name';
+		}
+	}
+	
+	function encoding_name()
+	{
+		if (substr($this->data, $this->position, 8) === 'encoding')
+		{
+			$this->position += 8;
+			$this->skip_whitespace();
+			$this->state = 'encoding_equals';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function encoding_equals()
+	{
+		if (substr($this->data, $this->position, 1) === '=')
+		{
+			$this->position++;
+			$this->skip_whitespace();
+			$this->state = 'encoding_value';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function encoding_value()
+	{
+		if ($this->encoding = $this->get_value())
+		{
+			$this->skip_whitespace();
+			if ($this->has_data())
+			{
+				$this->state = 'standalone_name';
+			}
+			else
+			{
+				$this->state = 'emit';
+			}
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function standalone_name()
+	{
+		if (substr($this->data, $this->position, 10) === 'standalone')
+		{
+			$this->position += 10;
+			$this->skip_whitespace();
+			$this->state = 'standalone_equals';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function standalone_equals()
+	{
+		if (substr($this->data, $this->position, 1) === '=')
+		{
+			$this->position++;
+			$this->skip_whitespace();
+			$this->state = 'standalone_value';
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+	
+	function standalone_value()
+	{
+		if ($standalone = $this->get_value())
+		{
+			switch ($standalone)
+			{
+				case 'yes':
+					$this->standalone = true;
+					break;
+				
+				case 'no':
+					$this->standalone = false;
+					break;
+				
+				default:
+					$this->state = false;
+					return;
+			}
+			
+			$this->skip_whitespace();
+			if ($this->has_data())
+			{
+				$this->state = false;
+			}
+			else
+			{
+				$this->state = 'emit';
+			}
+		}
+		else
+		{
+			$this->state = false;
+		}
+	}
+}
+
+class SimplePie_Locator
+{
+	var $useragent;
+	var $timeout;
+	var $file;
+	var $local = array();
+	var $elsewhere = array();
+	var $file_class = 'SimplePie_File';
+	var $cached_entities = array();
+	var $http_base;
+	var $base;
+	var $base_location = 0;
+	var $checked_feeds = 0;
+	var $max_checked_feeds = 10;
+	var $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer';
+
+	function SimplePie_Locator(&$file, $timeout = 10, $useragent = null, $file_class = 'SimplePie_File', $max_checked_feeds = 10, $content_type_sniffer_class = 'SimplePie_Content_Type_Sniffer')
+	{
+		$this->file =& $file;
+		$this->file_class = $file_class;
+		$this->useragent = $useragent;
+		$this->timeout = $timeout;
+		$this->max_checked_feeds = $max_checked_feeds;
+		$this->content_type_sniffer_class = $content_type_sniffer_class;
+	}
+
+	function find($type = SIMPLEPIE_LOCATOR_ALL)
+	{
+		if ($this->is_feed($this->file))
+		{
+			return $this->file;
+		}
+		
+		if ($this->file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
+		{
+			$sniffer = new $this->content_type_sniffer_class($this->file);
+			if ($sniffer->get_type() !== 'text/html')
+			{
+				return null;
+			}
+		}
+
+		if ($type & ~SIMPLEPIE_LOCATOR_NONE)
+		{
+			$this->get_base();
+		}
+
+		if ($type & SIMPLEPIE_LOCATOR_AUTODISCOVERY && $working = $this->autodiscovery())
+		{
+			return $working;
+		}
+
+		if ($type & (SIMPLEPIE_LOCATOR_LOCAL_EXTENSION | SIMPLEPIE_LOCATOR_LOCAL_BODY | SIMPLEPIE_LOCATOR_REMOTE_EXTENSION | SIMPLEPIE_LOCATOR_REMOTE_BODY) && $this->get_links())
+		{
+			if ($type & SIMPLEPIE_LOCATOR_LOCAL_EXTENSION && $working = $this->extension($this->local))
+			{
+				return $working;
+			}
+
+			if ($type & SIMPLEPIE_LOCATOR_LOCAL_BODY && $working = $this->body($this->local))
+			{
+				return $working;
+			}
+
+			if ($type & SIMPLEPIE_LOCATOR_REMOTE_EXTENSION && $working = $this->extension($this->elsewhere))
+			{
+				return $working;
+			}
+
+			if ($type & SIMPLEPIE_LOCATOR_REMOTE_BODY && $working = $this->body($this->elsewhere))
+			{
+				return $working;
+			}
+		}
+		return null;
+	}
+
+	function is_feed(&$file)
+	{
+		if ($file->method & SIMPLEPIE_FILE_SOURCE_REMOTE)
+		{
+			$sniffer = new $this->content_type_sniffer_class($file);
+			$sniffed = $sniffer->get_type();
+			if (in_array($sniffed, array('application/rss+xml', 'application/rdf+xml', 'application/atom+xml', 'text/xml', 'application/xml', 'text/plain')))
+			{
+				return true;
+			}
+			else
+			{
+				return false;
+			}
+		}
+		elseif ($file->method & SIMPLEPIE_FILE_SOURCE_LOCAL)
+		{
+			return true;
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	function get_base()
+	{
+		$this->http_base = $this->file->url;
+		$this->base = $this->http_base;
+		$elements = SimplePie_Misc::get_element('base', $this->file->body);
+		foreach ($elements as $element)
+		{
+			if ($element['attribs']['href']['data'] !== '')
+			{
+				$this->base = SimplePie_Misc::absolutize_url(trim($element['attribs']['href']['data']), $this->http_base);
+				$this->base_location = $element['offset'];
+				break;
+			}
+		}
+	}
+
+	function autodiscovery()
+	{
+		$links = array_merge(SimplePie_Misc::get_element('link', $this->file->body), SimplePie_Misc::get_element('a', $this->file->body), SimplePie_Misc::get_element('area', $this->file->body));
+		$done = array();
+		foreach ($links as $link)
+		{
+			if ($this->checked_feeds == $this->max_checked_feeds)
+			{
+				break;
+			}
+			if (isset($link['attribs']['href']['data']) && isset($link['attribs']['rel']['data']))
+			{
+				$rel = array_unique(SimplePie_Misc::space_seperated_tokens(strtolower($link['attribs']['rel']['data'])));
+
+				if ($this->base_location < $link['offset'])
+				{
+					$href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
+				}
+				else
+				{
+					$href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
+				}
+
+				if (!in_array($href, $done) && in_array('feed', $rel) || (in_array('alternate', $rel) && !empty($link['attribs']['type']['data']) && in_array(strtolower(SimplePie_Misc::parse_mime($link['attribs']['type']['data'])), array('application/rss+xml', 'application/atom+xml'))))
+				{
+					$this->checked_feeds++;
+					$feed =& new $this->file_class($href, $this->timeout, 5, null, $this->useragent);
+					if ($this->is_feed($feed))
+					{
+						return $feed;
+					}
+				}
+				$done[] = $href;
+			}
+		}
+		return null;
+	}
+
+	function get_links()
+	{
+		$links = SimplePie_Misc::get_element('a', $this->file->body);
+		foreach ($links as $link)
+		{
+			if (isset($link['attribs']['href']['data']))
+			{
+				$href = trim($link['attribs']['href']['data']);
+				$parsed = SimplePie_Misc::parse_url($href);
+				if ($parsed['scheme'] === '' || preg_match('/^(http(s)|feed)?$/i', $parsed['scheme']))
+				{
+					if ($this->base_location < $link['offset'])
+					{
+						$href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->base);
+					}
+					else
+					{
+						$href = SimplePie_Misc::absolutize_url(trim($link['attribs']['href']['data']), $this->http_base);
+					}
+
+					$current = SimplePie_Misc::parse_url($this->file->url);
+
+					if ($parsed['authority'] === '' || $parsed['authority'] == $current['authority'])
+					{
+						$this->local[] = $href;
+					}
+					else
+					{
+						$this->elsewhere[] = $href;
+					}
+				}
+			}
+		}
+		$this->local = array_unique($this->local);
+		$this->elsewhere = array_unique($this->elsewhere);
+		if (!empty($this->local) || !empty($this->elsewhere))
+		{
+			return true;
+		}
+		return null;
+	}
+
+	function extension(&$array)
+	{
+		foreach ($array as $key => $value)
+		{
+			if ($this->checked_feeds == $this->max_checked_feeds)
+			{
+				break;
+			}
+			if (in_array(strtolower(strrchr($value, '.')), array('.rss', '.rdf', '.atom', '.xml')))
+			{
+				$this->checked_feeds++;
+				$feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
+				if ($this->is_feed($feed))
+				{
+					return $feed;
+				}
+				else
+				{
+					unset($array[$key]);
+				}
+			}
+		}
+		return null;
+	}
+
+	function body(&$array)
+	{
+		foreach ($array as $key => $value)
+		{
+			if ($this->checked_feeds == $this->max_checked_feeds)
+			{
+				break;
+			}
+			if (preg_match('/(rss|rdf|atom|xml)/i', $value))
+			{
+				$this->checked_feeds++;
+				$feed =& new $this->file_class($value, $this->timeout, 5, null, $this->useragent);
+				if ($this->is_feed($feed))
+				{
+					return $feed;
+				}
+				else
+				{
+					unset($array[$key]);
+				}
+			}
+		}
+		return null;
+	}
+}
+
+class SimplePie_Parser
+{
+	var $error_code;
+	var $error_string;
+	var $current_line;
+	var $current_column;
+	var $current_byte;
+	var $separator = ' ';
+	var $feed = false;
+	var $namespace = array('');
+	var $element = array('');
+	var $xml_base = array('');
+	var $xml_base_explicit = array(false);
+	var $xml_lang = array('');
+	var $data = array();
+	var $datas = array(array());
+	var $current_xhtml_construct = -1;
+	var $encoding;
+
+	function parse(&$data, $encoding)
+	{
+		// Use UTF-8 if we get passed US-ASCII, as every US-ASCII character is a UTF-8 character
+		if (strtoupper($encoding) == 'US-ASCII')
+		{
+			$this->encoding = 'UTF-8';
+		}
+		else
+		{
+			$this->encoding = $encoding;
+		}
+
+		// Strip BOM:
+		// UTF-32 Big Endian BOM
+		if (substr($data, 0, 4) === "\x00\x00\xFE\xFF")
+		{
+			$data = substr($data, 4);
+		}
+		// UTF-32 Little Endian BOM
+		elseif (substr($data, 0, 4) === "\xFF\xFE\x00\x00")
+		{
+			$data = substr($data, 4);
+		}
+		// UTF-16 Big Endian BOM
+		elseif (substr($data, 0, 2) === "\xFE\xFF")
+		{
+			$data = substr($data, 2);
+		}
+		// UTF-16 Little Endian BOM
+		elseif (substr($data, 0, 2) === "\xFF\xFE")
+		{
+			$data = substr($data, 2);
+		}
+		// UTF-8 BOM
+		elseif (substr($data, 0, 3) === "\xEF\xBB\xBF")
+		{
+			$data = substr($data, 3);
+		}
+		
+		if (substr($data, 0, 5) === '<?xml' && strspn(substr($data, 5, 1), "\x09\x0A\x0D\x20") && ($pos = strpos($data, '?>')) !== false)
+		{
+			$declaration = new SimplePie_XML_Declaration_Parser(substr($data, 5, $pos - 5));
+			if ($declaration->parse())
+			{
+				$data = substr($data, $pos + 2);
+				$data = '<?xml version="' . $declaration->version . '" encoding="' . $encoding . '" standalone="' . (($declaration->standalone) ? 'yes' : 'no') . '"?>' . $data;
+			}
+			else
+			{
+				$this->error_string = 'SimplePie bug! Please report this!';
+				return false;
+			}
+		}
+		
+		$return = true;
+
+		// Create the parser
+		$xml = xml_parser_create_ns($this->encoding, $this->separator);
+		xml_parser_set_option($xml, XML_OPTION_SKIP_WHITE, 1);
+		xml_parser_set_option($xml, XML_OPTION_CASE_FOLDING, 0);
+		xml_set_object($xml, $this);
+		xml_set_character_data_handler($xml, 'cdata');
+		xml_set_element_handler($xml, 'tag_open', 'tag_close');
+
+		// Parse!
+		if (!xml_parse($xml, $data, true))
+		{
+			$this->error_code = xml_get_error_code($xml);
+			$this->error_string = xml_error_string($this->error_code);
+			$return = false;
+		}
+		$this->current_line = xml_get_current_line_number($xml);
+		$this->current_column = xml_get_current_column_number($xml);
+		$this->current_byte = xml_get_current_byte_index($xml);
+		xml_parser_free($xml);
+		return $return;
+	}
+
+	function get_error_code()
+	{
+		return $this->error_code;
+	}
+
+	function get_error_string()
+	{
+		return $this->error_string;
+	}
+
+	function get_current_line()
+	{
+		return $this->current_line;
+	}
+
+	function get_current_column()
+	{
+		return $this->current_column;
+	}
+
+	function get_current_byte()
+	{
+		return $this->current_byte;
+	}
+
+	function get_data()
+	{
+		return $this->data;
+	}
+
+	function tag_open($parser, $tag, $attributes)
+	{
+		if ($this->feed === 0)
+		{
+			return;
+		}
+		elseif ($this->feed == false)
+		{
+			if (in_array($tag, array(
+				SIMPLEPIE_NAMESPACE_ATOM_10 . $this->separator . 'feed',
+				SIMPLEPIE_NAMESPACE_ATOM_03 . $this->separator . 'feed',
+				'rss',
+				SIMPLEPIE_NAMESPACE_RDF . $this->separator . 'RDF'
+			)))
+			{
+					$this->feed = 1;
+			}
+		}
+		else
+		{
+			$this->feed++;
+		}
+
+		list($this->namespace[], $this->element[]) = $this->split_ns($tag);
+
+		$attribs = array();
+		foreach ($attributes as $name => $value)
+		{
+			list($attrib_namespace, $attribute) = $this->split_ns($name);
+			$attribs[$attrib_namespace][$attribute] = $value;
+		}
+
+		if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['base']))
+		{
+			$this->xml_base[] = SimplePie_Misc::absolutize_url($attribs[SIMPLEPIE_NAMESPACE_XML]['base'], end($this->xml_base));
+			$this->xml_base_explicit[] = true;
+		}
+		else
+		{
+			$this->xml_base[] = end($this->xml_base);
+			$this->xml_base_explicit[] = end($this->xml_base_explicit);
+		}
+
+		if (isset($attribs[SIMPLEPIE_NAMESPACE_XML]['lang']))
+		{
+			$this->xml_lang[] = $attribs[SIMPLEPIE_NAMESPACE_XML]['lang'];
+		}
+		else
+		{
+			$this->xml_lang[] = end($this->xml_lang);
+		}
+
+		if ($this->current_xhtml_construct >= 0)
+		{
+			$this->current_xhtml_construct++;
+			if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML)
+			{
+				$this->data['data'] .= '<' . end($this->element);
+				if (isset($attribs['']))
+				{
+					foreach ($attribs[''] as $name => $value)
+					{
+						$this->data['data'] .= ' ' . $name . '="' . htmlspecialchars($value, ENT_COMPAT, $this->encoding) . '"';
+					}
+				}
+				$this->data['data'] .= '>';
+			}
+		}
+		else
+		{
+			$this->datas[] =& $this->data;
+			$this->data =& $this->data['child'][end($this->namespace)][end($this->element)][];
+			$this->data = array('data' => '', 'attribs' => $attribs, 'xml_base' => end($this->xml_base), 'xml_base_explicit' => end($this->xml_base_explicit), 'xml_lang' => end($this->xml_lang));
+			if ((end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_03 && in_array(end($this->element), array('title', 'tagline', 'copyright', 'info', 'summary', 'content')) && isset($attribs['']['mode']) && $attribs['']['mode'] == 'xml')
+			|| (end($this->namespace) == SIMPLEPIE_NAMESPACE_ATOM_10 && in_array(end($this->element), array('rights', 'subtitle', 'summary', 'info', 'title', 'content')) && isset($attribs['']['type']) && $attribs['']['type'] == 'xhtml'))
+			{
+				$this->current_xhtml_construct = 0;
+			}
+		}
+	}
+
+	function cdata($parser, $cdata)
+	{
+		if ($this->current_xhtml_construct >= 0)
+		{
+			$this->data['data'] .= htmlspecialchars($cdata, ENT_QUOTES, $this->encoding);
+		}
+		elseif ($this->feed > 1)
+		{
+			$this->data['data'] .= $cdata;
+		}
+	}
+
+	function tag_close($parser, $tag)
+	{
+		if (!$this->feed)
+		{
+			return;
+		}
+
+		if ($this->current_xhtml_construct >= 0)
+		{
+			$this->current_xhtml_construct--;
+			if (end($this->namespace) == SIMPLEPIE_NAMESPACE_XHTML && !in_array(end($this->element), array('area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param')))
+			{
+				$this->data['data'] .= '</' . end($this->element) . '>';
+			}
+		}
+		if ($this->current_xhtml_construct == -1)
+		{
+			$this->data =& $this->datas[$this->feed];
+			array_pop($this->datas);
+		}
+
+		array_pop($this->element);
+		array_pop($this->namespace);
+		array_pop($this->xml_base);
+		array_pop($this->xml_base_explicit);
+		array_pop($this->xml_lang);
+		$this->feed--;
+	}
+
+	function split_ns($string)
+	{
+		static $cache = array();
+		if (!isset($cache[$string]))
+		{
+			if ($pos = strpos($string, $this->separator))
+			{
+				static $separator_length;
+				if (!$separator_length)
+				{
+					$separator_length = strlen($this->separator);
+				}
+				$namespace = substr($string, 0, $pos);
+				$local_name = substr($string, $pos + $separator_length);
+				if (strtolower($namespace) === SIMPLEPIE_NAMESPACE_ITUNES)
+				{
+					$namespace = SIMPLEPIE_NAMESPACE_ITUNES;
+				}
+
+				// Normalize the Media RSS namespaces
+				if ($namespace === SIMPLEPIE_NAMESPACE_MEDIARSS_WRONG)
+				{
+					$namespace = SIMPLEPIE_NAMESPACE_MEDIARSS;
+				}
+				$cache[$string] = array($namespace, $local_name);
+			}
+			else
+			{
+				$cache[$string] = array('', $string);
+			}
+		}
+		return $cache[$string];
+	}
+}
+
+/**
+ * @todo Move to using an actual HTML parser (this will allow tags to be properly stripped, and to switch between HTML and XHTML), this will also make it easier to shorten a string while preserving HTML tags
+ */
+class SimplePie_Sanitize
+{
+	// Private vars
+	var $base;
+
+	// Options
+	var $remove_div = true;
+	var $image_handler = '';
+	var $strip_htmltags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style');
+	var $encode_instead_of_strip = false;
+	var $strip_attributes = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc');
+	var $strip_comments = false;
+	var $output_encoding = 'UTF-8';
+	var $enable_cache = true;
+	var $cache_location = './cache';
+	var $cache_name_function = 'md5';
+	var $cache_class = 'SimplePie_Cache';
+	var $file_class = 'SimplePie_File';
+	var $timeout = 10;
+	var $useragent = '';
+	var $force_fsockopen = false;
+
+	var $replace_url_attributes = array(
+		'a' => 'href',
+		'area' => 'href',
+		'blockquote' => 'cite',
+		'del' => 'cite',
+		'form' => 'action',
+		'img' => array('longdesc', 'src'),
+		'input' => 'src',
+		'ins' => 'cite',
+		'q' => 'cite'
+	);
+
+	function remove_div($enable = true)
+	{
+		$this->remove_div = (bool) $enable;
+	}
+
+	function set_image_handler($page = false)
+	{
+		if ($page)
+		{
+			$this->image_handler = (string) $page;
+		}
+		else
+		{
+			$this->image_handler = false;
+		}
+	}
+
+	function pass_cache_data($enable_cache = true, $cache_location = './cache', $cache_name_function = 'md5', $cache_class = 'SimplePie_Cache')
+	{
+		if (isset($enable_cache))
+		{
+			$this->enable_cache = (bool) $enable_cache;
+		}
+
+		if ($cache_location)
+		{
+			$this->cache_location = (string) $cache_location;
+		}
+
+		if ($cache_name_function)
+		{
+			$this->cache_name_function = (string) $cache_name_function;
+		}
+
+		if ($cache_class)
+		{
+			$this->cache_class = (string) $cache_class;
+		}
+	}
+
+	function pass_file_data($file_class = 'SimplePie_File', $timeout = 10, $useragent = '', $force_fsockopen = false)
+	{
+		if ($file_class)
+		{
+			$this->file_class = (string) $file_class;
+		}
+
+		if ($timeout)
+		{
+			$this->timeout = (string) $timeout;
+		}
+
+		if ($useragent)
+		{
+			$this->useragent = (string) $useragent;
+		}
+
+		if ($force_fsockopen)
+		{
+			$this->force_fsockopen = (string) $force_fsockopen;
+		}
+	}
+
+	function strip_htmltags($tags = array('base', 'blink', 'body', 'doctype', 'embed', 'font', 'form', 'frame', 'frameset', 'html', 'iframe', 'input', 'marquee', 'meta', 'noscript', 'object', 'param', 'script', 'style'))
+	{
+		if ($tags)
+		{
+			if (is_array($tags))
+			{
+				$this->strip_htmltags = $tags;
+			}
+			else
+			{
+				$this->strip_htmltags = explode(',', $tags);
+			}
+		}
+		else
+		{
+			$this->strip_htmltags = false;
+		}
+	}
+
+	function encode_instead_of_strip($encode = false)
+	{
+		$this->encode_instead_of_strip = (bool) $encode;
+	}
+
+	function strip_attributes($attribs = array('bgsound', 'class', 'expr', 'id', 'style', 'onclick', 'onerror', 'onfinish', 'onmouseover', 'onmouseout', 'onfocus', 'onblur', 'lowsrc', 'dynsrc'))
+	{
+		if ($attribs)
+		{
+			if (is_array($attribs))
+			{
+				$this->strip_attributes = $attribs;
+			}
+			else
+			{
+				$this->strip_attributes = explode(',', $attribs);
+			}
+		}
+		else
+		{
+			$this->strip_attributes = false;
+		}
+	}
+
+	function strip_comments($strip = false)
+	{
+		$this->strip_comments = (bool) $strip;
+	}
+
+	function set_output_encoding($encoding = 'UTF-8')
+	{
+		$this->output_encoding = (string) $encoding;
+	}
+
+	/**
+	 * Set element/attribute key/value pairs of HTML attributes
+	 * containing URLs that need to be resolved relative to the feed
+	 *
+	 * @access public
+	 * @since 1.0
+	 * @param array $element_attribute Element/attribute key/value pairs
+	 */
+	function set_url_replacements($element_attribute = array('a' => 'href', 'area' => 'href', 'blockquote' => 'cite', 'del' => 'cite', 'form' => 'action', 'img' => array('longdesc', 'src'), 'input' => 'src', 'ins' => 'cite', 'q' => 'cite'))
+	{
+		$this->replace_url_attributes = (array) $element_attribute;
+	}
+
+	function sanitize($data, $type, $base = '')
+	{
+		$data = trim($data);
+		if ($data !== '' || $type & SIMPLEPIE_CONSTRUCT_IRI)
+		{
+			if ($type & SIMPLEPIE_CONSTRUCT_MAYBE_HTML)
+			{
+				if (preg_match('/(&(#(x[0-9a-fA-F]+|[0-9]+)|[a-zA-Z0-9]+)|<\/[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>)/', $data))
+				{
+					$type |= SIMPLEPIE_CONSTRUCT_HTML;
+				}
+				else
+				{
+					$type |= SIMPLEPIE_CONSTRUCT_TEXT;
+				}
+			}
+
+			if ($type & SIMPLEPIE_CONSTRUCT_BASE64)
+			{
+				$data = base64_decode($data);
+			}
+
+			if ($type & SIMPLEPIE_CONSTRUCT_XHTML)
+			{
+				if ($this->remove_div)
+				{
+					$data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '', $data);
+					$data = preg_replace('/<\/div>$/', '', $data);
+				}
+				else
+				{
+					$data = preg_replace('/^<div' . SIMPLEPIE_PCRE_XML_ATTRIBUTE . '>/', '<div>', $data);
+				}
+			}
+
+			if ($type & (SIMPLEPIE_CONSTRUCT_HTML | SIMPLEPIE_CONSTRUCT_XHTML))
+			{
+				// Strip comments
+				if ($this->strip_comments)
+				{
+					$data = SimplePie_Misc::strip_comments($data);
+				}
+
+				// Strip out HTML tags and attributes that might cause various security problems.
+				// Based on recommendations by Mark Pilgrim at:
+				// http://diveintomark.org/archives/2003/06/12/how_to_consume_rss_safely
+				if ($this->strip_htmltags)
+				{
+					foreach ($this->strip_htmltags as $tag)
+					{
+						$pcre = "/<($tag)" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . "(>(.*)<\/$tag" . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>|(\/)?>)/siU';
+						while (preg_match($pcre, $data))
+						{
+							$data = preg_replace_callback($pcre, array(&$this, 'do_strip_htmltags'), $data);
+						}
+					}
+				}
+
+				if ($this->strip_attributes)
+				{
+					foreach ($this->strip_attributes as $attrib)
+					{
+						$data = preg_replace('/(<[A-Za-z][^\x09\x0A\x0B\x0C\x0D\x20\x2F\x3E]*)' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . trim($attrib) . '(?:\s*=\s*(?:"(?:[^"]*)"|\'(?:[^\']*)\'|(?:[^\x09\x0A\x0B\x0C\x0D\x20\x22\x27\x3E][^\x09\x0A\x0B\x0C\x0D\x20\x3E]*)?))?' . SIMPLEPIE_PCRE_HTML_ATTRIBUTE . '>/', '\1\2\3>', $data);
+					}
+				}
+
+				// Replace relative URLs
+				$this->base = $base;
+				foreach ($this->replace_url_attributes as $element => $attributes)
+				{
+					$data = $this->replace_urls($data, $element, $attributes);
+				}
+
+				// If image handling (caching, etc.) is enabled, cache and rewrite all the image tags.
+				if (isset($this->image_handler) && ((string) $this->image_handler) !== '' && $this->enable_cache)
+				{
+					$images = SimplePie_Misc::get_element('img', $data);
+					foreach ($images as $img)
+					{
+						if (isset($img['attribs']['src']['data']))
+						{
+							$image_url = call_user_func($this->cache_name_function, $img['attribs']['src']['data']);
+							$cache = call_user_func(array($this->cache_class, 'create'), $this->cache_location, $image_url, 'spi');
+
+							if ($cache->load())
+							{
+								$img['attribs']['src']['data'] = $this->image_handler . $image_url;
+								$data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
+							}
+							else
+							{
+								$file =& new $this->file_class($img['attribs']['src']['data'], $this->timeout, 5, array('X-FORWARDED-FOR' => $_SERVER['REMOTE_ADDR']), $this->useragent, $this->force_fsockopen);
+								$headers = $file->headers;
+
+								if ($file->success && ($file->status_code == 200 || ($file->status_code > 206 && $file->status_code < 300)))
+								{
+									if ($cache->save(array('headers' => $file->headers, 'body' => $file->body)))
+									{
+										$img['attribs']['src']['data'] = $this->image_handler . $image_url;
+										$data = str_replace($img['full'], SimplePie_Misc::element_implode($img), $data);
+									}
+									else
+									{
+										trigger_error("$cache->name is not writeable", E_USER_WARNING);
+									}
+								}
+							}
+						}
+					}
+				}
+
+				// Having (possibly) taken stuff out, there may now be whitespace at the beginning/end of the data
+				$data = trim($data);
+			}
+
+			if ($type & SIMPLEPIE_CONSTRUCT_IRI)
+			{
+				$data = SimplePie_Misc::absolutize_url($data, $base);
+			}
+
+			if ($type & (SIMPLEPIE_CONSTRUCT_TEXT | SIMPLEPIE_CONSTRUCT_IRI))
+			{
+				$data = htmlspecialchars($data, ENT_COMPAT, 'UTF-8');
+			}
+
+			if ($this->output_encoding != 'UTF-8')
+			{
+				$data = SimplePie_Misc::change_encoding($data, 'UTF-8', $this->output_encoding);
+			}
+		}
+		return $data;
+	}
+
+	function replace_urls($data, $tag, $attributes)
+	{
+		if (!is_array($this->strip_htmltags) || !in_array($tag, $this->strip_htmltags))
+		{
+			$elements = SimplePie_Misc::get_element($tag, $data);
+			foreach ($elements as $element)
+			{
+				if (is_array($attributes))
+				{
+					foreach ($attributes as $attribute)
+					{
+						if (isset($element['attribs'][$attribute]['data']))
+						{
+							$element['attribs'][$attribute]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attribute]['data'], $this->base);
+							$new_element = SimplePie_Misc::element_implode($element);
+							$data = str_replace($element['full'], $new_element, $data);
+							$element['full'] = $new_element;
+						}
+					}
+				}
+				elseif (isset($element['attribs'][$attributes]['data']))
+				{
+					$element['attribs'][$attributes]['data'] = SimplePie_Misc::absolutize_url($element['attribs'][$attributes]['data'], $this->base);
+					$data = str_replace($element['full'], SimplePie_Misc::element_implode($element), $data);
+				}
+			}
+		}
+		return $data;
+	}
+
+	function do_strip_htmltags($match)
+	{
+		if ($this->encode_instead_of_strip)
+		{
+			if (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
+			{
+				$match[1] = htmlspecialchars($match[1], ENT_COMPAT, 'UTF-8');
+				$match[2] = htmlspecialchars($match[2], ENT_COMPAT, 'UTF-8');
+				return "&lt;$match[1]$match[2]&gt;$match[3]&lt;/$match[1]&gt;";
+			}
+			else
+			{
+				return htmlspecialchars($match[0], ENT_COMPAT, 'UTF-8');
+			}
+		}
+		elseif (isset($match[4]) && !in_array(strtolower($match[1]), array('script', 'style')))
+		{
+			return $match[4];
+		}
+		else
+		{
+			return '';
+		}
+	}
+}
+
+?>
Index: /trunk/seguranca/vercert.php
===================================================================
--- /trunk/seguranca/vercert.php	(revision 1035)
+++ /trunk/seguranca/vercert.php	(revision 1035)
@@ -0,0 +1,240 @@
+<?php
+function item_para_uid($dados_do_certificado)
+	{
+/*
+// Exemplo do Array $dados_do_certificado padrao ICP-BRASIL
+// O conteudo do array pode variar conforme a AC emissora.
+Array
+(
+    [SERIALNUMBER] => 2009031816232802
+    [EMISSOR_CAMINHO_COMPLETO] => Array
+        (
+            [C] => BR
+            [O] => ICP-Brasil
+            [OU] => CSPB-1
+            [CN] => HOMAutoridade Certificadora do SERPRO Final v2
+        )
+
+    [EMISSOR] => HOMAutoridade Certificadora do SERPRO Final v2
+    [INICIO_VALIDADE] => 20090318205216
+    [FIM_VALIDADE] => 20120317205216
+    [EXPIRADO] => 
+    [SUBJECT] => Array
+        (
+            [C] => BR
+            [O] => ICP-Brasil
+            [OU] => Pessoa Fisica A3
+            [CN] => CESAR VIANNA
+        )
+
+    [NOME] => CESAR VIANNA
+    [AUTHORITYKEYIDENTIFIER] => AE34F397BB05B1AA6CC3FD6C4F0E9129BBB61BE2
+    [KEYUSAGE] => Array
+        (
+            [digitalSignature] => 1
+            [nonRepudiation] => 1
+            [keyEncipherment] => 1
+        )
+
+    [EXTKEYUSAGE] => Array
+        (
+            [clientAuth] => 1.3.6.1.5.5.7.3.2
+            [emailProtection] => 1.3.6.1.5.5.7.3.4
+        )
+
+    [CA] => 
+    [CRLDISTRIBUTIONPOINTS] => Array
+        (
+            [0] => http://ccdhom.serpro.gov.br/lcr/serproacfv2.crl
+            [1] => http://ccdhom.serpro.gov.br/lcr/serproacfv3.crl
+            [2] => http://ccdhom.serpro.gov.br/lcr/serproacfv4.crl
+        )
+
+    [2.16.76.1.3.6] => Array
+        (
+            [CADINSS] => 000000000000
+        )
+
+    [CADINSS] => 000000000000
+    [2.16.76.1.3.5] => Array
+        (
+            [TITULO] => 000000000000
+            [ZONA] => 000
+            [SECAO] => 0000
+            [TITULO_CIDADE_UF] => 
+        )
+
+    [TITULO] => 000000000000
+    [ZONA] => 000
+    [SECAO] => 0000
+    [TITULO_CIDADE_UF] => 
+    [2.16.76.1.3.1] => Array
+        (
+            [NASCIMENTO] => 19081981
+            [CPF] => 12345678902
+            [NIS] => 12345678901
+            [RG] => 000201075150953
+            [ORGAOUF] => SSPRS
+        )
+
+    [NASCIMENTO] => 19081981
+    [CPF] =>  12345678902
+    [NIS] => 12345678901
+    [RG] => 000201075150953
+    [ORGAOUF] => SSPRS
+    [EMAIL] => cesar.vianna@pr.planalto.gov.br
+)
+*/	
+	
+		// Retorna o CPF para usar como uid.
+		return $dados_do_certificado['2.16.76.1.3.1']['CPF'];
+	}
+	
+	
+$GLOBALS['phpgw_info']['flags'] = array(
+		'disable_Template_class' => True,
+		'login'                  => True,
+		'currentapp'             => 'login',
+		'noheader'               => True
+	);
+
+if(!$_REQUEST['certificado'])
+{
+   echo '2'.chr(0x0D).chr(0x0A).'Certificado não foi apresentado.';
+   exit();
+}
+
+if(file_exists('../header.inc.php'))
+	{
+		include('../header.inc.php');
+	}
+else
+	{
+	        echo '1'.chr(0x0D).chr(0x0A).'Arquivo header.inc.php n&atilde;o foi localizado.';
+		exit();    
+	}
+    
+$ldap_context = $GLOBALS['phpgw_info']['server']['ldap_context'];
+$ldap_servidor = $GLOBALS['phpgw_info']['server']['ldap_host'];
+$ldap_dn = $GLOBALS['phpgw_info']['server']['ldap_root_dn'];
+$ldap_passwd = $GLOBALS['phpgw_info']['server']['ldap_root_pw'];
+
+require_once('classes/CertificadoB.php');
+require_once('classes/Verifica_Certificado.php');
+include('classes/Verifica_Certificado_conf.php');
+
+  # Transforma o certificado do formato PEM para o formato DER ...
+  function troca_espaco_por_mais($pem_data) 
+  {
+    $begin = "CERTIFICATE-----";
+    $end   = "-----END";
+    $aux = substr($pem_data, strpos($pem_data, $begin)+strlen($begin));    
+    $aux = substr($aux, 0, strpos($aux, $end));
+    $aux = strtr($aux,' ','+');
+    $aux = '-----BEGIN CERTIFICATE-----'.$aux.'-----END CERTIFICATE-----';
+    return $aux;
+   }
+ 
+
+$cert =str_replace(chr(0x0A).chr(0x0A),chr(0x0A),$_REQUEST['certificado']);
+$cert = troca_espaco_por_mais($cert);
+
+$c = new certificadoB();
+$c->certificado($cert);
+
+if (!$c->apresentado)
+{
+   echo '2'.chr(0x0D).chr(0x0A).'Certificado não foi apresentado.';
+   exit();
+}
+
+if (!$c->dados['CPF'])
+{
+   echo '2'.chr(0x0D).chr(0x0A).'Não foi possível obter o CPF do certificado apresentado.';
+   exit();
+}
+
+$b = new Verifica_Certificado($c->dados,$cert);
+
+// Testa se Certificado OK.
+if(!$b->status)
+{
+   $msg = '3'.chr(0x0D).chr(0x0A).$b->msgerro;
+
+   foreach($b->erros_ssl  as $linha)
+   {
+	$msg .= "\n" . $linha;
+   }
+
+   echo $msg;
+   exit();   
+}
+
+    $cc=ldap_connect($ldap_servidor); 
+
+    //  bind ..
+    $sr=ldap_bind($cc,$ldap_dn,$ldap_passwd);  
+
+    $filtro = 'uid='. item_para_uid($c->dados);
+
+    // Pesquisa CPF no RHDS/LDAP
+    $sr=ldap_search($cc, $ldap_context,$filtro);  
+
+    // Pega resultado ....
+    $info = ldap_get_entries($cc, $sr);
+  
+    // Tem de achar só uma entrada.....ao menos uma....
+    if($info["count"]!=1)
+    {
+	echo '4'.chr(0x0D).chr(0x0A).'Dados inválidos no diretório de usuários';	
+	ldap_close($cc);
+	exit();
+    }
+
+// A conta expresso tem de estar ativa....
+if($info[0]['phpgwaccountstatus'][0]!='A')
+    {
+	echo '5'.chr(0x0D).chr(0x0A).'Conta do usuario nao esta ativa no Expresso.';
+	ldap_close($cc);
+	exit();
+    }
+
+if($info[0]["cryptpassword"][0] && $info[0]["usercertificate"][0] && $cert == $info[0]["usercertificate"][0] )
+    {
+	echo '0'.chr(0x0D).chr(0x0A).$info[0]["uid"][0].chr(0x0D).chr(0x0A).$info[0]["cryptpassword"][0];
+	//echo '0' . "\n" . $info[0]["uid"][0] . "\n" . $info[0]["cryptpassword"][0];
+    }
+else
+    {
+        if(!$info[0]["usercertificate"][0] || $cert != $info[0]["usercertificate"][0])
+		{
+			$user_info = array();
+			$aux1 = $info[0]["dn"];
+			$user_info['usercertificate'] = $cert;
+			 if(isset($GLOBALS['phpgw_info']['server']['atributoexpiracao']))
+				{
+					if(substr($ldap_info['atributoexpiracao'],-1,1)=="Z")
+						{
+							###quando a data de expiracao estah no formato yyyymmddhhmmssZ
+							$user_info[$GLOBALS['phpgw_info']['server']['atributoexpiracao']] = '19800101000000Z';
+						}
+					else
+						{
+							###Outro atributo ldap que, assim como o phpgwaccounttype, tambem contem hora em formato unix
+							$user_info[$GLOBALS['phpgw_info']['server']['atributoexpiracao']] = '0';
+						}
+				}
+			else
+				{
+					$user_info['phpgwaccountexpires'] = '0';
+				}
+			ldap_modify($cc,$aux1,$user_info);
+			echo '6'.chr(0x0D).chr(0x0A).'Seu Certificado foi cadastrado. Sua senha foi expirada. Altere sua senha para concluir o processo.';
+		}
+	else
+		{
+			echo '6'.chr(0x0D).chr(0x0A).'Sua senha foi expirada. Altere sua senha para acessar o Expresso usando certificado digital.';
+		}
+    }
+ldap_close($cc);
+?>
Index: /trunk/seguranca/security_admin.php
===================================================================
--- /trunk/seguranca/security_admin.php	(revision 1035)
+++ /trunk/seguranca/security_admin.php	(revision 1035)
@@ -0,0 +1,16 @@
+<?php
+
+	$GLOBALS['phpgw_info'] = array();
+	$GLOBALS['phpgw_info']['flags']['currentapp'] = 'admin';
+	include('../header.inc.php');
+	$GLOBALS['phpgw_info']['flags']['app_header'] = lang('Admin') .' - ' . lang('CAs/CRLs Configuration ');
+
+        if (file_exists('security.php'))
+	  {
+	       include('security.php');
+	  }
+	else
+	  {
+	       echo '<div><h4>Dados para administra&ccedil;&atilde;o das CA\'s e CRL\'s n&atilde;o foram localizados.</h4></div>';
+	  }
+?>
Index: /trunk/seguranca/cas/todos.cer
===================================================================
--- /trunk/seguranca/cas/todos.cer	(revision 1035)
+++ /trunk/seguranca/cas/todos.cer	(revision 1035)
@@ -0,0 +1,672 @@
+-----BEGIN CERTIFICATE-----
+MIIEuDCCA6CgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wMTExMzAxMjU4MDBaFw0xMTExMzAy
+MzU5MDBaMIG0MQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG
+A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt
+YWNhbyAtIElUSTERMA8GA1UEBxMIQnJhc2lsaWExCzAJBgNVBAgTAkRGMTEwLwYD
+VQQDEyhBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwPMudwX/hvm+Uh2b/lQAcHVA
+isamaLkWdkwP9/S/tOKIgRrL6Oy+ZIGlOUdd6uYtk9Ma/3pUpgcfNAj0vYm5gsyj
+Qo9emsc+x6m4VWwk9iqMZSCK5EQkAq/Ut4n7KuLE1+gdftwdIgxfUsPt4CyNrY50
+QV57KM2UT8x5rrmzEjr7TICGpSUAl2gVqe6xaii+bmYR1QrmWaBSAG59LrkrjrYt
+bRhFboUDe1DK+6T8s5L6k8c8okpbHpa9veMztDVC9sPJ60MWXh6anVKo1UcLcbUR
+yEeNvZneVRKAAU6ouwdjDvwlsaKydFKwed0ToQ47bmUKgcm+wV3eTRk36UOnTwID
+AQABo4HSMIHPME4GA1UdIARHMEUwQwYFYEwBAQAwOjA4BggrBgEFBQcCARYsaHR0
+cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0RQQ2FjcmFpei5wZGYwPQYDVR0f
+BDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFj
+cmFpei5jcmwwHQYDVR0OBBYEFIr68VeEERM1kEL6V0lUaQ2kxPA3MA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAZA5c1
+U/hgIh6OcgLAfiJgFWpvmDZWqlV30/bHFpj8iBobJSm5uDpt7TirYh1Uxe3fQaGl
+YjJe+9zd+izPRbBqXPVQA34EXcwk4qpWuf1hHriWfdrx8AcqSqr6CuQFwSr75Fos
+SzlwDADa70mT7wZjAmQhnZx2xJ6wfWlT9VQfS//JYeIc7Fue2JNLd00UOSMMaiK/
+t79enKNHEA2fupH3vEigf5Eh4bVAN5VohrTm6MY53x7XQZZr1ME7a55lFEnSeT0u
+mlOAjR2mAbvSM5X5oSZNrmetdzyTj2flCM8CC7MLab0kkdngRIlUBGHF1/S5nmPb
+K+9A46sd33oqK8n8
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEeDCCA2CgAwIBAgIBEzANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wNTAzMjQyMDAxMDBaFw0xMTEwMjQy
+MzU5MDBaMIGPMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE7MDkG
+A1UECxMyU2VydmljbyBGZWRlcmFsIGRlIFByb2Nlc3NhbWVudG8gZGUgRGFkb3Mg
+LSBTRVJQUk8xLjAsBgNVBAMTJUF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBkbyBT
+RVJQUk8gdjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0WxXnyzz5
+J03+aBrPJ5AIoCYhdp8W3fMneH7l4jwMDiF9C8/bsgDYUc6hGC3l1PVwuYf/VGwB
+p6kYPaJX/W88Tm/4Vq66yYUIsa7q8yq90CD387rbaCu8qbGEIrOV18Fp63ohLPI0
+24FoNBI4WwlRb6aktVOkSBr0UeIAc2x4vjJWpSzvCg2eyRQyOz9nKVLwQJLkYk1f
+hac/aoj18ksK8zKQieHtls2fW51p4DI4jaM42kHHxV9eJCml4wbrNiTy+1NSi/VX
+JAXWCGcNoHM5hmkCDbfQB2aWrZDLjJ8RS0E32ilT3A30DqdkOIhKgbmjfQuBTZWJ
+8ZA+msEYaOl5AgMA05ejgbcwgbQwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Fj
+cmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFjcmFpei5jcmwwEgYDVR0gBAswCTAH
+BgVgTAEBAjAdBgNVHQ4EFgQU4osVQdt1OSm8HFR7+1E/FAkS8rQwHwYDVR0jBBgw
+FoAUivrxV4QREzWQQvpXSVRpDaTE8DcwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
+/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAGJSHMCH3re9mCmtnVH+btonLi8M
+EJgtYDwwOkLvknnwI+0WimHsFDM7ABcaKw4N5OZwAlcSFla4i1vbFjools4HD4z+
+fMwbHIhifTNLQKW49Dm+XqnBIe/UIbNXfDdQmKk770WhsljALMC53k/phxPxHN3y
+qrD06YwDaQKLbuAO800ycCUeIvvxB698oSdrC/m2jf+Wt6NZMybqw7Tp2qBR+c/v
+CZW1g6Qbij5lOm2ADrpXpjiDKnmsUmff9uvByix2mbTHRNa9E+eeev7ZN+PpSLhZ
+5x8xKisZxBXdBL+2aeGaNa81sWculWLam3DI6bARrzAtRrI0cVev2kkSWks=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFdzCCBF+gAwIBAgISMjAwNTA0MDQxNTUwNTYwMDAxMA0GCSqGSIb3DQEBBQUA
+MIGPMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE7MDkGA1UECxMy
+U2VydmljbyBGZWRlcmFsIGRlIFByb2Nlc3NhbWVudG8gZGUgRGFkb3MgLSBTRVJQ
+Uk8xLjAsBgNVBAMTJUF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBkbyBTRVJQUk8g
+djEwHhcNMDUwNDA0MTYyNjU5WhcNMTExMDI0MjM1OTAwWjCBpjELMAkGA1UEBhMC
+QlIxEzARBgNVBAoTCklDUC1CcmFzaWwxOzA5BgNVBAsTMlNlcnZpY28gRmVkZXJh
+bCBkZSBQcm9jZXNzYW1lbnRvIGRlIERhZG9zIC0gU0VSUFJPMQ8wDQYDVQQLEwZD
+U1BCLTExNDAyBgNVBAMTK0F1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBkbyBTRVJQ
+Uk8gRmluYWwgdjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7axUl
+Kt/w/tTlxreEIOPdewTpE73tZD7G+pABsmGsND+wkhXdsE8u9muZz2QgUC0FNQnz
+BtxEfIVFIQtS6RVQ2y4oF8FkpnSdamxFXfd3UfxY5IADM3e7GzLxevLtNd2CfB34
+41inYkkbcF1x37zGDktKWimOutXBIeKhADY/xkLP1rb1ud8hfxwmlZvR7kERtq1+
+3ha54R3MH3lvGjvXUdWrJ7cyqhGhuBRPOQTMLABoTvp1/6tVkDeq+xqoh8qxB+bw
+MKlLmhdz/IGJzajO7rqkqiFi+hV6ULFGYna8aAoxYMXwGY5CaY0+vmZiVgWHVc+o
+F/y1E4T23N06EhDHAgMA5fGjggGyMIIBrjASBgNVHRMBAf8ECDAGAQH/AgEAMCIG
+A1UdIwEBAAQYMBaAFOKLFUHbdTkpvBxUe/tRPxQJEvK0MCAGA1UdDgEBAAQWBBQy
+OJbH7kRk6ZqqFV3gCLSNiUdRojAOBgNVHQ8BAf8EBAMCAQYwggEBBgNVHSABAQAE
+gfYwgfMwTwYGYEwBAgEQMEUwQwYIKwYBBQUHAgEWN2h0dHBzOi8vY2NkLnNlcnBy
+by5nb3YuYnIvYWNzZXJwcm8vZG9jcy9kcGNhY3NlcnByby5wZGYwTwYGYEwBAgMN
+MEUwQwYIKwYBBQUHAgEWN2h0dHBzOi8vY2NkLnNlcnByby5nb3YuYnIvYWNzZXJw
+cm8vZG9jcy9kcGNhY3NlcnByby5wZGYwTwYGYEwBAgERMEUwQwYIKwYBBQUHAgEW
+N2h0dHBzOi8vY2NkLnNlcnByby5nb3YuYnIvYWNzZXJwcm8vZG9jcy9kcGNhY3Nl
+cnByby5wZGYwPQYDVR0fAQEABDMwMTAvoC2gK4YpaHR0cDovL2NjZC5zZXJwcm8u
+Z292LmJyL2xjci9hY3NlcnByby5jcmwwDQYJKoZIhvcNAQEFBQADggEBACDVTheR
+VBDVPIygP/NdI/sDg8iSWRNY4do3PraFAPL1wl4n3sbdMPH4jcvf4HlCUuiKnMA5
+QGfiMhkFD8OKYnxE2KscApC/Sg2FidkoPBlq9eH2QVmkxNDZ9ZlMoZgQ1Wlq4yoH
+Rwsi24Vv8J6xnf+ebUu6RM3BCYN4YwgyQCqCxKjhAKMwcthPgDdjZFTrMzvvCN5O
+lf1tYZAFR7J7ZBK56JfpIBctoR5nJSkU+hHGUFNG7erySLvXmDzF582Wgg11aj5R
+XEN/q9YdPvUbGRFU+aQqVuWELpS7Kj6Otwi9Ai+Fi5OVWaRYofuhPpvWXjLv+RvI
+cHed5wX+WP7pfSw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEjDCCA3SgAwIBAgIBGDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wNjA5MjAxODM5MDBaFw0xMTA5MjAy
+MzU5MDBaMIGjMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE9MDsG
+A1UECxM0SW5zdGl0dXRvIE5hY2lvbmFsIGRlIFRlY25vbG9naWEgZGEgSW5mb3Jt
+YWNhbyAtIElUSTFAMD4GA1UEAxM3QXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIGRh
+IFByZXNpZGVuY2lhIGRhIFJlcHVibGljYSB2MTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBANdjRqQ+eeeyu3tHVrgNIqQ4I8TcxbJPDfr5t9t6skPHFGFj
+m6rgXIejtmtN83NFmGhLIB2FZIejEkg0kHv2akuoz1qBTTt5BNj5lyHQBVobrH3V
+BTqyUfXRLCnykca6lUugk5H2LjqeA0knsSopu9QHKwgy9i//MBK7mdU47VHQaJa8
+ONM1OC5MurfcmhVAIu3FaYTaOyRhukvoVMta1G46bXARkgN6wYIBZHqIQGUZHM3D
++BsaK59p1cnDo2/kH4LSPpEcrFkk/zbQPzsuebbRIARZLWviIubw4B8St5gTUh/m
+2H/olIbJylzq+X4OMiThz1XmBzNueMlp7ClzYA0CAwDH16OBtzCBtDA9BgNVHR8E
+NjA0MDKgMKAuhixodHRwOi8vYWNyYWl6LmljcGJyYXNpbC5nb3YuYnIvTENSYWNy
+YWl6LmNybDASBgNVHSAECzAJMAcGBWBMAQEBMB0GA1UdDgQWBBS+3nlKjQejae0L
+vkXEPu3VxOup8jAfBgNVHSMEGDAWgBSK+vFXhBETNZBC+ldJVGkNpMTwNzAOBgNV
+HQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEA
+Nmqku7VHja7/TQkGJvY7EqMfDdKaVhFq4XVAdkedEjOIcMxg7/1lgtlgbZK0ttYu
+KAJ+ODxJGjNozfinNdebq/vQg11SMCn+AmFHWqMWjNhmLjCdfPjGPavzJmlOlWTg
+0xTo53Kd6G8mAk86rhEz+5tAUWwmBVdDpXqeowk/YJ08M/XwMZpXxIj8RjWwd/Ma
+HPysCZBmkOk8iK1kP+hZOTZUWOAs98LGN9O+PY7svclXQ+6LfZ+JXJXweLtm3Yf9
+/P4MHYLeiCjV/dUN0ygKrdUIbxR1ouxRZ0UShO1ZJQ0ZgC61S5mIoCMpBKlXVk0h
+U7g2qUogTG1hnVvP32Rjkw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIBBDANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMTK0F1
+dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjEwHhcNMDgx
+MDEzMTg0ODE3WhcNMTgxMDEzMTg0ODE3WjBkMQswCQYDVQQGEwJCUjETMBEGA1UE
+ChMKSUNQLUJyYXNpbDFAMD4GA1UEAxM3QXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3Jh
+IGRhIFByZXNpZGVuY2lhIGRhIFJlcHVibGljYSB2MjCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBANfQ/zMCWuG5O0ID19fjM/agsThhHiMlm/wriB/9rIIk
+UIn6pHXgMx/ADYOWQsXfJaa3d7VjIC8U48N7qWJDgHM4ZB8nZyEynMRkiFlGK7bC
+iSqlgrUx84SDbExIPeFgxnjhxuog2bAqcNz0b1sSx66wEEvtrb4afAlvZ+ht92Fk
+j4thQcvYfm4S4KawdaTP6P0OZ6KXIvUs+pBQW8MXBV9JmpEYY1aa65Qa4uQn4a7Q
+jPwJ/fk5Dka10VlSNwYu8Nfvp3kO8fM6+4+o0zRXFU72jAeGQ9zwlr3wjQ66QNdY
+3SaSi0LUkqJjc+66GXfOq6So/SHP/v/SDsiqpnOyMl8CAwC4J6OBpTCBojAOBgNV
+HQ8BAf8EBAMCAQYwPwYDVR0fBDgwNjA0oDKgMIYuaHR0cDovL2FjcmFpei5pY3Bi
+cmFzaWwuZ292LmJyL0xDUmFjcmFpenYxLmNybDAfBgNVHSMEGDAWgBRCsixcdAEH
+vpv/VTM77im7XZG/BjAdBgNVHQ4EFgQUNb96TUft5yGIzSaFOuCfUZSDaGMwDwYD
+VR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAUeQIKToPUWYHWfLmO1Er
+zlmbH6CYW9JUSlgxz8L/bbnfFuyl+G2siCPhXonCeczBd2P9/akdH40iqVdEAvWl
+DPmyLgkzwR7jxnL2kBCJ228Ap5G8M8E39DvYmYTYGakZaJCrwa5PqZOIzzOtuua0
+X+DRFzz4p+TjU22h159iCE7AIfKROXUBELLW3z1psWjRQtteZiDKzGLsth5fRhJl
+0nkLfcyMVGpneSLkhrfp3Ip38I1GNz/S4EyHzZMFut1JGRBFZwa1s1YHWFEhs0rO
+aybq6AenUjXSyCocajlAk1okyWtQjTyA+PlQtEZUm6kZeFrM1+MuCMQf2RWGwgnj
+XQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEgDCCA2igAwIBAgIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMTK0F1
+dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjEwHhcNMDgw
+NzI5MTkxNzEwWhcNMjEwNzI5MTkxNzEwWjCBlzELMAkGA1UEBhMCQlIxEzARBgNV
+BAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25hbCBkZSBU
+ZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMTK0F1dG9yaWRh
+ZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDOHOi+kzTOybHkVO4J9uykCIWgP8aKxnAwp4CM
+7T4BVAeMGSM7n7vHtIsgseL3QRYtXodmurAH3W/RPzzayFkznRWwn5LIVlRYijon
+ojQem3i1t83lm+nALhKecHgH+o7yTMD45XJ8HqmpYANXJkfbg3bDzsgSu9H/766z
+Yn2aoOS8bn0BLjRg3IfgX38FcFwwFSzCdaM/UANmI2Ys53R3eNtmF9/5Hw2CaI91
+h/fpMXpTT89YYrtAojTPwHCEUJcV2iBL6ftMQq0raI6j2a0FYv4IdMTowcyFE86t
+KDBQ3d7AgcFJsF4uJjjpYwQzd7WAds0qf/I8rF2TQjn0onNFAgMBAAGjgdQwgdEw
+TgYDVR0gBEcwRTBDBgVgTAEBADA6MDgGCCsGAQUFBwIBFixodHRwOi8vYWNyYWl6
+LmljcGJyYXNpbC5nb3YuYnIvRFBDYWNyYWl6LnBkZjA/BgNVHR8EODA2MDSgMqAw
+hi5odHRwOi8vYWNyYWl6LmljcGJyYXNpbC5nb3YuYnIvTENSYWNyYWl6djEuY3Js
+MB0GA1UdDgQWBBRCsixcdAEHvpv/VTM77im7XZG/BjAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAWWyKdukZcVeD/qf0
+eg+egdDPBxwMI+kkDVHLM+gqCcN6/w6jgIZgwXCX4MAKVd2kZUyPp0ewV7fzq8TD
+GeOY7A2wG1GRydkJ1ulqs+cMsLKSh/uOTRXsEhQZeAxi6hQ5GArFVdtThdx7KPoV
+caPKdCWCD2cnNNeuUhMC+8XvmoAlpVKeOQ7tOvR4B1/VKHoKSvXQw2f3jFgXbwoA
+oyYQtGAiOkpIpdrgqYTeQ9ufQ6c/KARHki/352R1IdJPgc6qPmQO4w6tVZp+lJs0
+wdCuaU4eo9mzh1facMJafYfN+b833u1WNfe3Ig5Pkrg/CN+cnphe8m+5+pss+M1F
+2HKyIA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBFDANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wNTA2MzAxNDA5MDBaFw0xMTEwMzAy
+MzU5MDBaMFcxCzAJBgNVBAYTAmJyMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSAwHgYD
+VQQLExdDYWl4YSBFY29ub21pY2EgRmVkZXJhbDERMA8GA1UEAxMIQUMgQ0FJWEEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXx2dOOF3Pt4yaK5F6yhmM
+72DRUrBdPGOALpIpzLcKk7XZ8myuFMVxHEkQV6DTpGwooUjhsFTqGH9Cb4rixj9j
+mh4Rek9K+rHvxwTHBN94GJ1AP65s/ytucTSvldACimqNPAg/htj5MOTwKiTl0Hnf
+5yjE1GxAcaOquwz6siyYUZ/msDGCVJGdAepfXwjdZo3AoqTZ/VHWahvHKyVUvxF6
+q6gCLFpor259LB9vGBiOIcaSdvL0P5MPtkV1UCH+QxpEZTv4Uo+c4nVZTysheLSt
+6aoKZdDUZaELGnyYN5bpWWA/lWFrBIpS9I5Y87broR671rpDiLlckShIPMmWDuRR
+AgMBAAGjgbcwgbQwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3Bi
+cmFzaWwuZ292LmJyL0xDUmFjcmFpei5jcmwwEgYDVR0gBAswCTAHBgVgTAEBCTAd
+BgNVHQ4EFgQUHPxV/WT83BbMZSzn+XQH3rpLK9YwHwYDVR0jBBgwFoAUivrxV4QR
+EzWQQvpXSVRpDaTE8DcwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAIPN+JFPD3nfGczyLBzGwdD6XmDfPtEpEfbQKGib
+ZekS/ip6eWoXAwWqgYRunSN5H9lukMWI6IEKcV92aSVFSQRrOPIIpZg0MiA+XCBq
+XLXqVYUmVDCtKbzDq9xrRYP21lDQk94vgKih7OUznHQspUKgNvAHJeE60oAVgeA8
+cBc+AVVmf5VWbiKOKwx3JiCoGI7g3p41fXxk4urxu/rD8lYh3FcH3v261H6aEAba
+e5eeGwcioeDH9vusedmFYpmcSDGmr8edCoOohZToFffKQJNdNSrpFt1yECQ/Nj/y
+6B+CCY1XWte4TJ2/tbIFasBxzjRDUD7luJ/Ij0X24+3EsyE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFCjCCA/KgAwIBAgIEQd8NtTANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJi
+cjETMBEGA1UEChMKSUNQLUJyYXNpbDEgMB4GA1UECxMXQ2FpeGEgRWNvbm9taWNh
+IEZlZGVyYWwxETAPBgNVBAMTCEFDIENBSVhBMB4XDTA1MDYzMDE3NDQzMloXDTEx
+MTAzMDIzNTkwMFowWjELMAkGA1UEBhMCYnIxEzARBgNVBAoTCklDUC1CcmFzaWwx
+IDAeBgNVBAsTF0NhaXhhIEVjb25vbWljYSBGZWRlcmFsMRQwEgYDVQQDEwtBQyBD
+QUlYQSBJTjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKJ9UgjioJ/+
+K2NLorz1V1rxRvqKAT4ECVuloApMuOAtDnEjfnf7aIe4wn+z8MN1Vw0TlaNeXmKI
+sPk3kndlGSu99AucYkl26JyBjoI7KWvJeenBAYvSexkIKAgXB+DoBXrcaRhULT+q
+pKJhgzQAlppsD60XqifnToxgjd4cMfgmjp+DPL2sFU1nr+ZqqbTym8AVQQ6u+48D
+BPtlrVeNWXrbcjNWL54HY9NMUB33CXNo4+qphCFCrAxwiXNRlSequZ1wpYOCkB8y
+vZjX5sXTn05+RlebZyU3PBc9Zri3t2lcZaFsIBNgCH4crpYGu6hnf0QtU+epsciX
+VcIkUto/vscCAwEAAaOCAdkwggHVMA4GA1UdDwEB/wQEAwIBBjCBowYDVR0gBIGb
+MIGYMEoGBmBMAQIBBzBAMD4GCCsGAQUFBwIBFjJodHRwOi8vaWNwLmNhaXhhLmdv
+di5ici9yZXBvc2l0b3Jpby9kcGNhY2NhaXhhLnBkZjBKBgZgTAECAwcwQDA+Bggr
+BgEFBQcCARYyaHR0cDovL2ljcC5jYWl4YS5nb3YuYnIvcmVwb3NpdG9yaW8vZHBj
+YWNjYWl4YS5wZGYwgbMGA1UdHwSBqzCBqDBuoGygaqRoMGYxCzAJBgNVBAYTAmJy
+MRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSAwHgYDVQQLExdDYWl4YSBFY29ub21pY2Eg
+RmVkZXJhbDERMA8GA1UEAxMIQUMgQ0FJWEExDTALBgNVBAMTBENSTDEwNqA0oDKG
+MGh0dHA6Ly9pY3AuY2FpeGEuZ292LmJyL3JlcG9zaXRvcmlvL0FDQ0FJWEExLmNy
+bDAfBgNVHSMEGDAWgBQc/FX9ZPzcFsxlLOf5dAfeuksr1jAdBgNVHQ4EFgQUlIqn
+HLQRdQ4B4Vnh0fnxcI6WHEowDAYDVR0TBAUwAwEB/zAZBgkqhkiG9n0HQQAEDDAK
+GwRWNy4wAwIAgTANBgkqhkiG9w0BAQUFAAOCAQEABRY0YVB0QcEOz8cYorjINJW+
+z8posP1QjmIPxNSLM96qQJ8G53uLv7q1CF2cWVvuZZnkxQqWnpSKCJr0f5X5TiLW
+7Qzq9P7xrTKJfpK+lvdDkQFZxkvhH0SaTiqg8cCwCU9xcHtMaTuYZTHF9x38fNBL
+gngc1eqF2lqjrrsvZ0kX3Y/DeT6wxQu8QteWb0tS5LnRaKRlwqgq3eWGz5ZdRr1e
+8Y3p6/PrXJXINR5c0uMZA4v3Ke8IHx30ZZK79udDIWE2/lGuWsrIRVfwUquPAQEG
+u8o+KoxeYDHeQuEuTSlTuzR5uM+q5NiNr6Pd0lFkdI9ObHeMS4gYdovE7piOOA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFlTCCBH2gAwIBAgISMjAwNjA0MDcxNTM2NDYwMDAxMA0GCSqGSIb3DQEBBQUA
+MFAxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSwwKgYDVQQDEyNB
+dXRvcmlkYWRlIENlcnRpZmljYWRvcmEgZGEgSnVzdGljYTAeFw0wNjA0MDcxNTUz
+MzZaFw0xMTA1MzExNTUzMzZaMHAxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1At
+QnJhc2lsMTUwMwYDVQQLEyxBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgZGEgSnVz
+dGljYSAtIEFDLUpVUzEVMBMGA1UEAxMMQUMgQ0FJWEEtSlVTMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxPeks/OhVO9rsPjWGLmx0wb0B5MfDsOsoEOs
+nO/Yh6jAiJ0Br+fUCAIWq0ehN4AWMuiemNvGdJRqJW2I42ME5WPfgPgYNMLQAopo
+oipRo9S8C0BJm1ci0ATXbDvp68lsBHFVlo1ZmyQttnz7Vb1Mlruq6S5u6seezp2z
+STFjVwzp9XVaYnutz1uD1IeCEPIdkgBRTlXP95JjacX6xnG7g2hZ2DvY1E8wqNZq
+yyQB/qyQf1gQj7z93g51d5C1FUCSVQRarwI3zEQhfi5UrhACi4wZdBsNzk7GlTLc
+gKLKvxNLyPG804qj8hEeOUuc5FTU1visVIeNnknAGTxIHJ/DGQIDAQABo4ICRzCC
+AkMwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBS+OdrawXcl4K69Gs6k
+W5/AemD8ZTAdBgNVHQ4EFgQUDNDX/gMFm70hiQQ/Esavo6rXni4wDgYDVR0PAQH/
+BAQDAgEGMIIBnwYDVR0gBIIBljCCAZIwQQYGYEwBAgEWMDcwNQYIKwYBBQUHAgEW
+KWh0dHA6Ly93d3cuYWNqdXMuZ292LmJyL2FjanVzL2RwY2FqdXMucGRmMEEGBmBM
+AQICBTA3MDUGCCsGAQUFBwIBFilodHRwOi8vd3d3LmFjanVzLmdvdi5ici9hY2p1
+cy9kcGNhanVzLnBkZjBBBgZgTAECAxMwNzA1BggrBgEFBQcCARYpaHR0cDovL3d3
+dy5hY2p1cy5nb3YuYnIvYWNqdXMvZHBjYWp1cy5wZGYwQQYGYEwBAmUFMDcwNQYI
+KwYBBQUHAgEWKWh0dHA6Ly93d3cuYWNqdXMuZ292LmJyL2FjanVzL2RwY2FqdXMu
+cGRmMEEGBmBMAQJmBDA3MDUGCCsGAQUFBwIBFilodHRwOi8vd3d3LmFjanVzLmdv
+di5ici9hY2p1cy9kcGNhanVzLnBkZjBBBgZgTAECZwYwNzA1BggrBgEFBQcCARYp
+aHR0cDovL3d3dy5hY2p1cy5nb3YuYnIvYWNqdXMvZHBjYWp1cy5wZGYwOgYDVR0f
+BDMwMTAvoC2gK4YpaHR0cDovL3d3dy5hY2p1cy5nb3YuYnIvYWNqdXMvYWNqdXN2
+MS5jcmwwDQYJKoZIhvcNAQEFBQADggEBAHJhUoT96zSCDM68Gc7u40gotmTFoxN3
+JFIBOhi7aO2qABGdyRTJUq4+LzwGXk0BljF4G+sMpBZRAuy2a3sfPYFQggnK2iMl
+acRaLMkxjxhYEAMvUTptatQvsyqJAZHh/a9VKwpv98b6y1N1ZzRxQaof55w/aC5Y
+rCzal8gUSl6qJOeDF9nbarbN7FT2B5NpE34hOfLctuJG8WKr4nF4eRQR8baxpiBe
+YaAQAK0TZ14JCLipeAnivAoR+7OsIT9gk6JF+C2fQDkAWd/GX+PPsnSGJvUntoz/
+CKCkL+YS/e1kh3EqUMEXYmTKZm9lwDpzZSPVdpRieCqQNtcjXm5R2L8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFCjCCA/KgAwIBAgIEQd8NszANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJi
+cjETMBEGA1UEChMKSUNQLUJyYXNpbDEgMB4GA1UECxMXQ2FpeGEgRWNvbm9taWNh
+IEZlZGVyYWwxETAPBgNVBAMTCEFDIENBSVhBMB4XDTA1MDYzMDE3MzgxNFoXDTEx
+MTAzMDIzNTkwMFowWjELMAkGA1UEBhMCYnIxEzARBgNVBAoTCklDUC1CcmFzaWwx
+IDAeBgNVBAsTF0NhaXhhIEVjb25vbWljYSBGZWRlcmFsMRQwEgYDVQQDEwtBQyBD
+QUlYQSBQRjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALrVcHHI/6rA
+XeTBQOwciz8TQmGqHsnJ1N3wpETdi47g7qBcSOxDv7E+Ndr/EE6nOIhNA/sGWplo
+1bgzWalYdl7fW+pzCEHaYJlSQ2crA1DgIacbyvuGSEUfHyiYBBfFv5Y8fdU1IXY7
+8rmF2VEVtU7BbT9S+7+LeLjhonqyjQk1FinsdC+YGCDjNQqbiKlkMOVUGMFRuhlu
+usD6GpZXW0Ez61cbRq81IIUBTEVvV7bAcPr2/cVCNOVlxWQv6Q3fCinvtTi4v41P
+YPad+vZec3BxyWZZzfmbT/2CbyQJMWNohNPeQ3pSEyBmLLTEcXBAXmuy0J3MfmMk
+QJbflpMKsasCAwEAAaOCAdkwggHVMA4GA1UdDwEB/wQEAwIBBjCBowYDVR0gBIGb
+MIGYMEoGBmBMAQIBBzBAMD4GCCsGAQUFBwIBFjJodHRwOi8vaWNwLmNhaXhhLmdv
+di5ici9yZXBvc2l0b3Jpby9kcGNhY2NhaXhhLnBkZjBKBgZgTAECAwcwQDA+Bggr
+BgEFBQcCARYyaHR0cDovL2ljcC5jYWl4YS5nb3YuYnIvcmVwb3NpdG9yaW8vZHBj
+YWNjYWl4YS5wZGYwgbMGA1UdHwSBqzCBqDBuoGygaqRoMGYxCzAJBgNVBAYTAmJy
+MRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSAwHgYDVQQLExdDYWl4YSBFY29ub21pY2Eg
+RmVkZXJhbDERMA8GA1UEAxMIQUMgQ0FJWEExDTALBgNVBAMTBENSTDEwNqA0oDKG
+MGh0dHA6Ly9pY3AuY2FpeGEuZ292LmJyL3JlcG9zaXRvcmlvL0FDQ0FJWEExLmNy
+bDAfBgNVHSMEGDAWgBQc/FX9ZPzcFsxlLOf5dAfeuksr1jAdBgNVHQ4EFgQUUMLw
+p1F6NCjO5zxYaNjRvc9mXhkwDAYDVR0TBAUwAwEB/zAZBgkqhkiG9n0HQQAEDDAK
+GwRWNy4wAwIAgTANBgkqhkiG9w0BAQUFAAOCAQEAGkRhJIjrHitD3BSycDYSDp2h
+SMyrzk6DhbjG/T8wLHDVgTvezM4ljdApzKsKqJb8UUPmc4gWurVBna3C9AJUBqY7
+9hvMyU/DDzNbElia7N3+nydBGpkaDLhSjbBe+bxutmUfJxncY2z4ATR+xU1hhH2j
+E8OVCM5xYxP1Y6J0W+Cq3/mLQ8cUEkgmAynfUyENtHOrhtwVGyjWxYwLBDnUIzHO
+CthdqMmAUpZg/+033Tc9ReYC5ApQ3BEU59Kg9B2+kVqOhiXFjyeUbkmFVPaovOTr
+kSP/6nyDkNYVAppyuph3a11V0unIO1aUZd/uvwI/xIhE3j/lMjiCgYyOD6Bssw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFCjCCA/KgAwIBAgIEQd8NtDANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJi
+cjETMBEGA1UEChMKSUNQLUJyYXNpbDEgMB4GA1UECxMXQ2FpeGEgRWNvbm9taWNh
+IEZlZGVyYWwxETAPBgNVBAMTCEFDIENBSVhBMB4XDTA1MDYzMDE3NDEyMloXDTEx
+MTAzMDIzNTkwMFowWjELMAkGA1UEBhMCYnIxEzARBgNVBAoTCklDUC1CcmFzaWwx
+IDAeBgNVBAsTF0NhaXhhIEVjb25vbWljYSBGZWRlcmFsMRQwEgYDVQQDEwtBQyBD
+QUlYQSBQSjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ+a0eW75H+V
+Ik7qKh1E6wXXxrs1dHA7VzWSvUwDAdRAX1cfowrD8y3lC0f4DeY9kHyiTIKss6gm
+wgUns0H0L1Dr1G2E40AFFnRt8uG3iDEXe5tlUJBL7uKSPHpfCcawWV+bZweIG3Bc
+kLnuL3y6x0iqRvtQ7QvTRqzAauyPLHGUhUa8xmXtx6I/x8vqoS8xr1lliMT2YX9y
+1bj9H0vcauVz57r6eMPjtuPlsNyvLz6XPo0Fj5V8SkP3cLOP7MqLATZnpMhLj1Qd
+n7sdMjyWB6MROQNMInjdx5Ie6zHfTAOOc4r0saCUsVfbs6gesCZ5S+YF5JeGh05X
+SkraOrJOEc8CAwEAAaOCAdkwggHVMA4GA1UdDwEB/wQEAwIBBjCBowYDVR0gBIGb
+MIGYMEoGBmBMAQIBBzBAMD4GCCsGAQUFBwIBFjJodHRwOi8vaWNwLmNhaXhhLmdv
+di5ici9yZXBvc2l0b3Jpby9kcGNhY2NhaXhhLnBkZjBKBgZgTAECAwcwQDA+Bggr
+BgEFBQcCARYyaHR0cDovL2ljcC5jYWl4YS5nb3YuYnIvcmVwb3NpdG9yaW8vZHBj
+YWNjYWl4YS5wZGYwgbMGA1UdHwSBqzCBqDBuoGygaqRoMGYxCzAJBgNVBAYTAmJy
+MRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSAwHgYDVQQLExdDYWl4YSBFY29ub21pY2Eg
+RmVkZXJhbDERMA8GA1UEAxMIQUMgQ0FJWEExDTALBgNVBAMTBENSTDEwNqA0oDKG
+MGh0dHA6Ly9pY3AuY2FpeGEuZ292LmJyL3JlcG9zaXRvcmlvL0FDQ0FJWEExLmNy
+bDAfBgNVHSMEGDAWgBQc/FX9ZPzcFsxlLOf5dAfeuksr1jAdBgNVHQ4EFgQUjkAv
+Cv4T1ao5oHZ0htO8fcfx5c8wDAYDVR0TBAUwAwEB/zAZBgkqhkiG9n0HQQAEDDAK
+GwRWNy4wAwIAgTANBgkqhkiG9w0BAQUFAAOCAQEAU9emrjVOoAZheRKpes0tjHzY
+Tk4MHGE2rp9Jgk7OCqfBY8vl6eQDLgGKIPLemhqqDJnX5o1F0zqo+jVo0sz04GHy
+j4B1KSj194fqS2/Fsauo1z9akYrqSX3tguDoEKDR0OVrUOjlNyZajEA/sUz/369F
+stBYc0SYy+n3cTWm59oKSNOJ8CjSDlgcx+Oh0e2ctQaAN/LpG7cOSPEKV5QsWLkQ
+GY6piuI31gi04O3NbacUyN7UsxCU+P1iRXbpcpFwCv//PJPAJRdqEGXvtrKNSik/
+AfP38MMXI9spydOezauvo/iv6dWrC3CuHjgvhFJJ5KqX5tua2QzINGmdlI0DcQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEODCCAyCgAwIBAgIBFTANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wNTEyMTkxMzAwMDBaFw0xMTA2MTky
+MzU5MDBaMFAxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSwwKgYD
+VQQDEyNBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgZGEgSnVzdGljYTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZdinSE3Ly323/o9QhmoXxj58rV88m8
+nNzlBPjs84dSB4nvaYTwCwZtbhk+NEbCzs8ydDL5JveYNqIP1sBtqxVz+nfEdDHV
+WdwJuPwrX+q5+zkv91C/nUDfvp6ZcKh2ufGeAdI6YjDiqiPJL8wUxOd4W/KAbejp
+6yynu6X3uUFaK4ziBEsTV5WwSnoh569KSJoDGr1Gyeo/2Di48UdAT3eEemW8l56G
+nwnXX+ZwDKwPMp4rn4nq9n+7VUxlProo+xEe3OUNe8iVXftRLjTp5nrvkXMwJ/g8
+Pu3CpsQUJgDl/GRpuUCB0Tb4c9zVVqu+DTToEytyV47VxJwLOFS76esCAwD3v6OB
+tzCBtDA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vYWNyYWl6LmljcGJyYXNpbC5n
+b3YuYnIvTENSYWNyYWl6LmNybDASBgNVHSAECzAJMAcGBWBMAQETMB0GA1UdDgQW
+BBS+OdrawXcl4K69Gs6kW5/AemD8ZTAfBgNVHSMEGDAWgBSK+vFXhBETNZBC+ldJ
+VGkNpMTwNzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQUFAAOCAQEAu22EJMIck6Q5E/piA3I26+JjChyuwU4UOWdk1GxqJ2AiI11N
+ZrjoEHc8W0gFTKZFFaywwBZYVqHvWao7iyRCDCXi4q2iVnPdA3GpMpuM69E2a5sf
+lH5Xd4VUoLpbozdio6hqjRSChX47MiIGu+B2b0DvtejdIIhkElnI2yysa0FhP7af
+qqr/FjH4Z1nDFxfJPIPQ3+u+nVICIGF7Fx/RCefIxo7+1/7e4IPsOdgCaJnsAE3x
+Kr1tz8mC+Wd8WR8ieeWwcEDt7frV1vXHSeqA8n0QwaNWfYneDWqklcr7Z9Z6bu6B
+yQfHRF6V/bSFpw6nZkYHZs7JO3w+3wmyJvc7Tg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEczCCA1ugAwIBAgISMjAwNzA3MDYxNDA5MjgwMDAxMA0GCSqGSIb3DQEBBQUA
+MFsxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMTcwNQYDVQQDEy5I
+T01BdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhIHYyMB4X
+DTA3MDcwNjE0MTI1NVoXDTE1MDIwNTEzMzMwN1owgZIxCzAJBgNVBAYTAkJSMRMw
+EQYDVQQKEwpJQ1AtQnJhc2lsMTswOQYDVQQLEzJTZXJ2aWNvIEZlZGVyYWwgZGUg
+UHJvY2Vzc2FtZW50byBkZSBEYWRvcyAtIFNFUlBSTzExMC8GA1UEAxMoSE9NQXV0
+b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIGRvIFNFUlBSTyB2MjCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKzhCojv3vAqr0E4bYLk4622BIG2c81+AM0PJvzW
+yxlWEZ9LMc5OmAsLGCKavIA0gPCPaYOsUJmH96aJTBCbHHXhJ0axfbiDCSDYU/yl
+QnDrfaviffeMKWXo0iDqep+1CYHipdryzSjjMz+cMmDf0FIZ5U3L0oIsbMIWCFeQ
+SMQKOrIA+5qsidKg9mzAi47Lib9fUkHIxkzsc1UpZJguxG0/OL8wAAzkHTGbNTRr
+KnE+GUzAZGVGTaX8gfufR7qGTfUcbuirfGbyaEf56yv2lFdDktiI2d5uqVtYsX80
+ZnI3UQhBtD74Hz8zrZYlckokkHzr3wEgiFsWAi3Ck3w4bN8CAwC366OB+DCB9TAP
+BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFJYO9HOQfXSw7NpneWFbdw/ngZMo
+MB0GA1UdDgQWBBRrbM92NcY/uYHy1BaoSs9MpXYkuzAOBgNVHQ8BAf8EBAMCAQYw
+UAYDVR0gBEkwRzBFBgVgTAEBADA8MDoGCCsGAQUFBwIBFi5odHRwOi8vY2NkaG9t
+LnNlcnByby5nb3YuYnIvRFBDaG9tYWNyYWl6djIucGRmMEAGA1UdHwQ5MDcwNaAz
+oDGGL2h0dHA6Ly9jY2Rob20uc2VycHJvLmdvdi5ici9sY3IvaG9tYWNyYWl6djIu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCYhv204f6nsoVxGRBGY9vt+wvvjmODuZ0K
+4vMBLwHGyb8Fx0l6mbT9cuns2Uq4TZiL5UMz/SUHu+4Va7XZ1I8GBAMt5nhoocsG
+Ng+YzJ80fHLNqJ6PHkdixWV+nm1/d3YzZcwQ1wXirF6dYEelH2XC4EQq2y3jLmy9
+E+BKilgdwVChviH6CIPR1LLqNhumhOQuNnA9FkVopj/jDORnNmosFkp52lx9gSyC
+xLUjEA5JbVUEl3xxIPs1pm50dZLojOjzLajtgsmOvJ9tZWe8ITuiDSvLCSuKNq6w
+KRc+qJ3NYCOudS+1hJm9qN3BPq0Q3njioQSHJQT+RoF5kmB91jiW
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFcDCCBFigAwIBAgISMjAwNzA3MDYxODU3MzYwMDAxMA0GCSqGSIb3DQEBBQUA
+MIGSMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE7MDkGA1UECxMy
+U2VydmljbyBGZWRlcmFsIGRlIFByb2Nlc3NhbWVudG8gZGUgRGFkb3MgLSBTRVJQ
+Uk8xMTAvBgNVBAMTKEhPTUF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBkbyBTRVJQ
+Uk8gdjIwHhcNMDcwNzA2MTkwNTE0WhcNMTMwNzA0MTkwNTE0WjCBqTELMAkGA1UE
+BhMCQlIxEzARBgNVBAoTCklDUC1CcmFzaWwxOzA5BgNVBAsTMlNlcnZpY28gRmVk
+ZXJhbCBkZSBQcm9jZXNzYW1lbnRvIGRlIERhZG9zIC0gU0VSUFJPMQ8wDQYDVQQL
+EwZDU1BCLTExNzA1BgNVBAMTLkhPTUF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBk
+byBTRVJQUk8gRmluYWwgdjIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQC8/uBuPe+VpJLKBiDPxEP6XEEY1pdyVgCGmdaWK/byR2bZrvvnY2SwpJWYpt0i
+Fs01utxAC6FMRURUKz9c3mM7fQSlN3rZti0l/iP3Hk+D1Fs1/xUWFTl5suWUiZT1
+HVBNQrOb9WNAQFdCpRpZqvMR0ohrRo69Uaf4nA/xwxh7cpSQM2jlu/8M75xIKf13
+vI4PnxYRcC6mgctY5Qpq9ZkT8rnfeNWm+zCNj66Eg2gW5eR0LpgyT4rdE8j7YUDb
+zybRGxan7Z4bA2+srL/wccCSTlWoJrfTo/4JjKbyljhFBfVuhZlRillIZee2VYAe
+WH18dQPPUEP7uvS5b6rBzsaTAgMA69+jggGlMIIBoTASBgNVHRMBAf8ECDAGAQH/
+AgEAMB8GA1UdIwQYMBaAFGtsz3Y1xj+5gfLUFqhKz0yldiS7MB0GA1UdDgQWBBSu
+NPOXuwWxqmzD/WxPDpEpu7Yb4jAOBgNVHQ8BAf8EBAMCAQYwgfgGA1UdIASB8DCB
+7TBNBgZgTAECARAwQzBBBggrBgEFBQcCARY1aHR0cDovL2NjZC5zZXJwcm8uZ292
+LmJyL2Fjc2VycHJvL2RvY3MvZHBjYXNlcnByby5wZGYwTQYGYEwBAgMNMEMwQQYI
+KwYBBQUHAgEWNWh0dHA6Ly9jY2Quc2VycHJvLmdvdi5ici9hY3NlcnByby9kb2Nz
+L2RwY2FzZXJwcm8ucGRmME0GBmBMAQIBBzBDMEEGCCsGAQUFBwIBFjVodHRwOi8v
+Y2NkLnNlcnByby5nb3YuYnIvYWNzZXJwcm8vZG9jcy9kcGNhc2VycHJvLnBkZjBA
+BgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY2NkaG9tLnNlcnByby5nb3YuYnIvbGNy
+L2hvbXNlcnByb3YyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAeDPepDoH81XwH2wt
+CRx4eWCo4rnG94a72OZ93cZLp5qY5XD5P93WDJ5AoNzvPYHvZgzrtFz5lrP0zlV2
+d0OhhYaqwNqHpy5w/BYsM6gYvlbIIjDWdQVqc/p854YTRE9q81aVIuM2NYEFqPnC
+hTAb+sI4z3jMrrtYOBHB0XHPCzPYAKe2kP5HVKQ5LZsTY0m3A9RCWEAHaBPDQ/LX
+BYOFRqt7Yra0z22ul3TZyM/tL9jmLJyRoQC07gqjYJwgUwAa+smrGfQqSyzu9q6o
+ttLYJVsqu8G3MiTrIf6ND7TwlvxwPJAj3m+PXSdnVkBD1NKVMk9BiTeqoI7A0k6B
+XaHuQg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEOzCCAyOgAwIBAgISMjAwNzAyMDcxMzMyNTcwMDAwMA0GCSqGSIb3DQEBBQUA
+MFsxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMTcwNQYDVQQDEy5I
+T01BdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgUmFpeiBCcmFzaWxlaXJhIHYyMB4X
+DTA3MDIwNzEzMzMwN1oXDTE1MDIwNTEzMzMwN1owWzELMAkGA1UEBhMCQlIxEzAR
+BgNVBAoTCklDUC1CcmFzaWwxNzA1BgNVBAMTLkhPTUF1dG9yaWRhZGUgQ2VydGlm
+aWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjIwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDtov6OzoFyLGNs6CmLZ9FI0FOortZY3I5crKPFX9pWEDFbxjXb
+ARn1tBhraqBOaoNMHk2jktURRE+d4NBz9FzTJqzxx7gM9mgTAVy4E9Yybc0cKH34
+6GO3AZLz9Kok6BQ/0wIVpcoyaPSoJvFV3bbOZ8tvAjIbkKjcVmVKzThL6YmOu+Zc
+EFDKoau8lk8CifERoST5c0EtRlpeX9vIYsLq4h/N6jaSnCooqVcoVQxzcGrEEmVH
+rLdplBsFW0syKI46mWvPmubHL3MZseX5uOGl0N7aT6Obi7XAKDsSMcOEB7C1Kx56
+vRg0pE5p0oRgX0x0wjgpP6jVx3SJhM1snPEjAgMAtdWjgfgwgfUwDwYDVR0TAQH/
+BAUwAwEB/zAfBgNVHSMEGDAWgBSWDvRzkH10sOzaZ3lhW3cP54GTKDAdBgNVHQ4E
+FgQUlg70c5B9dLDs2md5YVt3D+eBkygwDgYDVR0PAQH/BAQDAgEGMFAGA1UdIARJ
+MEcwRQYFYEwBAQAwPDA6BggrBgEFBQcCARYuaHR0cDovL2NjZGhvbS5zZXJwcm8u
+Z292LmJyL0RQQ2hvbWFjcmFpenYyLnBkZjBABgNVHR8EOTA3MDWgM6Axhi9odHRw
+Oi8vY2NkaG9tLnNlcnByby5nb3YuYnIvbGNyL2hvbWFjcmFpenYyLmNybDANBgkq
+hkiG9w0BAQUFAAOCAQEAoysgdsBf8fwZn9Ldd27BjXyvMTU+z3Yxz4Y+iNzW+zf6
+kDVeU9rjbOFfHpNRRp/sK35tRjG2+wqdk1qXRggg7i/lj8wWYMkgGmw2PFc6IxgI
+ZsHCa8IGGGETpc94ZTF527zHvqL58pnxIh+5K/+8/YyoRCHlH7jqtZxopUFRqEup
+FqRTeBoqwy0RE1Gr6txhdktUJqOtY7xw9fg5tskbaReiWSYxkI2nWkIKcQ7W3wMc
+WI6PzTAM8nTB5kzBs8E9z7EFWAOvTrf6tbB6xhDPW0wEpp6BWF8zqBvCqlM8cwOV
+1CshiU0615IBiD6DuuS66FtoYpOR0aKwFCMVJMIWOA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBBjANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMTK0F1
+dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjEwHhcNMDkw
+MjE4MTkwMzI4WhcNMTkwMjE4MTkwMzI4WjBPMQswCQYDVQQGEwJCUjETMBEGA1UE
+ChMKSUNQLUJyYXNpbDErMCkGA1UEAxMiQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3Jh
+IFNFUlBSTyB2MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKvqKR6c
+rhBNjIB6amZnpOE+cuSfmrpG9tO6qTlFBUrhgJdsXreUxsQzuKGJ9C0TvjP9kNOE
+AXAc6kdueDb82kQNOworuqJi9uY2NiNgQSIIp/5/4HQ4bNldcBB9gPjNHW9lk4gn
+GJCwQ6mie3H6WQOwkIh7lWKWs5Fpx4H+qspLJ3blTou3AFQYDS6i4dvwGY58R517
+6Xl3B3jsJ5OifWzJr4pMxK3TJrzZ6jsdEslbRPeRSafTkF3eqLr6nrv619r34ISd
+7NCj8eFGb6yYb+OuE7gPuxQq/1lxQyXigj+pN94X+8KC4fT7xxr300BnHZCBlaw9
+T4ivr0Y/RaB3DW8CAwEAAaOBuzCBuDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAUBgNVHSAEDTALMAkGBWBMAQECMAAwPwYDVR0fBDgwNjA0oDKgMIYu
+aHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xDUmFjcmFpenYxLmNybDAf
+BgNVHSMEGDAWgBRCsixcdAEHvpv/VTM77im7XZG/BjAdBgNVHQ4EFgQUHVcev4hY
+sn4YKPjAk1SFyxJpKQwwDQYJKoZIhvcNAQEFBQADggEBAG1MKQN2MRTgm4rUSCmy
+CWnFozVoMMAUC6n4NnDvFIeBZOvsQueD0banmc8JwzvWweQUhXW/2YhE5h63hHve
+p71ie1CHRqncLfgfooBvjJBTdXbHsg+k3sqmqt84ndG/YbeOsQ64+ovK1yBjrzen
+Z0ZmLKsrP2cHS7yeaJb/ZlhcAQ9jhxqN+jKT3BSvAss4LJ3Nh0cEr+bQaaN3FA7I
+fsbLCg9JZQ5WeAL3f894ERW3Iur+IzZvDfQj/I/+D1wiHIRLuYSkMV5gswyqUDSj
+btMn/D1SMp5QsR6n3qfaoS66jbQgZglQJ6rvt4HFIyEx4rJgIhtv72UeMQWcIyrX
+XNo=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFGjCCBAKgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJCUjET
+MBEGA1UEChMKSUNQLUJyYXNpbDErMCkGA1UEAxMiQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFNFUlBSTyB2MjAeFw0wOTAzMTIxNTM0MjZaFw0xNjAzMTIxNTM0MjZa
+MIGmMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDE7MDkGA1UECxMy
+U2VydmljbyBGZWRlcmFsIGRlIFByb2Nlc3NhbWVudG8gZGUgRGFkb3MgLSBTRVJQ
+Uk8xDzANBgNVBAsTBkNTUEItMTE0MDIGA1UEAxMrQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIGRvIFNFUlBSTyBGaW5hbCB2MjCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAOD6O5umiLCPP2GK18RjAmpzpnjPvetQBvOeQtc61SCVvxxnkYnD
+nWVtHbRLQwnuV/IXuiP7HdnBUV5E8lvNJwGxSzyAGYa1rIYlBeoT1hrFCQkL5csd
+yq8Rp2CiFSjE2CrVSx0g1fhS0e1Hu53bWEMC38i4RPCjG91qW9zQT8p8et8nIJ2H
+By4JC+bRm2u7kkXx4QlCL2eCX6+Q+Q95uRuUd40oO8400gCrPz49jzW/eO9G2EKL
+22GRFOQkKAMmtQZFPu8Sh+U7DOoqyO46VdamHY6uPmQoyJoq+KFuWUkKHy99fORY
+7CXWB3O+CqQYIetHGvG+pA7HAQlWAgsO3CsCAwDRi6OCAacwggGjMA4GA1UdDwEB
+/wQEAwIBBjCB/gYDVR0gBIH2MIHzME8GBmBMAQIBEDBFMEMGCCsGAQUFBwIBFjdo
+dHRwczovL2NjZC5zZXJwcm8uZ292LmJyL2Fjc2VycHJvL2RvY3MvZHBjYWNzZXJw
+cm8ucGRmME8GBmBMAQIDDTBFMEMGCCsGAQUFBwIBFjdodHRwczovL2NjZC5zZXJw
+cm8uZ292LmJyL2Fjc2VycHJvL2RvY3MvZHBjYWNzZXJwcm8ucGRmME8GBmBMAQIB
+ETBFMEMGCCsGAQUFBwIBFjdodHRwczovL2NjZC5zZXJwcm8uZ292LmJyL2Fjc2Vy
+cHJvL2RvY3MvZHBjYWNzZXJwcm8ucGRmMDwGA1UdHwQ1MDMwMaAvoC2GK2h0dHA6
+Ly9jY2Quc2VycHJvLmdvdi5ici9sY3IvYWNzZXJwcm92Mi5jcmwwHwYDVR0jBBgw
+FoAUHVcev4hYsn4YKPjAk1SFyxJpKQwwHQYDVR0OBBYEFMMHIUz2AP2ET2ip5rAF
+/d+wpak8MBIGA1UdEwEB/wQIMAYBAf8CAQAwDQYJKoZIhvcNAQEFBQADggEBADGN
+NtiN/Tk3bRBAaq6H1ipgyq4IPeA4F9wYLm9lYsoAqvHYV6vYQ5CuZs24lpidashd
+z4E+qdjWDW40eucfreWPD4Y6PbfUwuABS7vbyuAPn78VTODc/jUxj6k5sqEuzDa0
+tOLLggUdI5TnL8k163ezAfTvBYF/PgqQSKLPl7ygNVwIglkDMI17fcuiKNPwP6bm
+jpyaiVt0Z9q9zqkJuEmgeFI5deiVuotjBTmfSsqOfcIKtHChNvKodkSnXWJfV/Qr
+JDVdzjr2fUAjh9xmUj8jy/P00Go48o7XchMwCRxNdNHuKlzaqMSyCw5943ot9MQR
+br8utaD7Mh3XSUi7qj4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEEDCCAvigAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxNDAyBgNVBAMTK0F1
+dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEJyYXNpbGVpcmEgdjEwHhcNMDgx
+MDI0MTIzOTQ2WhcNMTgxMDI0MTIzOTQ2WjBXMQswCQYDVQQGEwJCUjETMBEGA1UE
+ChMKSUNQLUJyYXNpbDEzMDEGA1UEAxMqQUMgU2VjcmV0YXJpYSBkYSBSZWNlaXRh
+IEZlZGVyYWwgZG8gQnJhc2lsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA3o1phpOoNH/BA5ydDgeDndk7mItSVUK7t3PNjCkF/7lCSM3SiQxi/XsnvS3f
+4NCR5Vq/4yGrWa31FJi/XYRlLZH46L86S2hOBkV5sIxrr0EPN5q/EUTQCrcbcqgr
+V9QX2SSPqOO5+wS8+zygNfBAOPFSLpqwyzSYS+ZQdeDkuhFMikF07e7XwfRvc+/K
+eR0RU1p8GijtAtqsXGmq/8wunlySd7g+h2CfkILnY87GyB3UwOP7zSOaV2Un9/yz
+dBRduGpUZSx2yn8FrBB7mCfE58gJo5YZ1KZfcSfRNrAaQW6B7mDLsRnDdn5jYQnn
+0w/xf9Kwq3YFB1rZKRDBGLqhVwIDAQABo4GlMIGiMA8GA1UdEwEB/wQFMAMBAf8w
+DgYDVR0PAQH/BAQDAgEGMD8GA1UdHwQ4MDYwNKAyoDCGLmh0dHA6Ly9hY3JhaXou
+aWNwYnJhc2lsLmdvdi5ici9MQ1JhY3JhaXp2MS5jcmwwHwYDVR0jBBgwFoAUQrIs
+XHQBB76b/1UzO+4pu12RvwYwHQYDVR0OBBYEFBtdm3eNVCVtBaPCcqy/d/mxPDhL
+MA0GCSqGSIb3DQEBBQUAA4IBAQAfE0z7q9dicmpuK8TbkmFjb5NdR4xxy5n2H+hI
+S/mxAXXUxD1MHQltmFzjGjCVLKxfnLXDFPzfEuB1KCEACseAS1q2iAgDaEOAbVoG
+iSNZF5Tx8wCdkGXszBC8kdM4RUsLqVAAIkNxH+6K7I9r9Z5/8oNg/JZHCnNP5BLq
+1nKxplltISTTfNecUP2bY/7f24oGlYfoYwtzPZEDu1Zw01jHbT5K4vaMG4pV81d6
+exb+paeCVcZItAo8lxc35ago9RG5HyWO0Ep08CVzesO5CNVhFb5BQDKO/fDDyNPH
+DirDKnx6ZJAclztk6KtIJK9yjixYkBeG6J78eYMhnxJJmfRh
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEtTCCA52gAwIBAgIBCTANBgkqhkiG9w0BAQUFADBXMQswCQYDVQQGEwJCUjET
+MBEGA1UEChMKSUNQLUJyYXNpbDEzMDEGA1UEAxMqQUMgU2VjcmV0YXJpYSBkYSBS
+ZWNlaXRhIEZlZGVyYWwgZG8gQnJhc2lsMB4XDTA4MTEwODEyMzQzOFoXDTE2MTEw
+ODEyMzQzOFowgYoxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMTYw
+NAYDVQQLEy1TZWNyZXRhcmlhIGRhIFJlY2VpdGEgRmVkZXJhbCBkbyBCcmFzaWwg
+LSBSRkIxLjAsBgNVBAMTJUF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBkbyBTRVJQ
+Uk9SRkIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD4D53Epar0R3dq
+xNeJK+G72gYfnIYiBprbiqqewZjev34EThrlGzZ2clWaBZBsnzEW6+LqHXXSJfOn
+IWN3FJ768OQwC09N+k6DX7wt7QRAlkulKptfIXdpjjrSmjoUngcctaiKCuT46kYx
+Pk0Mx0BfIJ4vfwMPE8xd9zkdFknWR+UqDS+gKbApxHQbSrVEjD5fU3R7S6impF8s
+rlev7aKBxw3Yd6Uyz/eaxis3i6cBvwnuF+ZojI/hLPqHpFXnqsFAVzTCxpCSTG25
+ChL52vgaX35AQU7zm9NRvoOOgRgSRdyMj+piaSt7iwU79VCbiQu4knjsSyySbpVG
+bGAvLCOjAgMAovWjggFWMIIBUjAOBgNVHQ8BAf8EBAMCAQYwgacGA1UdIASBnzCB
+nDBMBgZgTAECAQowQjBABggrBgEFBQcCARY0aHR0cDovL3d3dy5yZWNlaXRhLmZh
+emVuZGEuZ292LmJyL2FjcmZiL2RwY2FjcmZiLnBkZjBMBgZgTAECAwQwQjBABggr
+BgEFBQcCARY0aHR0cDovL3d3dy5yZWNlaXRhLmZhemVuZGEuZ292LmJyL2FjcmZi
+L2RwY2FjcmZiLnBkZjBCBgNVHR8EOzA5MDegNaAzhjFodHRwOi8vd3d3LnJlY2Vp
+dGEuZmF6ZW5kYS5nb3YuYnIvYWNyZmIvYWNyZmIuY3JsMB8GA1UdIwQYMBaAFBtd
+m3eNVCVtBaPCcqy/d/mxPDhLMB0GA1UdDgQWBBS5IouGJEbnoq3nKTuMaDtNrXSR
+FDASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBBQUAA4IBAQC5EgiFEaa8
+QmYfcdmsTEjKf3xHIkNbFrJMXFPufUy7RADAsWNj2osjiS0flQehuyPwuKObUQUY
+dXNArO9hZogXQO3NEEFX81KS0CHlT2s+Wn43q5cshoQODfL6msjca+le8LqvDZht
+deGuODxfkp9t43kBvNt8P54b/9ADBuWqY1303j22l6t+vJd9Mdw8ZVnhf7MCLa5x
+4TEr1iRi0mZxE3im9S9DgkhgYDBUPxu16h31fSokgdo4flxbrsqvxitlX0pOqsE2
+KcASqg27iTq2Nfy9pQMC4T4ro/vQwpyWccQAfPNLmroJxlp2XaKaUkSGMVsmhaZT
+kB+UOMPGrRky
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEODCCAyCgAwIBAgIBFTANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIx
+EzARBgNVBAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25h
+bCBkZSBUZWNub2xvZ2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJy
+YXNpbGlhMQswCQYDVQQIEwJERjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZp
+Y2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAeFw0wNTEyMTkxMzAwMDBaFw0xMTA2MTky
+MzU5MDBaMFAxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSwwKgYD
+VQQDEyNBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgZGEgSnVzdGljYTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZdinSE3Ly323/o9QhmoXxj58rV88m8
+nNzlBPjs84dSB4nvaYTwCwZtbhk+NEbCzs8ydDL5JveYNqIP1sBtqxVz+nfEdDHV
+WdwJuPwrX+q5+zkv91C/nUDfvp6ZcKh2ufGeAdI6YjDiqiPJL8wUxOd4W/KAbejp
+6yynu6X3uUFaK4ziBEsTV5WwSnoh569KSJoDGr1Gyeo/2Di48UdAT3eEemW8l56G
+nwnXX+ZwDKwPMp4rn4nq9n+7VUxlProo+xEe3OUNe8iVXftRLjTp5nrvkXMwJ/g8
+Pu3CpsQUJgDl/GRpuUCB0Tb4c9zVVqu+DTToEytyV47VxJwLOFS76esCAwD3v6OB
+tzCBtDA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vYWNyYWl6LmljcGJyYXNpbC5n
+b3YuYnIvTENSYWNyYWl6LmNybDASBgNVHSAECzAJMAcGBWBMAQETMB0GA1UdDgQW
+BBS+OdrawXcl4K69Gs6kW5/AemD8ZTAfBgNVHSMEGDAWgBSK+vFXhBETNZBC+ldJ
+VGkNpMTwNzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG
+9w0BAQUFAAOCAQEAu22EJMIck6Q5E/piA3I26+JjChyuwU4UOWdk1GxqJ2AiI11N
+ZrjoEHc8W0gFTKZFFaywwBZYVqHvWao7iyRCDCXi4q2iVnPdA3GpMpuM69E2a5sf
+lH5Xd4VUoLpbozdio6hqjRSChX47MiIGu+B2b0DvtejdIIhkElnI2yysa0FhP7af
+qqr/FjH4Z1nDFxfJPIPQ3+u+nVICIGF7Fx/RCefIxo7+1/7e4IPsOdgCaJnsAE3x
+Kr1tz8mC+Wd8WR8ieeWwcEDt7frV1vXHSeqA8n0QwaNWfYneDWqklcr7Z9Z6bu6B
+yQfHRF6V/bSFpw6nZkYHZs7JO3w+3wmyJvc7Tg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIErDCCA5SgAwIBAgISMjAwNjAzMTAxNDUwNTgwMDAxMA0GCSqGSIb3DQEBBQUA
+MFAxCzAJBgNVBAYTAkJSMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSwwKgYDVQQDEyNB
+dXRvcmlkYWRlIENlcnRpZmljYWRvcmEgZGEgSnVzdGljYTAeFw0wNjAzMTAxNTAz
+MDhaFw0xMTA1MzExNTAzMDhaMIGHMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQ
+LUJyYXNpbDE1MDMGA1UECxMsQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIGRhIEp1
+c3RpY2EgLSBBQy1KVVMxLDAqBgNVBAMTI0F1dG9yaWRhZGUgQ2VydGlmaWNhZG9y
+YSBTRVJQUk8tSlVTMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyn3a
+XFTTnHlmeTGqzo9NQIUezNQhqfmTUvk0t03KWWZ6gmXO48sO9O/j4jmTWes0rztl
+5hS617gICjUq5KkcowB6L18MQiVPnMmG+Wp1+qNT3fWKsOXrWGPfvtHavVRJ9E1X
+XCt4e5207aaJPKCCWiQ9KDl3Z7+NoSx5yffnpwHHN/6SelrXaRelQlmZZG2gFK2l
+3INF+mCkJ+RKN9FTTjMpog5BNXQHDbCgJQvyp6J4UDs5UfHNjxPQneEa+31/wCWe
+FKHB23mwMtA/IPkifLlKy+rb+Yx6Q/Z962/g6bKKo5XvNXqi1lBm3sqvh6Ztz0HR
+GMzveM0C97nH4lxjxQIDAM3To4IBRjCCAUIwEgYDVR0TAQH/BAgwBgEB/wIBADAi
+BgNVHSMBAQAEGDAWgBS+OdrawXcl4K69Gs6kW5/AemD8ZTAgBgNVHQ4BAQAEFgQU
+5XNjTkp4mXa8Lfj/+Byo/ytxGj0wDgYDVR0PAQH/BAQDAgEGMIGWBgNVHSABAQAE
+gYswgYgwQgYGYEwBAgEVMDgwNgYIKwYBBQUHAgEWKmh0dHA6Ly93d3cuYWNqdXMu
+Z292LmJyL2FjanVzL2RwY2FjanVzLnBkZjBCBgZgTAECAxIwODA2BggrBgEFBQcC
+ARYqaHR0cDovL3d3dy5hY2p1cy5nb3YuYnIvYWNqdXMvZHBjYWNqdXMucGRmMD0G
+A1UdHwEBAAQzMDEwL6AtoCuGKWh0dHA6Ly93d3cuYWNqdXMuZ292LmJyL2FjanVz
+L2FjanVzdjEuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC2b7GzutyRxCuLRu+oTVrW
+r0h+AFmpTXibRyATf3llBImJgQpJMAJHjRUZI7jRexUJKAqlRfO32f/Ozdd8BV+f
+kzc6E0yGB4Stnqg2Qh2uMu1F5ado9I/uwPEAUoieDxtygxEMJHI3+8vGdUelo6Of
+cufmLmuRFiLf+QdpE53MjXYfMMgCa60ngVfhlOmzTx8AIwjf/VTwk5Ojo0DZUQIQ
+uOzWIKkLVNSqQq/NTTib5tO7eRpXGjhhgNJDwa/HDnY7Bihf6YWaxSM5A1GoIVCi
+ueMWldKJdBikQ0GeyqElqmmEJba0LoJ2OlqnkXs0RZ+akp53hfIW1RCnYQqJfouM
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIETjCCAzagAwIBAgIBCTANBgkqhkiG9w0BAQUFADCBtDELMAkGA1UEBhMCQlIxEzARBgNV
+BAoTCklDUC1CcmFzaWwxPTA7BgNVBAsTNEluc3RpdHV0byBOYWNpb25hbCBkZSBUZWNub2xv
+Z2lhIGRhIEluZm9ybWFjYW8gLSBJVEkxETAPBgNVBAcTCEJyYXNpbGlhMQswCQYDVQQIEwJE
+RjExMC8GA1UEAxMoQXV0b3JpZGFkZSBDZXJ0aWZpY2Fkb3JhIFJhaXogQnJhc2lsZWlyYTAe
+Fw0wMjEwMTQxNjM4MDBaFw0wNzEwMTQyMzU5MDBaMGYxCzAJBgNVBAYTAkJSMRMwEQYDVQQK
+EwpJQ1AtQnJhc2lsMUIwQAYDVQQDEzlBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEgZGEgU2Vj
+cmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC+z/4Dqlb6MwAikElPMur5MPnpmeGYlG2lnqL9zp81FJlf8TcBnQ4Qm934cTmuYsjL
+i3H8qZkHKd5KWV7pw1IfY1fv2jN62mGCT0Y0QDLO/Ovc8VR/dF89xQC9A0/s/5eXgCX6QwbM
+Q/46d0kQxz2WrDcx4qtGShfsvgW1kbHa9+KJWKM8WG513eyDPpN7FcD8MXmNKGkE+eorUtwZ
+YcSI7Ooe5xjBxRPemqz6fmCZ7HsXi4udNpGAFxV+KNW3gYuKIiGZ3Ry4JDMz9/gnBYPOrfL0
+e6qOa45oas1pcw93Eg2F3igNR324a6BK51sIwvUroihVE8RxrdP9FTw+7WTrAgMBAAGjgbcw
+gbQwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2FjcmFpei5pY3BicmFzaWwuZ292LmJyL0xD
+UmFjcmFpei5jcmwwEgYDVR0gBAswCTAHBgVgTAEBCDAdBgNVHQ4EFgQUrUPpEW3CB3EnV7nS
+vxCCVYg9EHcwHwYDVR0jBBgwFoAUivrxV4QREzWQQvpXSVRpDaTE8DcwDgYDVR0PAQH/BAQD
+AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBADUrc/zWTEEXMYEgO/AI
+lCFD5AWxE0qh80ysKgR0x+W1ULkYwSxM6sZrth3mzb4iIJk/KclqGns94kTLx6e4zFZpi2oK
+mltgkkTKMHjR6hanMMdGwJ1/jZL6APye0SmyL57rof0cM6k5d1reERYbj4HEpUSZlo2WZ5uk
+EfolqJwznssbROIlReQnpThk3Om5GVNJnblgEFFmUhcLoM+IY0Y0spORu938skMEGzECW8+o
+D93t4CCw7Dylho1gPVME85elx3OzQU56JfA5luCcrGXikbrKDTA/0Cy/JrRRn1nPfHXh1C2X
+ocL9SUmEVCNjMLAZL32jf3TTKk68dx6bqB4=
+-----END CERTIFICATE-----
+
+-----BEGIN CERTIFICATE-----
+MIID7jCCAtagAwIBAgIBATANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJCUjEM
+MAoGA1UEChMDSUNQMTIwMAYDVQQDEylBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEg
+UmFpeiBIb21vbG9nYWNhbzAeFw0wOTAxMDMxMjIxNTJaFw0yMjAxMDQxMjIxNTJa
+ME8xCzAJBgNVBAYTAkJSMQwwCgYDVQQKEwNJQ1AxMjAwBgNVBAMTKUF1dG9yaWRh
+ZGUgQ2VydGlmaWNhZG9yYSBSYWl6IEhvbW9sb2dhY2FvMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAtNolXLj/KExEvuz+vZDsfKSTfIYM+x9CaN71/Awf
+SpB+ghegALAiW0LaJojSRdA1GCZwce4RThtt/zjrsuMxUnFL74Jpu8RMcp7Gc/Us
+MO8fdfaY6vn+PX/XDaUyEk36R6hRrp0ywe1VwAaXmhWjWvDll+MYH7hSHguRb/Od
+44CjAlHVfA61rU3sOD6HDbnK9mjyzB5a0mN8DZgq2NcaGZywXlVQLtec/p6jbqw7
+OJLiDh+eS+jvf8A8OkMCQ82ZabPD2yp8xK4NWwvO+QdwuscdgOm1FsEeUoJJu9sl
+alXXzEyzSHHtl5rZirzUAIcwDEUT+JXtD1808BxpTbw4xQIDAQABo4HUMIHRMFEG
+A1UdIARKMEgwRgYGYEwBAoNEMDwwOgYIKwYBBQUHAgEWLmh0dHA6Ly9jY2Rob20u
+c2VycHJvLmdvdi5ici9kb2MvZHBjcmFpemhvbS5wZGYwPAYDVR0fBDUwMzAxoC+g
+LYYraHR0cDovL2NjZGhvbS5zZXJwcm8uZ292LmJyL2xjci9yYWl6aG9tLmNybDAd
+BgNVHQ4EFgQUtfP6QrSAZIeIicDPi2G3Af1Gdi4wDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAJenILQO0B7vSlNocewH
+0n/vgqeVT5+fuda+/GuQX+lN4wwR1E3+Hwq1IIVdTLPS6luRhvDkJkQ+rA65rJA8
++/1DZHAaz5qAajmkY3rzu2Vf5PGKfKqGIG7ejdYFQnQrURvX3LSlubb3odSQ6jYs
+4gEbhrnFTyAk5XmOm/QJ62ME7V3OqXOnEf3YyeX9fTKwvvTIhdBR1CNXjDGLhnly
+b8cLoRKwGKVQMdX9EsX8mYezOT600YBmVU0NNT95DeH6Zn4hZjgMPUI//3r1Jmxa
+f8YFOGMjwkNXNOY5t8ZTrrwBCrS8spJQ8DCO9l7wb1FzC2Gg5E3AdJW3mRky85vz
+qWA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBPMQswCQYDVQQGEwJCUjEM
+MAoGA1UEChMDSUNQMTIwMAYDVQQDEylBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEg
+UmFpeiBIb21vbG9nYWNhbzAeFw0wOTAxMDMxNjAwMDlaFw0yMDAxMDMxNjAwMDla
+MFgxCzAJBgNVBAYTAkJSMQwwCgYDVQQKEwNJQ1AxOzA5BgNVBAMTMkF1dG9yaWRh
+ZGUgQ2VydGlmaWNhZG9yYSBJbnRlcm1lZGlhcmlhIEhvbW9sb2dhY2FvMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6VtI2zmzIqaNBls8f7p70Cu2WopJ
+c647RzxkqgIOKhkk67/UEkKYm3ZY1YmK1Y1k3iIpU0+upzH2/ohCo+OOCGAoucsI
+2NWMOb7XRkY7eO9wtD+ErBul/3dGb7feWVnIo4CYoFKmui4VgedV0XlXQoyi1PRA
+2NG+oSMEYyBfwenBppgbHJtAo898eRnx7ZGR/hhdojSw5JXF9AIjUuX2PyjZIXDa
+b6iIsIQ8SB1yMuZOuqGKdHZg0KXTYjJBkAhkoGtSxB+ikIdjNX9vmkUYAYB0kkcr
+X/iIc39yW/dGispzliAGcqXL7XCHxZjkyqvRJhBMxqQ0HCfKMix0trKD+QIDAQAB
+o4GYMIGVMB0GA1UdDgQWBBTWARCTrzdL6Khlw/VGYhjxdqma0zAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAVBgNVHSAEDjAMMAoGBmBMAQKDRTAAMDwG
+A1UdHwQ1MDMwMaAvoC2GK2h0dHA6Ly9jY2Rob20uc2VycHJvLmdvdi5ici9sY3Iv
+cmFpemhvbS5jcmwwDQYJKoZIhvcNAQEFBQADggEBADrg4jMKCAMgrGB9xqIMDwjg
+Yk0/p4xnqcCI1rGPyLK9e4upvcS5pwoxrlxwCI1RNTFltqOEmaT0thh2yrnD1BIX
+UNvX/OVV+RFnf0jAmEJ+D2iIDz+YVb+rMYxo7C9Xz0kvSzuQfZW/TbMHoV5PWh87
+6uPykYcoAzDtm3+sPbKMSO5FIijdfTxSbPyezQ4D1gs6FHBULeCXLx2lteHr5YTA
+glG8C3S1eJfWjVdF/Z+waEOSJmNshGPOKtIqn4oYr48H36hwNJVs4e+twAJoYJy/
+Z26h2241MRpxXymhfnkdb8Wa7ciAki9+37Pta2rjRXzzcSnSxsNUpIFP62rpfGs=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEUzCCAzugAwIBAgIBBTANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJCUjEM
+MAoGA1UEChMDSUNQMTswOQYDVQQDEzJBdXRvcmlkYWRlIENlcnRpZmljYWRvcmEg
+SW50ZXJtZWRpYXJpYSBIb21vbG9nYWNhbzAeFw0wOTAyMTExNjMwMzhaFw0xMjAy
+MTExNjMwMzhaMIGHMQswCQYDVQQGEwJCUjETMBEGA1UEChMKSUNQLUJyYXNpbDEs
+MCoGA1UECxMjU2VjcmV0YXJpYSBkYSBSZWNlaXRhIEZlZGVyYWwgLSBTUkYxNTAz
+BgNVBAMTLEhPTUF1dG9yaWRhZGUgQ2VydGlmaWNhZG9yYSBkbyBTRVJQUk8gU1JG
+IHYyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxgxQn/v4kkJhrueW
+UcGRYwLN+6qC3gWD1rEpQK994Rmq5Ne7QJUsLasV9BLUT7Be5isEZucUBxr/aRIe
+UCcAbfpDAuOS8R9ZphxxX4UCUlOkIap1NZNoojbmI4dLhOSPcrTDIm2MGvpq93/p
+mvfpzz2iazYft8ZNXoxJx255EWvirWJGnv2WlYtiv7NOuj4fwb88dc4g6jSTw6eu
+HbpbNJ+MEs91eVioC4EPO1GrxJuAb9KFAISQxZoBRyQuQdOUMMY6XTg4SxizUFbZ
+/FdI8JD30unA8aE8hrTW/ACdsOSad5eRFNdWJ+jlz/7Ohc5aj69TR2KKy/TWnQXF
+IBx3eQIDAL7lo4H3MIH0MA4GA1UdDwEB/wQEAwIBBjBIBgNVHSAEQTA/MD0GBWBM
+AQIyMDQwMgYIKwYBBQUHAgEWJmh0dHA6Ly9jY2Rob20uc2VycHJvLmdvdi4vZG9j
+cy9kcGMucGRmMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jY2Rob20uc2VycHJv
+Lmdvdi5ici9sY3IvYWNpbnRlcm1lZGlhcmlhLmNybDAfBgNVHSMEGDAWgBTWARCT
+rzdL6Khlw/VGYhjxdqma0zAdBgNVHQ4EFgQUh4z1W51V52V8KRZMAx5UD/VbMa8w
+EgYDVR0TAQH/BAgwBgEB/wIBADANBgkqhkiG9w0BAQUFAAOCAQEAHo7RjG9nP+oV
+cLyLfQsMBY+M6OuIj+nVaRcd/tPxKuUXKMK+o7wEL3Qzc0j6p7F4ThbtDA1IFZBq
+BgULyVRIp5iQY26kXC85A/jIu/c6KfPQ02IByU89rlXjVVnHjMHO1BNfQDJMe+XJ
+XTpBSBp15+Y63him9o3qhKsQKWsZll2FhvuT4phOYFGvOULt693nJzqmcqMM37lg
+0m1Fhurrf3ngfQglpXuWFoU/3qV/7300Chs9YZG/sZn8/959INEp//s3Awovkmgy
+0GlL80gxFbbOh7oqaEAkbLZ2CgMKliwhlN0QtlBSG2bEOQgwRvyuQngTnJ/okERH
+EOonzgne4Q==
+-----END CERTIFICATE-----
Index: /trunk/seguranca/certificados.js
===================================================================
--- /trunk/seguranca/certificados.js	(revision 1035)
+++ /trunk/seguranca/certificados.js	(revision 1035)
@@ -0,0 +1,169 @@
+   var num = 0;
+   var titulo = '';
+   
+function msgWin(msg,w,h,params)
+	{
+		var winl = (screen.width - w ) / 2;
+		var wint = (screen.height - h) / 2;	
+		var parm = "width=" + w + ",height=" + h + ",top=" + wint + ",left=" + winl + params;
+		win3 = window.open("","12345" + num,parm); 
+		num = num + 1;				
+		win3.document.writeln(msg);
+		win3.focus();
+	}
+
+  function Um_Certificado(valor) 
+	{	
+		if(valor.length < 2) { return; }
+		//verifica se o browser tem suporte a ajax
+		try 
+			{
+				ajax = new ActiveXObject("Microsoft.XMLHTTP");
+			} 
+		catch(e) 
+			{
+				try 
+					{
+						ajax = new ActiveXObject("Msxml2.XMLHTTP");
+					}
+				catch(ex) 
+					{
+						try 
+							{
+								ajax = new XMLHttpRequest();
+							}
+						catch(exc) 
+							{
+								alert("Esse browser não tem recursos para uso do Ajax");
+								ajax = null;
+							}
+					}
+			}
+
+		//se tiver suporte ajax
+		if(ajax) 
+			{
+				titulo = valor;
+				ajax.open("POST", "certs_xml.php", true);
+				ajax.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
+				ajax.onreadystatechange = function() 
+											{
+												//enquanto estiver processando...emite a msg de carregando
+												//if(ajax.readyState == 1) 
+												//	{
+												//		//idOpcao.innerHTML = "Obtendo Certificados ...! ";   
+												//	}
+												//após ser processado - chama função processa_um_certificado que vai varrer os dados
+												if(ajax.readyState == 4 ) 
+													{
+														if(ajax.responseXML) 
+															{
+																processa_um_certificado(ajax.responseXML);
+															}
+														else 
+															{
+																//caso não seja um arquivo XML emite a mensagem abaixo
+																msg = 'N&atilde;o foi poss&iacute;vel obter dados do certificado.' + '<br/><br/><div align="center"><INPUT type="button" value="Fechar" onClick="window.close()">';
+																parms = ",scrollbars=1";
+																msgWin(msg,450,200,parms)
+															}
+													}
+											}
+				//passa o código do certificado desejado...
+				var params = "id="+valor;
+				ajax.send(params);
+			}
+	}
+      
+   function processa_um_certificado(obj)
+	{
+	        // Tab com tags que deve exibir sho o nome....
+	        var TBtags = new Array( "EMISSOR_CAMINHO_COMPLETO", "SUBJECT" , "CRLDISTRIBUTIONPOINTS" , "KEYUSAGE" );
+		//pega a tag certificado
+		var dataArray   = obj.getElementsByTagName("certificado");
+		//total de elementos contidos na tag 
+		if(dataArray.length > 0)
+			{
+				var novo = "<head><title>" + titulo + "</title></head><body><font size=2><h3 align=center ><font color=#0000EE>Dados do certificado</font></h3>";
+				//percorre o arquivo XML para extrair os dados
+				for(var i = 0 ; i < dataArray.length ; i++) 
+					{
+						var item = dataArray[i];
+						var cc    =  item.getElementsByTagName("*");
+						len = 0;
+						for(var j = 0 ; j < cc.length ; j++) 
+							{
+								//contéudo dos campos no arquivo XML
+								var tag = cc[j].nodeName
+								if(tag == "CA") continue; // skipa tag CA .... 
+								var xflag = 0;
+								for(var iz = 0;iz< TBtags.length;iz++)
+									{
+										if(TBtags[iz] == tag) xflag = 1;
+									}
+								 // Testa se deve exibir o valor da tag..
+								if(xflag ==1 )
+									{
+										var nome    =   "<b>" +tag +":</b> ";
+									}
+								else
+									{
+									        // Testa o browser para usar a propriedade  correta ...
+										if (navigator.userAgent.match('MSIE'))
+											{
+												var conteudo = cc[j].text;
+											}
+										else
+											{
+												var conteudo = cc[j].textContent;
+											}
+										
+										if(conteudo == "1") 
+											{
+												conteudo = "Sim.";
+											}
+											
+										if(conteudo == "") 
+											{
+												conteudo = "N&atilde;o.";
+											}	
+											
+										switch(tag)
+											{
+											
+												case "INICIO_VALIDADE":
+													{
+														var aux = conteudo.substr(0,4) + "/" + conteudo.substr(4,2) + "/" + conteudo.substr(6,2)  + "  -  " + conteudo.substr(8,2)  + ":" + conteudo.substr(10,2)  + ":" + conteudo.substr(12,2)  + " GMT";
+														conteudo = aux;
+														break;
+													}
+												case "FIM_VALIDADE":
+													{
+														var aux = conteudo.substr(0,4) + "/" + conteudo.substr(4,2) + "/" + conteudo.substr(6,2)  + "  -  " + conteudo.substr(8,2)  + ":" + conteudo.substr(10,2)  + ":" + conteudo.substr(12,2)  + " GMT";
+														conteudo = aux;
+														break;
+													}
+												default:
+													{
+														break;
+													}
+											}
+										var nome    =  "<b>" + tag +":</b> " + conteudo;
+									}
+								novo = novo + nome + '<br/>';
+								len = len + 24;
+							}
+					}
+				msg = novo + '<br/><br/><div align="center"><INPUT type="button" value="Fechar" onClick="window.close()"></font></body>';
+			}
+		else 
+			{
+				//caso o XML volte vazio, printa a mensagem abaixo
+				msg = 'N&atilde;o foi poss&iacute;vel obter dados do certificado.' + '<br/><br/><div align="center"><INPUT type="button" value="Fechar" onClick="window.close()"></font></body>';
+				len =200;
+			}
+		parms = ",scrollbars=1";
+		num = num + 1;				
+		msgWin(msg,450,len,parms)
+	}
+
Index: /trunk/expressoMail1_2/setup/phpgw_en.lang
===================================================================
--- /trunk/expressoMail1_2/setup/phpgw_en.lang	(revision 799)
+++ /trunk/expressoMail1_2/setup/phpgw_en.lang	(revision 1035)
@@ -14,4 +14,7 @@
 all	expressoMail1_2	en	all
 Also check message against next rule	expressoMail1_2	en	Also check message against next rule
+Always sign message digitally?	expressoMail1_2	en	Always sign message digitally?
+Always cipher message digitally?	expressoMail1_2	en	Always cipher message digitally?
+and	expressoMail1_2	en	and
 and save in	expressoMail1_2	en	and save in
 Answered	expressoMail1_2	en	Answered
@@ -21,4 +24,5 @@
 At %1, %2 hours, %3 wrote:	expressoMail1_2	en	At %1, %2 hours, %3 wrote:
 Auto save draft	expressoMail1_2	en	Auto save draft
+authentic	expressoMail1_2	en	authentic
 Back	expressoMail1_2	en	Back
 BCC	expressoMail1_2	en	BCC
@@ -33,4 +37,8 @@
 CC	expressoMail1_2	en	CC
 CCo	expressoMail1_2	en	CCo
+REVOKED Certificate.	expressoMail1_2	en	REVOKED Certificate.
+Certificate Authority: 	expressoMail1_2	en	Certificate Authority:
+Certificate email: 	expressoMail1_2	en	Certificate email:
+certificate has expired	expressoMail1_2	en	certificate has expired
 Change folder	expressoMail1_2	en	Change folder
 Choose a name	expressoMail1_2	en	Choose a name
@@ -44,4 +52,8 @@
 Command for unmark spam	admin	en	Command for unmark spam
 Config for ExpressoMail	expressoMail1_2	en	Config for ExpressoMail
+Couldn't verify if certificate was revoked.(CD-01)	expressoMail1_2	en	Couldn't verify if certificate was revoked.(CD-01)
+Couldn't verify if certificate was revoked.(CD-02)	expressoMail1_2	en	Couldn't verify if certificate was revoked.(CD-02)
+Couldn't verify if certificate was revoked.(CD-03)	expressoMail1_2	en	Couldn't verify if certificate was revoked.(CD-03)
+Crypted message	expressoMail1_2	en	Crypted message
 Cyrus IMAP Server	expressoMail1_2	en	Cyrus IMAP Server
 attachment	expressoMail1_2	en	attachment
@@ -59,4 +71,7 @@
 DISABLED	expressoMail1_2	en	DISABLED
 Disable	expressoMail1_2	en	Disable
+Details	expressoMail1_2	pt-br	Details
+Digitally sign message?	expressoMail1_2	en	Digitally sign message?
+Digitally crypt message?	expressoMail1_2	en	Digitally crypt message?
 Download all atachments	expressoMail1_2	en	Download all atachments
 Download manual	expressoMail1_2	en	Download manual
@@ -79,4 +94,5 @@
 ENABLED	expressoMail1_2	en	ENABLED
 Enable	expressoMail1_2	en	Enable
+Enable digitally sign/cipher the message?	expressoMail1_2	en	Enable digitally sign/cipher the message?
 Enable Quick Reply	expressoMail1_2	en	Enable Quick Reply
 Enter a name for the box	expressoMail1_2	en	Enter a name for the box
@@ -88,4 +104,10 @@
 Error in SMTP sending read confirmation.	expressoMail1_2	en	Error in SMTP sending read confirmation.
 Error moving message.	expressoMail1_2	en	Error moving message.
+Enable digitally sign/cipher the message?	expressoMail1_2	en	Enable digitally sign/cipher the message?
+#error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error	expressoMail1_2	en	#error:21075075:PKCS7 routines:PKCS7_verify:certificate verify error
+error:21075069:PKCS7 routines:PKCS7_verify:signature failure	expressoMail1_2	en	error:21075069:PKCS7 routines:PKCS7_verify:signature failure
+error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure	expressoMail1_2	en	error:21071065:PKCS7 routines:PKCS7_signatureVerify:digest failure
+error:21071065:PKCS7 routines:func(113):reason(101)	expressoMail1_2	en	error:21071065:PKCS7 routines:func(113):reason(101)
+error:21075069:PKCS7 routines:func(117):reason(105)	expressoMail1_2	en	error:21075069:PKCS7 routines:func(117):reason(105)
 Exclusion	expressoMail1_2	en	Exclusion
 Export	expressoMail1_2	en	Export
@@ -145,4 +167,5 @@
 Insert signature automatically in new messages?	expressoMail1_2	en	Insert signature automatically in new messages?
 insertunorderedlist	expressoMail1_2	en	Insert unordered list
+Invalid signature	expressoMail1_2	en	Invalid signature
 in this message	expressoMail1_2	en	in this message
 italic	expressoMail1_2	en	italic
@@ -169,4 +192,5 @@
 Loading	expressoMail1_2	en	Loading
 Mailbox Sharing	expressoMail1_2	en	Mailbox Sharing
+Mail from: 	expressoMail1_2	pt-br	Mail from:
 Manager your folders and export messages	expressoMail1_2	en	Manager your folders and export messages
 Mark as	expressoMail1_2	en	Mark as
@@ -176,4 +200,5 @@
 Medium	expressoMail1_2	en	Medium
 Message body	expressoMail1_2	en	Message body
+Message date: 	expressoMail1_2	pt-br	Message date:
 message	expressoMail1_2	en	message
 minute ago	expressoMail1_2	en	minute ago
@@ -183,8 +208,12 @@
 Message Header	expressoMail1_2	en	Message Header
 Message marked as 	expressoMail1_2	en	Message marked as 
+Message signed by: 	expressoMail1_2	pt-br	Message signed by:
+Message untouched	expressoMail1_2	pt-br	Message untouched
 message(s) deleted from your trash folder.	expressoMail1_2	en	message(s) deleted from your trash folder.
 messages	expressoMail1_2	en	messages
 messages found in folder:	expressoMail1_2	en	messages found in folder:
 Messages saved in %1 folder.	expressoMail1_2	en	Messages saved in %1 folder.
+#MSG010- Erro verificando Expiracao/CAs do certificado.	expressoMail1_2	en	#MSG010- Erro verificando Expiracao/CAs do certificado.
+#MSG011- Ocorreu erro validando o certificado.	expressoMail1_2	en	#MSG011- Ocorreu erro validando o certificado.
 More actions	expressoMail1_2	en	More actions
 More	expressoMail1_2	en	More
@@ -316,4 +345,5 @@
 The message was moved to folder 	expressoMail1_2	en	The message was moved to folder 
 The origin folder and the destination folder are the same.	expressoMail1_2	en	The origin folder and the destination folder are the same.
+The preference "%1" isn't enabled.	expressoMail1_2	en	The preference "%1" isn't enabled.
 There's an action processing. Do you want abort it?	expressoMail1_2	en	There's an action processing. Do you want abort it?
 The results were found in the Global Catalog	expressoMail1_2	en	The results were found in the Global Catalog
@@ -345,4 +375,5 @@
 User not registered	instant_messenger	en	User not registered
 Users	expressoMail1_2	en	Users
+Validity of certificate: 	expressoMail1_2	en	Validity of certificate:
 View HTML source	expressoMail1_2	en	View HTML source
 View tips	expressoMail1_2	en	View tips
@@ -353,4 +384,5 @@
 Who	expressoMail1_2	en	Who
 With all	expressoMail1_2	en	With all
+with signer different from sender	expressoMail1_2	en	with signer different from sender
 Without Quota	expressoMail1_2	en	Without Quota
 without save	expressoMail1_2	en	without save
Index: /trunk/expressoMail1_2/setup/tables_current.inc.php
===================================================================
--- /trunk/expressoMail1_2/setup/tables_current.inc.php	(revision 468)
+++ /trunk/expressoMail1_2/setup/tables_current.inc.php	(revision 1035)
@@ -19,4 +19,18 @@
 			'ix' => array(),
 			'uc' => array()
+		),
+        'phpgw_certificados' => array(
+            'fd' => array(
+                'email' => array( 'type' => 'varchar', 'precision' => 60, 'nullable' => false),
+                'chave_publica' => array( 'type' => 'text'),
+                'expirado' => array('type' => 'bool', 'default' => 'false'),
+                'revogado' => array('type' => 'bool', 'default' => 'false'),
+                'serialnumber' => array('type' => 'int', 'precision' => 8, 'nullable' => false),
+                'authoritykeyidentifier' => array( 'type' => 'text', 'nullable' => false),
+            ),
+            'pk' => array('email','serialnumber','authoritykeyidentifier'),
+            'fk' => array(),
+            'ix' => array(),
+            'uc' => array()
 		)
 	);
Index: /trunk/expressoMail1_2/setup/tables_update.inc.php
===================================================================
--- /trunk/expressoMail1_2/setup/tables_update.inc.php	(revision 1034)
+++ /trunk/expressoMail1_2/setup/tables_update.inc.php	(revision 1035)
@@ -12,6 +12,35 @@
 		$test[] = '1.233';
 		function expressoMail1_2_upgrade1_233() {
-			$setup_info['expressoMail1_2']['currentver'] = '1.234';
-			return $setup_info['expressoMail1_2']['currentver'];
+            $oProc = $GLOBALS['phpgw_setup']->oProc;
+            $oProc->CreateTable('phpgw_expressomail_contacts',array(
+				'fd' => array(
+					'id_owner' => array( 'type' => 'int', 'precision' => 8, 'nullable' => false),
+					'data' => array( 'type' => 'text')
+				),
+				'pk' => array('id_owner'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+
+            $oProc->CreateTable('phpgw_certificados',array(
+				'fd' => array(
+					'email' => array( 'type' => 'varchar', 'precision' => 60, 'nullable' => false),
+					'chave_publica' => array( 'type' => 'text'),
+					'expirado' => array('type' => 'bool', 'default' => 'false'),
+					'revogado' => array('type' => 'bool', 'default' => 'false'),
+					'serialnumber' => array('type' => 'int', 'precision' => 8, 'nullable' => false),
+					'authoritykeyidentifier' => array( 'type' => 'text', 'nullable' => false),
+				),
+				'pk' => array('email','serialnumber','authoritykeyidentifier'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+
+            $GLOBALS['setup_info']['expressoMail1_2']['currentver'] = '1.334';
+            return $GLOBALS['setup_info']['expressoMail1_2']['currentver'];
 		}
 	}	
@@ -53,9 +82,63 @@
 	if ($GLOBALS['setup_info']['expressoMail1_2']['currentver'] == '1.222'){
 		$test[] = '1.222';
-		function expressoMail1_2_upgrade1_222() {return expressoMail1_2_upgrade1_230();	}
+		function expressoMail1_2_upgrade1_222() {
+			$oProc = $GLOBALS['phpgw_setup']->oProc;
+			$oProc->CreateTable('phpgw_expressomail_contacts',array(
+				'fd' => array(
+					'id_owner' => array( 'type' => 'int', 'precision' => 8, 'nullable' => false),
+					'data' => array( 'type' => 'text')
+				),
+				'pk' => array('id_owner'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+			$oProc->CreateTable('phpgw_certificados',array(
+				'fd' => array(
+					'email' => array( 'type' => 'varchar', 'precision' => 60, 'nullable' => false),
+					'chave_publica' => array( 'type' => 'text'),
+					'expirado' => array('type' => 'bool', 'default' => 'false')
+				),
+				'pk' => array('email'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+			$GLOBALS['setup_info']['expressoMail1_2']['currentver'] = '1.223';
+			return $GLOBALS['setup_info']['expressoMail1_2']['currentver'];
+        }
 	}
 	if ($GLOBALS['setup_info']['expressoMail1_2']['currentver'] == '1.2211'){
 		$test[] = '1.2211';
-		function expressoMail1_2_upgrade1_2211() {return expressoMail1_2_upgrade1_230();}
+		function expressoMail1_2_upgrade1_2211() {
+			$oProc = $GLOBALS['phpgw_setup']->oProc;
+			$oProc->CreateTable('phpgw_expressomail_contacts',array(
+				'fd' => array(
+					'id_owner' => array( 'type' => 'int', 'precision' => 8, 'nullable' => false),
+					'data' => array( 'type' => 'text')
+				),
+				'pk' => array('id_owner'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+			$oProc->CreateTable('phpgw_certificados',array(
+				'fd' => array(
+					'email' => array( 'type' => 'varchar', 'precision' => 60, 'nullable' => false),
+					'chave_publica' => array( 'type' => 'text'),
+					'expirado' => array('type' => 'bool', 'default' => 'false')
+				),
+				'pk' => array('email'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+			$GLOBALS['setup_info']['expressoMail1_2']['currentver'] = '1.223';
+			return $GLOBALS['setup_info']['expressoMail1_2']['currentver'];
+        }
 	}
 	if ($GLOBALS['setup_info']['expressoMail1_2']['currentver'] == '1.2201'){
@@ -66,5 +149,32 @@
 	if ($GLOBALS['setup_info']['expressoMail1_2']['currentver'] == '1.2031'){
 		$test[] = '1.2031';
-		function expressoMail1_2_upgrade1_2031() {return expressoMail1_2_upgrade1_230();}
+		function expressoMail1_2_upgrade1_2031() {
+			$oProc = $GLOBALS['phpgw_setup']->oProc;
+			$oProc->CreateTable('phpgw_expressomail_contacts',array(
+				'fd' => array(
+					'id_owner' => array( 'type' => 'int', 'precision' => 8, 'nullable' => false),
+					'data' => array( 'type' => 'text')
+				),
+				'pk' => array('id_owner'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+			$oProc->CreateTable('phpgw_certificados',array(
+				'fd' => array(
+					'email' => array( 'type' => 'varchar', 'precision' => 60, 'nullable' => false),
+					'chave_publica' => array( 'type' => 'text'),
+					'expirado' => array('type' => 'bool', 'default' => 'false')
+				),
+				'pk' => array('email'),
+				'fk' => array(),
+				'ix' => array(),
+				'uc' => array()
+				)
+			);
+			$GLOBALS['setup_info']['expressoMail1_2']['currentver'] = '1.223';
+			return $GLOBALS['setup_info']['expressoMail1_2']['currentver'];
+        }
 	}	
 ?>
Index: /trunk/expressoMail1_2/setup/setup.inc.php
===================================================================
--- /trunk/expressoMail1_2/setup/setup.inc.php	(revision 1034)
+++ /trunk/expressoMail1_2/setup/setup.inc.php	(revision 1035)
@@ -12,7 +12,8 @@
 	$setup_info['expressoMail1_2']['name']      	= 'expressoMail1_2';
 	$setup_info['expressoMail1_2']['title']     	= 'ExpressoMail 1.2';
-	$setup_info['expressoMail1_2']['version']   	= '1.234';
+	$setup_info['expressoMail1_2']['version']   	= '1.334';
 	$setup_info['expressoMail1_2']['app_order'] 	= 2;
 	$setup_info['expressoMail1_2']['tables'][]		= 'phpgw_expressomail_contacts';
+    $setup_info['expressoMail1_2']['tables'][]		= 'phpgw_certificados';
 	$setup_info['expressoMail1_2']['enable']    	= 1;
 
Index: /trunk/expressoMail1_2/preferences.php
===================================================================
--- /trunk/expressoMail1_2/preferences.php	(revision 689)
+++ /trunk/expressoMail1_2/preferences.php	(revision 1035)
@@ -77,4 +77,37 @@
 		else
 			$GLOBALS['phpgw']->template->set_var('checked_auto_save_draft','');
+
+
+        if($GLOBALS['phpgw_info']['server']['use_assinar_criptografar'])
+		{
+		if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital_cripto'])
+			{
+			$GLOBALS['phpgw']->template->set_var('checked_use_signature_digital_cripto','checked');
+			$GLOBALS['phpgw']->template->set_var('display_digital','');
+			$GLOBALS['phpgw']->template->set_var('display_cripto','');
+			}
+		else
+			{
+			$GLOBALS['phpgw']->template->set_var('checked_use_signature_digital','');
+			$GLOBALS['phpgw']->template->set_var('display_digital','style="display: none;"');
+			$GLOBALS['phpgw']->template->set_var('display_cripto','style="display: none;"');
+			}
+
+		if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital'])
+			$GLOBALS['phpgw']->template->set_var('checked_use_signature_digital','checked');
+		else
+			$GLOBALS['phpgw']->template->set_var('checked_use_signature_digital','');
+		if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_cripto'])
+			$GLOBALS['phpgw']->template->set_var('checked_use_signature_cripto','checked');
+		else
+			$GLOBALS['phpgw']->template->set_var('checked_use_signature_cripto','');
+		}
+		else
+		{
+			$GLOBALS['phpgw']->template->set_var('display_digital','style="display: none;"');
+			$GLOBALS['phpgw']->template->set_var('display_cripto','style="display: none;"');
+			$GLOBALS['phpgw']->template->set_var('display_digital_cripto','style="display: none;"');
+		}
+
 
 		// Insert new expressoMail preference use_signature: defines if the signature will be automatically inserted
@@ -223,4 +256,19 @@
 			$GLOBALS['phpgw']->preferences->add('expressoMail','auto_save_draft',$_POST['auto_save_draft']);	
 
+        if($GLOBALS['phpgw_info']['server']['use_assinar_criptografar'])
+		{
+		if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital_cripto'])
+			$GLOBALS['phpgw']->preferences->change('expressoMail','use_signature_digital_cripto',$_POST['use_signature_digital_cripto']);
+		else
+			$GLOBALS['phpgw']->preferences->add('expressoMail','use_signature_digital_cripto',$_POST['use_signature_digital_cripto']);
+		if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital'])
+			$GLOBALS['phpgw']->preferences->change('expressoMail','use_signature_digital',$_POST['use_signature_digital']);
+		else
+			$GLOBALS['phpgw']->preferences->add('expressoMail','use_signature_digital',$_POST['use_signature_digital']);
+		if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_cripto'])
+			$GLOBALS['phpgw']->preferences->change('expressoMail','use_signature_cripto',$_POST['use_signature_cripto']);
+		else
+			$GLOBALS['phpgw']->preferences->add('expressoMail','use_signature_cripto',$_POST['use_signature_cripto']);
+		}
 		// Insert new expressoMail preference use_signature: defines if the signature will be automatically inserted
 		// at the e-mail body
@@ -312,9 +360,14 @@
 	$GLOBALS['phpgw']->template->set_var('lang_type_signature',lang('Signature type'));
 	$GLOBALS['phpgw']->template->set_var('big',lang('Big'));
+    //$GLOBALS['phpgw']->template->set_var('lang_use_signature_digital_cripto',lang('Possibilitar <b>assinar/criptografar</b> digitalmente a mensagem?'));
+	$GLOBALS['phpgw']->template->set_var('lang_use_signature_digital_cripto',lang('Enable digitally sign/cipher the message?'));
+	$GLOBALS['phpgw']->template->set_var('lang_use_signature_digital',lang('Always sign message digitally?'));
+	$GLOBALS['phpgw']->template->set_var('lang_use_signature_cripto',lang('Always cipher message digitally?'));
+	$GLOBALS['phpgw']->template->set_var('lang_use_signature',lang('Insert signature automatically in new messages?'));
+	$GLOBALS['phpgw']->template->set_var('lang_signature',lang('Signature'));
 	$GLOBALS['phpgw']->template->set_var('lang_Would_you_like_to_keep_archived_messages_?',lang('Would you like to keep archived messages?'));
 	$GLOBALS['phpgw']->template->set_var('lang_Yes',lang('Yes'));
 	$GLOBALS['phpgw']->template->set_var('lang_No',lang('No'));
 	$GLOBALS['phpgw']->template->set_var('lang_Would_you_like_to_use_local_messages_?',lang('Would you like to use local messages?'));
-	$GLOBALS['phpgw']->template->set_var('lang_use_signature',lang('Insert signature automatically in new messages?'));
 
 	$boemailadmin	= CreateObject('emailadmin.bo');
Index: /trunk/expressoMail1_2/inc/class.db_functions.inc.php
===================================================================
--- /trunk/expressoMail1_2/inc/class.db_functions.inc.php	(revision 906)
+++ /trunk/expressoMail1_2/inc/class.db_functions.inc.php	(revision 1035)
@@ -407,5 +407,71 @@
 		return $uiicalendar = $uiicalendar->import_from_mail($calendar);
 	}
-	
+
+    function insert_certificate($email,$certificate,$serialnumber,$authoritykeyidentifier=null)
+	{
+		if(!$email || !$certificate || !$serialnumber || !$authoritykeyidentifier)
+			return false;
+		// Insere uma chave publica na tabela phpgw_certificados.
+		$data = array	('email' => $email,
+						 'chave_publica' => $certificate,
+						 'serialnumber' => $serialnumber,
+						 'authoritykeyidentifier' => $authoritykeyidentifier);
+
+		if(!$this->db->insert('phpgw_certificados',$data,array(),__LINE__,__FILE__)){
+          	return $this->db->Error;
+        }
+    	return true;
+	}
+
+	function get_certificate($email=null)
+	{
+		if(!$email) return false;
+		$result = array();
+
+		$where = array ('email' => $email,
+						'revogado' => 0,
+						'expirado' => 0);
+
+ 		if(!$this->db->select('phpgw_certificados','chave_publica', $where, __LINE__,__FILE__))
+        {
+            $result['dberr1'] = $this->db->Error;
+            return $result;
+        }
+		$regs = array();
+		while($this->db->next_record())
+        {
+            $regs[] = $this->db->row();
+        }
+		if (count($regs) == 0)
+        {
+            $result['dberr2'] = ' Certificado nao localizado.';
+            return $result;
+        }
+		$result['certs'] = $regs;
+		return $result;
+	}
+
+	function update_certificate($serialnumber=null,$email=null,$authoritykeyidentifier,$expirado,$revogado)
+	{
+		if(!$email || !$serialnumber) return false;
+		if(!$expirado)
+			$expirado = 0;
+		if(!$revogado)
+			$revogado = 0;
+
+		$data = array	('expirado' => $expirado,
+						 'revogado' => $revogado);
+
+		$where = array	('email' => $email,
+						 'serialnumber' => $serialnumber,
+						 'authoritykeyidentifier' => $authoritykeyidentifier);
+
+		if(!$this->db->update('phpgw_certificados',$data,$where,__LINE__,__FILE__))
+		{
+			return $this->db->Error;
+		}
+		return true;
+	}
+
 }
 ?>
Index: /trunk/expressoMail1_2/inc/class.imap_functions.inc.php
===================================================================
--- /trunk/expressoMail1_2/inc/class.imap_functions.inc.php	(revision 1012)
+++ /trunk/expressoMail1_2/inc/class.imap_functions.inc.php	(revision 1035)
@@ -404,9 +404,18 @@
 		$body = ereg_replace("<a[^>]*href=[\'\"]mailto:([^\"\']+)[\'\"]>([^<]+)</a>","<a href=\"javascript:new_message_to('\\1')\">\\2</a>",$return_get_body['body']);
 
-		$return['body'] 		= $body;
-		$return['attachments'] 	= $return_get_body['attachments'];
-		$return['thumbs'] 		= $return_get_body['thumbs'];
-		$return['signature']	= $return_get_body['signature'];
-
+		if($return_get_body['body']=='isCripted'){
+			$exporteml = new ExportEml();
+			$return['source']=$exporteml->export_msg_data($msg_number,$msg_folder);
+			$return['body'] 		= "";
+			$return['attachments'] 	=  "";
+			$return['thumbs'] 		=  "";
+			$return['signature']	=  "";
+			//return $return;
+		}else{
+            $return['body'] 		= $body;
+            $return['attachments'] 	= $return_get_body['attachments'];
+            $return['thumbs'] 		= $return_get_body['thumbs'];
+            $return['signature']	= $return_get_body['signature'];
+        }
 		$pattern = '/^[ \t]*Disposition-Notification-To(^:)*:(.+)*@(.+)*$/isUm';
 		if (preg_match($pattern, $header_, $fields))
@@ -661,6 +670,16 @@
 		if(!$msg->structure[$msg_number]->parts) //Simple message, only 1 piece
 		{
+            if(strtolower($msg->structure[$msg_number]->subtype) == 'x-pkcs7-mime'){
+                $return['body']='isCripted';
+                return $return;
+            }
+
 			$attachment = array(); //No attachments
-			
+
+            if(strtolower($msg->structure[$msg_number]->subtype) == 'x-pkcs7-mime'){
+					$return['body']='isCripted';
+					return $return;
+			}
+
 			$content = '';
 			if (strtolower($msg->structure[$msg_number]->subtype) == "plain")
@@ -1007,7 +1026,12 @@
 
 	function get_signature($msg, $msg_number, $msg_folder)
-	{ 
+	{
+        include_once("../seguranca/classes/CertificadoB.php");
+		include_once("class.db_functions.inc.php");
 		foreach ($msg->file_type[$msg_number] as $index => $file_type)
 		{
+            $sign = array();
+			$temp = $this->get_info_head_msg($msg_number);
+			if($temp['ContentType'] =='normal') return $sign;
 			$file_type = strtolower($file_type);
 			if(strtolower($msg->encoding[$msg_number][$index]) == 'base64') 
@@ -1015,25 +1039,123 @@
 				if ($file_type == 'application/x-pkcs7-signature' || $file_type == 'application/pkcs7-signature') 
 				{
-					$export_mail = new ExportEml();
-					$params['folder'] = $msg_folder;
-					$params['msgs_to_export'] = $msg_number;
-				    $tempDir = ini_get("session.save_path");
-					$cert_file = $tempDir."/certificate_".base_convert(microtime(), 10, 36).".crt";					
-					$result = openssl_pkcs7_verify($export_mail->export_msg($params),PKCS7_NOVERIFY,$cert_file);
-					if (file_exists($cert_file))
+					if(!$this->mbox || !is_resource($this->mbox))
+					$this->mbox = $this->open_mbox($msg_folder);
+
+					$header = @imap_headerinfo($this->mbox, imap_msgno($this->mbox, $msg_number), 80, 255);
+
+					$imap_msg	 	= @imap_fetchheader($this->mbox, $msg_number, FT_UID);
+					$imap_msg		.= @imap_body($this->mbox, $msg_number, FT_UID);
+
+					$certificado = new certificadoB();
+					$validade = $certificado->verificar($imap_msg);
+
+					if ($certificado->apresentado)
 					{
-						$handle = fopen ($cert_file,"r");
-						$pemout = fread($handle,filesize($cert_file));
-						fclose($handle);
-						$cert=openssl_x509_parse($pemout);
-						$temp = "\\nSigned by: ".$cert[subject][CN];
-						$temp .= "\\nEmail Address: ".$cert[subject][emailAddress];
-						$temp .= "\\nCertificate issued by: ".$cert[issuer][CN]."\\n";
+						$from = $header->from;
+						foreach ($from as $id => $object) {
+							$fromname = $object->personal;
+						    $fromaddress = $object->mailbox . "@" . $object->host;
 					}
-				    /* Message verified */
-				    if ($result === true)
-					    $sign = $temp;
+						$sign_alert = '';
+						foreach ($certificado->erros_ssl as $item)
+						{
+							$check_error_msg = $this->functions->getLang($item);
+							/*
+							 * Desabilite o teste abaixo para mostrar todas as mensagem
+							 * de erro.
+							 */
+							//if (!strpos($check_error_msg,'*',strlen($check_error_msg-1)))
+							//{
+							$sign[] = "<span style=color:red>" . $check_error_msg . " </span>";
+							//}
+						}
+						if (count($certificado->erros_ssl) < 1)
+						{
+							$check_msg = $this->functions->getLang('Message untouched') . " ";
+							if($fromaddress == $certificado->dados['EMAIL'])
+							{
+								$check_msg .= $this->functions->getLang('and') . " ";
+								$check_msg .= $this->functions->getLang('authentic');
+							}
+							$sign[] = "<strong>".$check_msg."</strong>";
+						}
+						if($fromaddress != $certificado->dados['EMAIL'])
+						{
+							$sign[] = 	"<span style=color:red>" .
+										$this->functions->getLang('message') . " " .
+							        	$this->functions->getLang('with signer different from sender') .
+							        	" </span>";
+						}
+						$sign[] = "<strong>" . $this->functions->getLang('Message signed by: ') . "</strong>" . $certificado->dados['NOME'];
+						$sign[] = "<strong>" . $this->functions->getLang('Certificate email: ') . "</strong>" . $certificado->dados['EMAIL'];
+						$sign[] = "<strong>" . $this->functions->getLang('Mail from: ') . "</strong>" . $fromaddress;
+						$sign[] = "<strong>" . $this->functions->getLang('Certificate Authority: ') . "</strong>" . $certificado->dados['EMISSOR'];
+						$sign[] = "<strong>" . $this->functions->getLang('Validity of certificate: ') . "</strong>" . gmdate('r',openssl_to_timestamp($certificado->dados['FIM_VALIDADE']));
+						$sign[] = "<strong>" . $this->functions->getLang('Message date: ') . "</strong>" . $header->Date;
+
+					    $cert = openssl_x509_parse($certificado->cert_assinante);
+						/*
+						$sign[] = '<table>';
+						$sign[] = '<tr><td colspan=1><b>Expedido para:</b></td></tr>';
+						$sign[] = '<tr><td>Nome Comum (CN) </td><td>' . $cert[subject]['CN'] .  '</td></tr>';
+						$X = substr($certificado->dados['NASCIMENTO'] ,0,2) . '-' . substr($certificado->dados['NASCIMENTO'] ,2,2) . '-'  . substr($certificado->dados['NASCIMENTO'] ,4,4);
+						$sign[] = '<tr><td>Data de nascimento </td><td>' . $certificado->dados['NASCIMENTO'] .  '</td></tr>';
+						$sign[] = '<tr><td>CPF </td><td>' . $certificado->dados['CPF'] .  '</td></tr>';
+						$sign[] = '<tr><td>Documento identidade </td><td>' . $certificado->dados['RG'] .  '</td></tr>';
+						$sign[] = '<tr><td>Empresa (O) </td><td>' . $cert[subject]['O'] .  '</td></tr>';
+						$sign[] = '<tr><td>Unidade Organizacional (OU) </td><td>' . $cert[subject]['OU'][0] .  '</td></tr>';
+						//$sign[] = '<tr><td>Numero de serie </td><td>' . $cert['serialNumber'] .  '</td></tr>';
+						$sign[] = '<tr><td colspan=1> </td></tr>';
+						$sign[] = '<tr><td colspan=1><b>Expedido por:</b></td></tr>';
+						$sign[] = '<tr><td>Nome Comum (CN) </td><td>' . $cert[issuer]['CN'] .  '</td></tr>';
+						$sign[] = '<tr><td>Empresa (O) </td><td>' . $cert[issuer]['O'] .  '</td></tr>';
+						$sign[] = '<tr><td>Unidade Organizacional (OU) </td><td>' . $cert[issuer]['OU'][0] .  '</td></tr>';
+						$sign[] = '<tr><td colspan=1> </td></tr>';
+						$sign[] = '<tr><td colspan=1><b>Validade:</b></td></tr>';
+						$H = data_hora($cert[validFrom]);
+						$X = substr($H,6,2) . '-' . substr($H,4,2) . '-'  . substr($H,0,4);
+						$sign[] = '<tr><td>Expedido em </td><td>' . $X .  '</td></tr>';
+						$H = data_hora($cert[validTo]);
+						$X = substr($H,6,2) . '-' . substr($H,4,2) . '-'  . substr($H,0,4);
+						$sign[] = '<tr><td>Valido ate </td><td>' . $X .  '</td></tr>';
+						$sign[] = '<tr><td colspan=1> </td></tr>';
+						$sign[] = '</table>';
+						*/
+						$sign_alert .= 'Expedido para:\n';
+						$sign_alert .= 'Nome Comum (CN)  ' . $cert[subject]['CN'] .  '\n';
+						$X = substr($certificado->dados['NASCIMENTO'] ,0,2) . '-' . substr($certificado->dados['NASCIMENTO'] ,2,2) . '-'  . substr($certificado->dados['NASCIMENTO'] ,4,4);
+						$sign_alert .= 'Data de nascimento ' . $X .  '\n';
+						$sign_alert .= 'CPF ' . $certificado->dados['CPF'] .  '\n';
+						$sign_alert .= 'Documento identidade ' . $certificado->dados['RG'] .  '\n';
+						$sign_alert .= 'Empresa (O)  ' . $cert[subject]['O'] .  '\n';
+						$sign_alert .= 'Unidade Organizacional (OU) ' . $cert[subject]['OU'][0] .  '\n';
+						//$sign_alert[] = '<tr><td>Numero de serie </td><td>' . $cert['serialNumber'] .  '</td></tr>';
+						$sign_alert .= '\n';
+						$sign_alert .= 'Expedido por:\n';
+						$sign_alert .= 'Nome Comum (CN) ' . $cert[issuer]['CN'] . '\n';
+						$sign_alert .= 'Empresa (O)  ' . $cert[issuer]['O'] .  '\n';
+						$sign_alert .= 'Unidade Organizacional (OU) ' . $cert[issuer]['OU'][0] .  '\n';
+						$sign_alert .= '\n';
+						$sign_alert .= 'Validade:\n';
+						$H = data_hora($cert[validFrom]);
+						$X = substr($H,6,2) . '-' . substr($H,4,2) . '-'  . substr($H,0,4);
+						$sign_alert .= 'Expedido em ' . $X .  '\n';
+						$H = data_hora($cert[validTo]);
+						$X = substr($H,6,2) . '-' . substr($H,4,2) . '-'  . substr($H,0,4);
+						$sign_alert .= 'Valido ate ' . $X .  '\n';
+
+						$sign[] = "<a onclick=\"javascript:alert('" . $sign_alert . "')\"><b><font color=\"#0000FF\">".$this->functions->getLang("More")."...</font></b></a>";
+						$this->db = new db_functions();
+
+						// TODO: testar se existe um certificado no banco e verificar qual ï¿œ o mais atual.
+                        if(!$certificado->dados['EXPIRADO'] && !$certificado->dados['REVOGADO'] && count($certificado->erros_ssl) < 1)
+                            $this->db->insert_certificate(strtolower($certificado->dados['EMAIL']), $certificado->cert_assinante, $certificado->dados['SERIALNUMBER'], $certificado->dados['AUTHORITYKEYIDENTIFIER']);
+					}
 				     else
-					    $sign = "void";
+				    {
+				    	$sign[] = "<span style=color:red>" . $this->functions->getLang('Invalid signature') . "</span>";
+				    	foreach($certificado->erros_ssl as $item)
+				    	$sign[] = "<span style=color:red>" . $this->functions->getLang($item) . "</span>";
+                    }
 				}
 			}
@@ -1173,7 +1295,6 @@
 			* a perda em performance é insignificante.
 			*/
-			$flag = preg_match('/importance *: *(.*)\r/i',
-					@imap_fetchheader($this->mbox, imap_msgno($this->mbox, $msg_number))
-					,$importance);		
+            $tempHeader = @imap_fetchheader($this->mbox, imap_msgno($this->mbox, $msg_number));
+			$flag = preg_match('/importance *: *(.*)\r/i', $tempHeader, $importance);
 			$return[$i]['Importance'] = $flag==0?"Normal":$importance[1];
 			
@@ -1186,4 +1307,6 @@
 			
 			$return[$i]['msg_folder']	= $folder;
+            // Atribui o tipo (normal, signature ou cipher) ao campo Content-Type
+            $return[$i]['ContentType']  = $this->getMessageType($msg_number, $tempHeader);
 			$return[$i]['Recent']		= $header->Recent;
 			$return[$i]['Unseen']		= $header->Unseen;
@@ -1236,4 +1359,28 @@
 	}
 
+     /**
+     * Método que faz a verificação do Content-Type do e-mail e verifica se é um e-mail normal,
+     * assinado ou cifrado.
+     * @author Mário César Kolling <mario.kolling@serpro.gov.br>
+     * @param $headers Uma String contendo os Headers do e-mail retornados pela função imap_imap_fetchheader
+     * @param $msg_number O número da mesagem
+     * @return Retorna o tipo da mensagem (normal, signature, cipher).
+     */
+    function getMessageType($msg_number, $headers = false){
+
+            $contentType = "normal";
+            if (!$headers){
+                $headers = imap_fetchheader($this->mbox, imap_msgno($this->mbox, $msg_number));
+            }
+            //$header2 = imap_fetchheader($this->mbox, imap_msgno($this->mbox, $msg_number));
+            if (preg_match("/Content-Type:.*pkcs7-signature/i", $headers) == 1){
+                $contentType = "signature";
+            } else if (preg_match("/Content-Type:.*x-pkcs7-mime/i", $headers) == 1){
+                $contentType = "cipher";
+            }
+
+            return $contentType;
+    }
+
 	function get_folders_list($params = null)
 	{
@@ -1248,12 +1395,18 @@
 		if (is_array($folders_list)) {
   			reset($folders_list);
+            $this->ldap = new ldap_functions();
 			
 			$i = 0;
   			while (list($key, $val) = each($folders_list)) {
   				$status = imap_status($mbox_stream, $val->name, SA_UNSEEN);
-  				$result[$i]['folder_unseen'] = $status->unseen;
-			
+
   				//$tmp_folder_id = explode("}", imap_utf7_decode($val->name));
   				$tmp_folder_id = explode("}", mb_convert_encoding($val->name, "ISO_8859-1", "UTF7-IMAP" ));
+                if($tmp_folder_id[1]=='INBOX'.$this->imap_delimiter.'decifradas'){
+                    //error_log('passou', 3,'/tmp/imap_get_list.log');
+                    //imap_deletemailbox($mbox_stream,imap_utf7_encode("{".$this->imap_server."}".'INBOX/decifradas'));
+                    continue;
+                }
+                $result[$i]['folder_unseen'] = $status->unseen;
   				$folder_id = $tmp_folder_id[1];
 				$result[$i]['folder_id'] = $folder_id;
@@ -1263,5 +1416,5 @@
 				$result[$i]['folder_name'] = $result[$i]['folder_name'] == 'INBOX' ? 'Inbox' : $result[$i]['folder_name'];
 				if (is_numeric($result[$i]['folder_name']))	{
-					$this->ldap = new ldap_functions();
+					//$this->ldap = new ldap_functions();
 					if ($cn = $this->ldap->uid2cn($result[$i]['folder_name'])){
 						$result[$i]['folder_name'] = $cn;
@@ -1428,5 +1581,47 @@
 		$return_receipt = $params['input_return_receipt'];
 		$is_important = $params['input_important_message'];
-		$body = $params['body'];
+        $encrypt = $params['input_return_cripto'];
+		$signed = $params['input_return_digital'];
+
+		if($params['smime'])
+        {
+            $body = $params['smime'];
+            $mail->SMIME = true;
+            // A MSG assinada deve ser testada neste ponto.
+            // Testar o certificado e a integridade da msg....
+            include_once("../seguranca/classes/CertificadoB.php");
+            $erros_acumulados = '';
+            $certificado = new certificadoB();
+            $validade = $certificado->verificar($body);
+            if(!$validade)
+            {
+                foreach($certificado->erros_ssl as $linha_erro)
+                {
+                    $erros_acumulados .= $linha_erro;
+                }
+            }
+            else
+            {
+                // Testa o CERTIFICADO: se o CPF  he o do usuario logado, se  pode assinar msgs e se  nao esta expirado...
+                if ($certificado->apresentado)
+                {
+                    if($certificado->dados['EXPIRADO']) $erros_acumulados .='Certificado expirado.';
+                    if($certificado->dados['CPF'] != $this->username) $erros_acumulados .=' CPF no certificado diferente do logado no expresso.';
+                    if(!($certificado->dados['KEYUSAGE']['digitalSignature'] && $certificado->dados['EXTKEYUSAGE']['emailProtection'])) $erros_acumulados .=' Certificado nao permite assinar mensagens.';
+                }
+                else
+                {
+                    $$erros_acumulados .= 'Nao foi possivel usar o certificado para assinar a msg';
+                }
+            }
+            if(!$erros_acumulados =='')
+            {
+                return $erros_acumulados;
+            }
+        }
+        else
+        {
+            $body = $params['body'];
+        }
 		//echo "<script language=\"javascript\">javascript:alert('".$body."');</script>";
 		$attachments = $params['FILES'];
@@ -1447,6 +1642,13 @@
 ////////////////////////////////////////////////////////////////////////////////////////////////////
 		$mail->SMTPDebug = false;
-				
-		$mail->IsSMTP();
+
+		if($signed && !$params['smime'])
+		{
+            $mail->Mailer = "smime";
+			$mail->SignedBody = true;
+		}
+		else
+            $mail->IsSMTP();
+            
 		$mail->Host = $_SESSION['phpgw_info']['expressomail']['email_server']['smtpServer'];
 		$mail->Port = $_SESSION['phpgw_info']['expressomail']['email_server']['smtpPort'];
@@ -1465,5 +1667,97 @@
 		$mail->Subject = $subject;
 		$mail->IsHTML(true);
-		$mail->Body = $params['body'];
+		$mail->Body = $body;
+
+        if (($encrypt && $signed && $params['smime']) || ($encrypt && !$signed))	// a msg deve ser enviada cifrada...
+		{
+			$email = $this->add_recipients_cert($toaddress . ',' . $ccaddress. ',' .$ccoaddress);
+            $email = explode(",",$email);
+            // Deve ser testado se foram obtidos os certificados de todos os destinatarios.
+            // Deve ser verificado um numero limite de destinatarios.
+            // Deve ser verificado se os certificados sao validos.
+            // Se uma das verificacoes falhar, nao enviar o e-mail e avisar o usuario.
+            // O array $mail->Certs_crypt soh deve ser preenchido se os certificados passarem nas verificacoes.
+            $numero_maximo = $_SESSION['phpgw_info']['user']['preferences']['expressoMail']['num_max_certs_to_cipher'];  // Este valor dever ser configurado pelo administrador do site ....
+            $erros_acumulados = "";
+            $aux_mails = array();
+            $mail_list = array();
+            if(count($email) > $numero_maximo)
+            {
+                $erros_acumulados .= "Excedido o numero maximo (" . $numero_maximo . ") de destinatarios para uma msg cifrada...." . chr(0x0A);
+                return $erros_acumulados;
+            }
+            // adiciona o email do remetente. eh para cifrar a msg para ele tambem. Assim vai poder visualizar a msg na pasta enviados..
+            $email[] = $_SESSION['phpgw_info']['expressomail']['user']['email'];
+            foreach($email as $item)
+            {
+                $certificate = $db->get_certificate(strtolower($item));
+                if(!$certificate)
+                {
+                    $erros_acumulados .= "Chamada com parametro invalido.  e-Mail nao pode ser vazio." . chr(0x0A);
+                    return $erros_acumulados;
+                }
+
+                if (array_key_exists("dberr1", $certificate))
+                {
+
+                    $erros_acumulados .= "Ocorreu um erro quando pesquisava certificados dos destinatarios para cifrar a msg." . chr(0x0A);
+                    return $erros_acumulados;
+				}
+                if (array_key_exists("dberr2", $certificate))
+                {
+                    $erros_acumulados .=  $item . ' : Nao  pode cifrar a msg. Certificado nao localizado.' . chr(0x0A);
+                    //continue;
+                }
+			/*  Retirado este teste para evitar mensagem de erro duplicada.
+                if (!array_key_exists("certs", $certificate))
+              	{
+               		$erros_acumulados .=  $item . ' : Nao  pode cifrar a msg. Certificado nao localizado.' . chr(0x0A);
+                    continue;
+                }
+            */
+                include_once("../seguranca/classes/CertificadoB.php");
+
+                foreach ($certificate['certs'] as $registro)
+                {
+                    $c1 = new certificadoB();
+                    $c1->certificado($registro['chave_publica']);
+                    if ($c1->apresentado)
+                    {
+                        $c2 = new Verifica_Certificado($c1->dados,$registro['chave_publica']);
+                        if (!$c1->dados['EXPIRADO'] && !$c2->revogado && $c2->status)
+                        {
+                            $aux_mails[] = $registro['chave_publica'];
+                            $mail_list[] = strtolower($item);
+                        }
+                        else
+                        {
+                            if ($c1->dados['EXPIRADO'] || $c2->revogado)
+                            {
+                                $db->update_certificate($c1->dados['SERIALNUMBER'],$c1->dados['EMAIL'],$c1->dados['AUTHORITYKEYIDENTIFIER'],
+                                    $c1->dados['EXPIRADO'],$c2->revogado);
+                            }
+
+                            $erros_acumulados .= $item . ':  ' . $c2->msgerro . chr(0x0A);
+                            foreach($c2->erros_ssl as $linha)
+                            {
+                                $erros_acumulados .=  $linha . chr(0x0A);
+                            }
+                            $erros_acumulados .=  'Emissor: ' . $c1->dados['EMISSOR'] . chr(0x0A);
+                            $erros_acumulados .=  $c1->dados['CRLDISTRIBUTIONPOINTS'] . chr(0x0A);
+                        }
+                    }
+                    else
+                    {
+                        $erros_acumulados .= $item . ' : Nao  pode cifrar a msg. Certificado invalido.' . chr(0x0A);
+                    }
+                }
+            	if(!(in_array(strtolower($item),$mail_list)) && !empty($erros_acumulados))
+				{
+					return $erros_acumulados;
+        		}
+            }
+
+            $mail->Certs_crypt = $aux_mails;
+        }
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1589,4 +1883,8 @@
 		else
 		{
+            if ($signed && !$params['smime'])
+			{
+				return $sent;
+			}
 			if($_SESSION['phpgw_info']['server']['expressomail']['expressoMail_enable_log_messages'] == "True") 
 			{
@@ -1606,4 +1904,24 @@
    			return array("success" => true);
 		}
+	}
+
+    function add_recipients_cert($full_address)
+	{
+		$result = "";
+		$parse_address = imap_rfc822_parse_adrlist($full_address, "");
+		foreach ($parse_address as $val)
+		{
+			//echo "<script language=\"javascript\">javascript:alert('".$val->mailbox."@".$val->host."');</script>";
+			if ($val->mailbox == "INVALID_ADDRESS")
+				continue;
+			if ($val->mailbox == "UNEXPECTED_DATA_AFTER_ADDRESS")
+				continue;
+			if (empty($val->personal))
+				$result .= $val->mailbox."@".$val->host . ",";
+			else
+				$result .= $val->mailbox."@".$val->host . ",";
+		}
+
+		return substr($result,0,-1);
 	}
 
@@ -2367,5 +2685,5 @@
 			$folder_id = "INBOX";
 		
-		if(!$this->mbox)
+		if(!$this->mbox || !is_resource($this->mbox))
 			$this->mbox = $this->open_mbox();
 
@@ -2958,4 +3276,51 @@
     }
 
+    function show_decript($params){
+        $source = $params['source'];
+        //error_log("source: $source\nversao: " . PHP_VERSION, 3, '/tmp/teste.log');
+        $source = str_replace(" ", "+", $source,$i);
+        
+        if (version_compare(PHP_VERSION, '5.2.0', '>=')){
+            if(!$source = base64_decode($source,true))
+                return "error ".$source."Espaços ".$i;
+
+        }
+        else {
+            if(!$source = base64_decode($source))
+                return "error ".$source."Espaços ".$i;
+        }
+
+        $insert = $this->insert_email($source,'INBOX'.$this->imap_delimiter.'decifradas');
+
+		$get['msg_number'] = $insert['msg_no'];
+		$get['msg_folder'] = 'INBOX'.$this->imap_delimiter.'decifradas';
+		$return = $this->get_info_msg($get);
+		$get['msg_number'] = $params['ID'];
+		$get['msg_folder'] = $params['folder'];
+		$tmp = $this->get_info_msg($get);
+		if(!$tmp['status_get_msg_info'])
+		{
+			$return['msg_day']=$tmp['msg_day'];
+			$return['msg_hour']=$tmp['msg_hour'];
+			$return['fulldate']=$tmp['fulldate'];
+			$return['smalldate']=$tmp['smalldate'];
+		}
+		else
+		{
+			$return['msg_day']='';
+			$return['msg_hour']='';
+			$return['fulldate']='';
+			$return['smalldate']='';
+		}
+        $return['msg_no'] =$insert['msg_no'];
+        $return['error'] = $insert['error'];
+        $return['folder'] = $params['folder'];
+        //$return['acls'] = $insert['acls'];
+        $return['original_ID'] =  $params['ID'];
+
+        return $return;
+
+    }
+    
 //Por Bruno Costa(bruno.vieira-costa@serpro.gov.br - Trata fontes de emails enviados via POST para o servidor por um xmlhttprequest, as partes codificados com
 //Base64 os "+" são substituidos por " " no envio e essa função arruma esse efeito.
Index: /trunk/expressoMail1_2/inc/class.exporteml.inc.php
===================================================================
--- /trunk/expressoMail1_2/inc/class.exporteml.inc.php	(revision 1000)
+++ /trunk/expressoMail1_2/inc/class.exporteml.inc.php	(revision 1035)
@@ -242,4 +242,18 @@
 		imap_close($this->mbox_stream);
 		return $tempDir.'/'.$file;
+	}
+
+    function export_msg_data($id_msg,$folder) {
+		$this->folder = $folder;
+		$this->folder = mb_convert_encoding($this->folder, "UTF7-IMAP","UTF-8");
+
+		$this->connectImap();
+		$header	 	= $this-> getHeader($id_msg);
+		$body		= $this-> getBody($id_msg);
+
+		$msg_data = $header ."\r\n\r\n". $body;
+
+		imap_close($this->mbox_stream);
+		return $msg_data;
 	}
 
Index: /trunk/expressoMail1_2/inc/class.phpmailer.php
===================================================================
--- /trunk/expressoMail1_2/inc/class.phpmailer.php	(revision 614)
+++ /trunk/expressoMail1_2/inc/class.phpmailer.php	(revision 1035)
@@ -101,4 +101,19 @@
 
     /**
+     * Sets the signed body of the message.  This automatically sets the
+     * email to multipart/signed.
+     * @var string
+     */
+    var $SignedBody           = false;
+    var $SMIME          	= false;
+    var $Certs_crypt		= array();
+    /**
+     * Sets the encrypted body of the message.  This automatically sets the
+     * email to multipart/encript.
+     * @var string
+     */
+    var $CryptedBody           = "";
+
+    /**
      * Sets word wrapping on the body of the message to a given number of 
      * characters.
@@ -148,4 +163,6 @@
 	var $SaveMessageInFolder = "";
 	var $SaveMessageAsDraft = "";
+
+    var $xMailer           = "";
 
     /////////////////////////////////////////////////
@@ -372,11 +389,22 @@
         $this->SetMessageType();
         $header .= $this->CreateHeader();
-        $body = $this->CreateBody();
-		
-        if($body == "") { return false; }
+
+        if ($this->SMIME == false)
+        {
+            $body = $this->CreateBody();
+            if($body == "")
+            {
+                return false;
+            }
+        }
 		
         // Choose the mailer
         switch($this->Mailer)
         {
+            // Usado para processar o email e retornar para a applet
+        	case "smime":
+                $retorno['body'] = $header.$this->LE.$body;
+                $retorno['type'] =  $this->write_message_type();
+        		return $retorno;
             case "sendmail":
                 $result = $this->SendmailSend($header, $body);
@@ -473,8 +501,15 @@
         include_once($this->PluginDir . "class.smtp.php");
         $error = "";
+
         $bad_rcpt = array();
-
+        $errorx = '';
         if(!$this->SmtpConnect())
             return false;
+
+        if($this->SMIME)
+        {
+            $header='';
+            $body = $this->Body;
+        }
 
         $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender;
@@ -490,17 +525,43 @@
         for($i = 0; $i < count($this->to); $i++)
         {
-            if(!$this->smtp->Recipient($this->to[$i][0]))
-                $bad_rcpt[] = $this->to[$i][0];
+            if($this->valEm($this->to[$i][0]))
+            {
+                if(!$this->smtp->Recipient($this->to[$i][0]))  $bad_rcpt[] = $this->to[$i][0];
+            }
+            else
+            {
+                $errorx .= $this->to[$i][0] . ', ';
+            }
         }
         for($i = 0; $i < count($this->cc); $i++)
         {
-            if(!$this->smtp->Recipient($this->cc[$i][0]))
-                $bad_rcpt[] = $this->cc[$i][0];
+            if($this->valEm($this->cc[$i][0]))
+            {
+                if(!$this->smtp->Recipient($this->cc[$i][0])) $bad_rcpt[] = $this->cc[$i][0];
+            }
+			else
+            {
+                $errorx .= $this->cc[$i][0] . ', ';
+            }
         }
         for($i = 0; $i < count($this->bcc); $i++)
         {
-            if(!$this->smtp->Recipient($this->bcc[$i][0]))
-                $bad_rcpt[] = $this->bcc[$i][0];
-        }
+            if($this->valEm($this->bcc[$i][0]))
+            {
+                if(!$this->smtp->Recipient($this->bcc[$i][0])) $bad_rcpt[] = $this->bcc[$i][0];
+            }
+			else
+            {
+                $errorx .= $this->bcc[$i][0] . ', ';
+            }
+        }
+        if($errorx != '')
+		{
+			$error = $errorx;
+			$error = $this->Lang("recipients_failed")  . '  ' . $errorx;
+			$this->SetError($error);
+			$this->smtp->Reset();
+			return false;
+		}
 
         if(count($bad_rcpt) > 0) // Create error message
@@ -524,5 +585,93 @@
             return false;
         }
+
+        // Vai verificar se deve cifrar a msg ......
+        if(count($this->Certs_crypt) > 0)
+		{
+            // Vai cifrar a msg antes de enviar ......
+			include_once("../seguranca/classes/CertificadoB.php");
+
+            $teste1 = array();
+            $aux_cifra1 = $header . $body;
+
+            // Início relocação dos headers
+            // Esta relocação dos headers podem causar problemas.
+
+            $match = 0;
+            $pattern = '/^Disposition\-Notification\-To:.*\n/m';
+            $match = preg_match($pattern, $aux_cifra1, $teste1);
+
+            if (!empty($match)){
+                $aux_cifra1 = preg_replace($pattern, '', $aux_cifra1, 1); // retira o Disposition-Notification-To
+
+                $match = 0;
+                $teste2 = array();
+                $pattern = '/^MIME\-Version:.*\n/m';
+                $match = preg_match($pattern, $aux_cifra1, $teste2);
+                $aux_cifra1 = preg_replace($pattern, $teste1[0].$teste2[0], $aux_cifra1, 1); // Adiciona Disposition-Notification-To logo acima de MIME-Version
+
+            }
+            // Fim relocação dos headers
+
+           // Vai partir em duas partes a msg.  A primeira parte he a dos headers, e a segunda vai ser criptografada ...
+            $pos_content_type = strpos($aux_cifra1,'Content-Type:');
+            $pos_MIME_Version = strpos($aux_cifra1,'MIME-Version: 1.0' . chr(0x0D) . chr(0x0A));
+            $valx_len = 19;
+            if($pos_MIME_Version === False)
+		    {
+                $pos_MIME_Version = strpos($aux_cifra1,'MIME-Version: 1.0' . chr(0x0A));
+                $valx_len = 18;
+		    }
+
+            if($pos_MIME_Version >= $pos_content_type)
+            {
+                // nao deve enviar a msg..... O header MIME-Version com posicao invalida ......
+                $this->SetError('Formato dos headers da msg estao invalidos.(CD-17) - A');
+                $this->smtp->Reset();
+                return false;
+            }
+
+            $aux_cifra2 = array();
+            $aux_cifra2[] = substr($aux_cifra1,0,$pos_MIME_Version - 1);
+            $aux_cifra2[] = substr($aux_cifra1,$pos_MIME_Version + $valx_len);
+
+               /*
+			// este explode pode ser fonte de problemas .......
+			$aux_cifra2 = explode('MIME-Version: 1.0' . chr(0x0A), $aux_cifra1);
+			// Pode ocorrer um erro se nao tiver o header MIME-Version .....
+			if(count($aux_cifra2)  != 2 )
+				{
+					$aux_cifra2 = explode('MIME-Version: 1.0' . chr(0x0D) . chr(0x0A), $aux_cifra1);
+					if(count($aux_cifra2)  != 2 )
+						{
+							// nao deve enviar a msg..... nao tem o header MIME-Version ......
+							$this->SetError('Formato dos headers da msg estao invalidos.(CD-17) - ' . count($aux_cifra2));
+							$this->smtp->Reset();
+							return false;
+						}
+				}
+                */
+			$certificado = new certificadoB();
+			$h = array();
+			$aux_body = $certificado->encriptar($aux_cifra2[1], $this->Certs_crypt, $h);
+			if(!$aux_body)
+            {
+                $this->SetError('Ocorreu um erro. A msg nao foi enviada. (CD-18)');
+                $this->smtp->Reset();
+                return false;
+            }
+			// salvar sem cifra......
+			//$smtpSent = $this->smtp->Data($aux_cifra2[0] . $aux_body);
+
+			// salva a msg sifrada. neste caso deve ter sido adicionado o certificado do autor da msg......
+			$header = $aux_cifra2[0];
+			$body = $aux_body;
         $smtpSent = $this->smtp->Data($header . $body);
+        }
+        else
+		{
+			$smtpSent = $this->smtp->Data($header . $body);
+		}
+
         if(!$smtpSent)
         {
@@ -563,7 +712,8 @@
 				$header = substr($header, 0, $target) . $this->AddrAppend("Bcc", $this->bcc) . substr($header, $target);
 			}
-		
-			$new_header = str_replace("\n", "\r\n", $header);
-			$new_body = str_replace("\n", "\r\n", $body);
+            $new_headerx = str_replace(chr(0x0A),chr(0x0D).chr(0x0A), $header);
+			$new_bodyx = str_replace(chr(0x0A),chr(0x0D).chr(0x0A), $body);
+			$new_header = str_replace(chr(0x0D).chr(0x0D).chr(0x0A), chr(0x0D).chr(0x0A),$new_headerx);
+			$new_body = str_replace(chr(0x0D).chr(0x0D).chr(0x0A), chr(0x0D).chr(0x0A), $new_bodyx);
 			
 			if ($this->SaveMessageAsDraft){
@@ -576,4 +726,32 @@
         
         return $smtpSent;
+    }
+
+    function valEm($email)
+    {
+        $mail_retorno = FALSE;
+        if ((strlen($email) >= 6) && (substr_count($email,"@") == 1) && (substr($email,0,1) != "@") && (substr($email,strlen($email)-1,1) != "@"))
+        {
+            if ((!strstr($email,"'")) && (!strstr($email,"\"")) && (!strstr($email,"\\")) && (!strstr($email,"\$")) && (!strstr($email," ")))
+            {
+                //testa se tem caracter .
+                if (substr_count($email,".")>= 1)
+                {
+                    //obtem a terminação do dominio
+                    $term_dom = substr(strrchr ($email, '.'),1);
+                    //verifica se terminação do dominio esta correcta
+                    if (strlen($term_dom)>1 && strlen($term_dom)<5 && (!strstr($term_dom,"@")) )
+                    {
+                        $antes_dom = substr($email,0,strlen($email) - strlen($term_dom) - 1);
+                        $caracter_ult = substr($antes_dom,strlen($antes_dom)-1,1);
+                        if ($caracter_ult != "@" && $caracter_ult != ".")
+                        {
+                            $mail_retorno = TRUE;
+                        }
+                    }
+                }
+            }
+        }
+        return $mail_retorno;
     }
 
@@ -885,4 +1063,16 @@
         $result .= $this->HeaderLine("MIME-Version", "1.0");
 
+        $result .= $this->write_message_type();
+
+        if($this->Mailer != "mail")
+            $result .= $this->LE.$this->LE;
+
+        return $result;
+    }
+
+
+    function write_message_type()
+	{
+		$result = "";
         switch($this->message_type)
         {
@@ -891,5 +1081,5 @@
                 $result .= sprintf("Content-Type: %s; charset=\"%s\"",
                                     $this->ContentType, $this->CharSet);
-                break;
+                return $result;
             case "attachments":
                 // fall through
@@ -906,9 +1096,9 @@
                     $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
                 }
-                break;
+                return $result;
             case "alt":
                 $result .= $this->HeaderLine("Content-Type", "multipart/alternative;");
                 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
-                break;
+                return $result;
         }
 
Index: /trunk/expressoMail1_2/inc/hook_settings.inc.php
===================================================================
--- /trunk/expressoMail1_2/inc/hook_settings.inc.php	(revision 1005)
+++ /trunk/expressoMail1_2/inc/hook_settings.inc.php	(revision 1035)
@@ -13,4 +13,47 @@
 $type = $_GET['type']; // FIX ME
 
+//if ($type == 'user' || $type == ''){
+create_html_code('<script language="JavaScript" type="text/javascript">
+function exibir_ocultar()
+{
+    var type = ("'.$type.'" == "") ? "user" : "'.$type.'";
+    var use_signature_digital_cripto = document.getElementsByName(type+"[use_signature_digital_cripto]")[0];
+    var default_signature_digital_cripto = "'.$GLOBALS['phpgw_info']['default']['preferences']['expressoMail']['use_signature_digital_cripto'].'";
+
+    if (use_signature_digital_cripto)
+    {
+        var element_signature_digital = document.getElementById(type+"[use_signature_digital]");
+        var element_signature_cripto = document.getElementById(type+"[use_signature_cripto]");
+
+        switch (use_signature_digital_cripto[use_signature_digital_cripto.selectedIndex].value){
+
+            case "1":
+                element_signature_digital.style.display="";
+                element_signature_cripto.style.display="";
+                break;
+            case "0":
+                element_signature_digital.style.display="none";
+                element_signature_cripto.style.display="none";
+                break;
+            case "":
+                if (default_signature_digital_cripto){
+                    element_signature_digital.style.display="";
+                    element_signature_cripto.style.display="";
+                 }
+                 else
+                 {
+                    element_signature_digital.style.display="none";
+                    element_signature_cripto.style.display="none";
+                 }
+
+        }
+
+    }
+
+}
+
+</script>');
+//}
+
 $default = array(
 	'25'	=> '25',
@@ -20,7 +63,7 @@
 );
 
-create_select_box(lang('What is the maximum number of messages per page?'),'max_email_per_page',$default,
+create_select_box('What is the maximum number of messages per page?','max_email_per_page',$default,
 	'What is the maximum number of messages per page?');
-create_check_box(lang('Save deleted messages in trash folder?'),'save_deleted_msg','Save deleted messages in trash folder?');
+create_check_box('Save deleted messages in trash folder?','save_deleted_msg','Save deleted messages in trash folder?');
 $default = array(
 	'1'    => lang('1 day'),
@@ -31,12 +74,12 @@
 );
 
-create_select_box(lang('Delete trash messages after how many days?'),'delete_trash_messages_after_n_days',$default,lang('Delete trash messages after how many days?'));
-create_check_box(lang('Would you like to use local messages?'),'use_local_messages','');
-create_check_box(lang('Would you like to keep archived messages?'),'keep_archived_messages','');
-create_check_box(lang('Show previous message, after delete actual message?'),'delete_and_show_previous_message','');
-create_check_box(lang('Do you wanna receive an alert for new messages?'),'alert_new_msg','');
-create_check_box(lang('Show default view on main screen?'),'mainscreen_showmail','');
-create_check_box(lang('Do you want to use remove attachments function?'),'remove_attachments_function','');
-create_check_box(lang('Do you want to use important flag in email editor?'),'enable_important_flag','');
+create_select_box('Delete trash messages after how many days?','delete_trash_messages_after_n_days',$default,lang('Delete trash messages after how many days?'));
+create_check_box('Would you like to use local messages?','use_local_messages','');
+create_check_box('Would you like to keep archived messages?','keep_archived_messages','');
+create_check_box('Show previous message, after delete actual message?','delete_and_show_previous_message','');
+create_check_box('Do you wanna receive an alert for new messages?','alert_new_msg','');
+create_check_box('Show default view on main screen?','mainscreen_showmail','');
+create_check_box('Do you want to use remove attachments function?','remove_attachments_function','');
+create_check_box('Do you want to use important flag in email editor?','enable_important_flag','');
 
 //TODO use default folders from email admin
@@ -47,6 +90,6 @@
 	'INBOX/'.lang('Trash')	=> lang('Trash')
 );
-create_select_box(lang('Save sent messages in folder'),'save_in_folder',$default,'');
-create_check_box(lang('Hide menu folders?'),'check_menu','');
+create_select_box('Save sent messages in folder','save_in_folder',$default,'');
+create_check_box('Hide menu folders?','check_menu','');
 
 $default = array(
@@ -56,5 +99,5 @@
 );
 
-create_select_box(lang('What is the height of the lines in the list of messages?'),'line_height',$default,'');
+create_select_box('What is the height of the lines in the list of messages?','line_height',$default,'');
 $default = array(
 	'10' => lang('small'),
@@ -63,8 +106,8 @@
 );
 
-create_select_box(lang('What the font size in the list of messages?'),'font_size',$default,'');
-create_check_box(lang('Use dynamic contacts?'),'use_dynamic_contacts','');
-create_check_box(lang('Use shortcuts?'),'use_shotcuts','');
-create_check_box(lang('Auto save draft'),'auto_save_draft','');
+create_select_box('What the font size in the list of messages?','font_size',$default,'');
+create_check_box('Use dynamic contacts?','use_dynamic_contacts','');
+create_check_box('Use shortcuts?','use_shotcuts','');
+create_check_box('Auto save draft','auto_save_draft','');
 $default = array(
 	'65536' => lang('unlimited'),
@@ -76,5 +119,20 @@
 );
 
-create_select_box(lang('What is the maximum size of embedded images')."?",'image_size',$default,'');
+create_select_box('What is the maximum size of embedded images'."?",'image_size',$default,'');
+
+if($GLOBALS['phpgw_info']['server']['use_assinar_criptografar'])
+{
+    create_check_box('Enable digitally sign/cipher the message?','use_signature_digital_cripto','','',True,'onchange="javascript:exibir_ocultar();"');
+    if ($GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital_cripto'])
+    {
+        create_check_box('Always sign message digitally?','use_signature_digital','');
+        create_check_box('Always cipher message digitally?','use_signature_cripto','');
+    }
+    else
+    {
+        create_check_box('Always sign message digitally?','use_signature_digital','','',True,'',False);
+        create_check_box('Always cipher message digitally?','use_signature_cripto','','',True,'',False);
+    }
+}
 
 $default = array(
@@ -83,5 +141,5 @@
 );
 
-create_select_box(lang('Signature Type'),'type_signature',$default,'','','','onchange="javascript:changeType(this.value);" onload="javascript:alert(this.value);"');
+create_select_box('Signature Type','type_signature',$default,'','','','onchange="javascript:changeType(this.value);" onload="javascript:alert(this.value);"');
 
 if ($type == 'user' || $type == ''){
Index: /trunk/expressoMail1_2/js/local_messages.js
===================================================================
--- /trunk/expressoMail1_2/js/local_messages.js	(revision 1000)
+++ /trunk/expressoMail1_2/js/local_messages.js	(revision 1035)
@@ -135,5 +135,5 @@
 	local_messages.prototype.get_local_mail = function(id_mail) {
 		this.init_local_messages();
-		var rs = this.dbGears.execute("select mail.rowid,mail.mail,mail.ffrom,mail.subject,mail.body,mail.fto,mail.cc,folder.folder from mail inner join folder on mail.id_folder=folder.rowid  where mail.rowid="+id_mail);
+		var rs = this.dbGears.execute("select mail.rowid,mail.mail,mail.ffrom,mail.subject,mail.body,mail.fto,mail.cc,folder.folder,mail.original_id from mail inner join folder on mail.id_folder=folder.rowid  where mail.rowid="+id_mail);
 		var retorno = null;
 		if(rs.isValidRow()) {
@@ -141,40 +141,57 @@
 		}
 		retorno = connector.unserialize(retorno);
-		
-		retorno['from'] = connector.unserialize(rs.field(2));
-		retorno['subject'] = rs.field(3);
-		retorno['body'] = rs.field(4);
-                //Codigo que as imagens embutidas em emails (com multipart/related ou multipart/mixed) sejam corretamente mostradas em emails arquivados. Os links do
-                //tipo "./inc/show_embedded_attach.php?msg_folder=[folder]&msg_num=[msg_num]&msg_part=[part]"
-                //são substituidos pelos links dos anexos capturados pelo gears.
-
-                var thumbs= retorno.thumbs;
-                var anexos= retorno.array_attach;
-                for (i in anexos)
-                {
-                    nomeArquivo = anexos[i]['name'].substring(0,anexos[i]['name'].length - 4);
-                    if(nomeArquivo.match('jpg')||anexos[i]['name'].match('gif')||anexos[i]['name'].match('png'))
-                        {
-                            var er_imagens = new RegExp("\\.\\/inc\\/show_embedded_attach.php\\?msg_folder=[\\w/]+\\&msg_num=[0-9]+\\&msg_part="+anexos[i]['pid']);
-                            var Result_imagens = er_imagens.exec(retorno['body']);
-                            retorno['body'] = retorno['body'].replace(Result_imagens,anexos[i]['url']);
-                            if(thumbs && thumbs[i]){
-                                er_imagens = new RegExp("\\.\\/inc\\/show_thumbs.php\\?file_type=image\\/[\\w]+\\&msg_num=[0-9]+\\&msg_folder=[\\w/%]+\\&msg_part="+anexos[i]['pid']);
-                                Result_imagens = er_imagens.exec(thumbs[i]);
-                                thumbs[i] = thumbs[i].replace(Result_imagens,"'"+anexos[i]['url']+"'");
-                                er_imagens = new RegExp("\\.\\/inc\\/show_img.php\\?msg_num=[0-9]+\\&msg_folder=[\\w/%]+\\&msg_part="+anexos[i]['pid']);
-                                Result_imagens = er_imagens.exec(thumbs[i]);
-                                thumbs[i] = thumbs[i].replace(Result_imagens,"'"+anexos[i]['url']+"'");
-                                thumbs[i] = thumbs[i].replace(/<IMG/i,'<img width="120"');
-                            }
+
+        //alert('tipo retorno.source: ' + typeof(retorno.source));
+
+        if (typeof(retorno.source) == 'string')
+        {
+            retorno.msg_number=rs.field(0);
+            retorno.original_ID=rs.field(8);
+            retorno.msg_folder=rs.field(7);
+
+            //alert('tipo retorno: '+typeof(retorno))
+            //show_msg(retorno);
+        }
+		else
+        {
+            retorno['from'] = connector.unserialize(rs.field(2));
+            retorno['subject'] = rs.field(3);
+            retorno['body'] = rs.field(4);
+            //Codigo que as imagens embutidas em emails (com multipart/related ou multipart/mixed) sejam corretamente mostradas em emails arquivados. Os links do
+            //tipo "./inc/show_embedded_attach.php?msg_folder=[folder]&msg_num=[msg_num]&msg_part=[part]"
+            //são substituidos pelos links dos anexos capturados pelo gears.
+
+            var thumbs= retorno.thumbs;
+            var anexos= retorno.array_attach;
+            for (i in anexos)
+            {
+                nomeArquivo = anexos[i]['name'].substring(0,anexos[i]['name'].length - 4);
+                if(nomeArquivo.match('jpg')||anexos[i]['name'].match('gif')||anexos[i]['name'].match('png'))
+                    {
+                        var er_imagens = new RegExp("\\.\\/inc\\/show_embedded_attach.php\\?msg_folder=[\\w/]+\\&msg_num=[0-9]+\\&msg_part="+anexos[i]['pid']);
+                        var Result_imagens = er_imagens.exec(retorno['body']);
+                        retorno['body'] = retorno['body'].replace(Result_imagens,anexos[i]['url']);
+                        if(thumbs && thumbs[i]){
+                            er_imagens = new RegExp("\\.\\/inc\\/show_thumbs.php\\?file_type=image\\/[\\w]+\\&msg_num=[0-9]+\\&msg_folder=[\\w/%]+\\&msg_part="+anexos[i]['pid']);
+                            Result_imagens = er_imagens.exec(thumbs[i]);
+                            thumbs[i] = thumbs[i].replace(Result_imagens,"'"+anexos[i]['url']+"'");
+                            er_imagens = new RegExp("\\.\\/inc\\/show_img.php\\?msg_num=[0-9]+\\&msg_folder=[\\w/%]+\\&msg_part="+anexos[i]['pid']);
+                            Result_imagens = er_imagens.exec(thumbs[i]);
+                            thumbs[i] = thumbs[i].replace(Result_imagens,"'"+anexos[i]['url']+"'");
+                            thumbs[i] = thumbs[i].replace(/<IMG/i,'<img width="120"');
                         }
-                }
-
-		retorno['to'] = connector.unserialize(rs.field(5));
-		retorno['cc'] = connector.unserialize(rs.field(6));
-		
-		retorno['local_message'] = true;
-		retorno['msg_folder'] = "local_"+rs.field(7); //Now it's a local folder 
-		retorno['msg_number'] = rs.field(0); //the message number is the rowid
+                    }
+            }
+
+            retorno['to'] = connector.unserialize(rs.field(5));
+            retorno['cc'] = connector.unserialize(rs.field(6));
+
+            retorno['local_message'] = true;
+            retorno['msg_folder'] = "local_"+rs.field(7); //Now it's a local folder
+            retorno['msg_number'] = rs.field(0); //the message number is the rowid
+
+        }
+
+        rs.close();
 		this.finalize();
 		return retorno;
@@ -671,4 +688,35 @@
     }
 
+    local_messages.prototype.get_msg_date = function (original_id, is_local){
+
+        this.init_local_messages();
+
+        if (typeof(is_local) == 'undefined')
+        {
+            is_local = false;
+        }
+
+        var rs;
+
+        if (is_local)
+        {
+            rs = this.dbGears.execute("select mail from mail where rowid="+original_id);
+        }
+        else
+        {
+            rs = this.dbGears.execute("select mail from mail where original_id="+original_id);
+        }
+        var tmp = connector.unserialize(rs.field(0));
+        var ret = new Array();
+        ret.fulldate = tmp.fulldate.substr(0,16);
+        ret.smalldate = tmp.msg_day;
+        ret.msg_day = tmp.msg_day;
+        ret.msg_hour = tmp.msg_day;
+
+        rs.close();
+        this.finalize();
+        return ret;
+    }
+
 
     local_messages.prototype.download_all_local_attachments = function(folder,id){
Index: /trunk/expressoMail1_2/js/main.js
===================================================================
--- /trunk/expressoMail1_2/js/main.js	(revision 1005)
+++ /trunk/expressoMail1_2/js/main.js	(revision 1035)
@@ -23,4 +23,11 @@
 			write_msg(get_lang("Attention, you are in out of office mode."), true);
 		ConstructMenuTools();
+
+        // Insere a applet de criptografia
+        if (preferences.use_signature_digital_cripto == '1'){
+            loadApplet();
+        }
+        // Fim da inserção da applet
+
 		cExecute ("$this.imap_functions.get_folders_list", update_menu);
 	}
@@ -36,9 +43,85 @@
 	// Get cyrus delimiter
 	cyrus_delimiter = Element('cyrus_delimiter').value;
-	
+    var del_return = function(data){
+		//alert(data);
+	}
+
+	cExecute ("$this.imap_functions.delete_mailbox&del_past=INBOX/decifradas", del_return);
 	cExecute ("$this.db_functions.get_dropdown_contacts", save_contacts);
 	cExecute ("$this.functions.get_preferences", save_preferences);
 	setTimeout('auto_refresh()', time_refresh);
 }
+
+/**
+ * Carrega a applet java no objeto search_div
+ * @author Mário César Kolling <mario.kolling@serpro.gov.br>
+ */
+
+function loadApplet(){
+
+    var search_div = Element('search_div');
+    var applet = null;
+    if (navigator.userAgent.match('MSIE')){
+        applet = document.createElement('<object style="display:yes;width:0;height:0;vertical-align:bottom;" id="cert_applet" ' +
+            'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"></object>');
+
+        //applet = document.createElement('object');
+        //var attributes = {
+        //    style:'display:yes;width:0;height:0;vertical-align:bottom;',
+        //    id:'cert_applet',
+        //    classid:'clsid:8AD9C840-044E-11D1-B3E9-00805F499D93'
+        //}
+
+        var parameters = {
+            type:'application/x-java-applet;version=1.5',
+            code:'ExpressoSmimeApplet',
+            codebase:'../',
+            mayscript:'true',
+            token: token_param,
+            locale: locale,
+            archive:'ExpressoCertMail.jar,' +
+                'ExpressoCert.jar,' +
+                'bcmail-jdk15-142.jar,' +
+                'mail.jar,' +
+                'activation.jar,' +
+                'bcprov-jdk15-142.jar,' +
+                'commons-codec-1.3.jar,' +
+                'commons-httpclient-3.1.jar,' +
+                'commons-logging-1.1.1.jar'
+            //debug:'true'
+        }
+
+        //for (var attribute in attributes){
+        //    applet.setAttribute(attribute, attributes[attribute]);
+        //}
+
+        if (parameters != 'undefined' && parameters != null){
+            for (var parameter in parameters) {
+                var param = document.createElement("PARAM");
+                param.setAttribute("name",parameter);
+                param.setAttribute("value",parameters[parameter]);
+                applet.appendChild(param);
+            }
+        }
+        search_div.appendChild(applet);
+        //alert(search_div.innerHTML);
+        //alert(window.);
+    }
+    else {
+        applet = document.createElement('embed');
+        applet.innerHTML = '<embed style="display:yes;width:0;height:0;vertical-align:bottom;" id="cert_applet" code="ExpressoSmimeApplet.class" ' +
+            'codebase="../" locale="'+locale+'"'+
+            'archive="ExpressoCertMail.jar,ExpressoCert.jar,bcmail-jdk15-142.jar,mail.jar,activation.jar,bcprov-jdk15-142.jar,commons-codec-1.3.jar,commons-httpclient-3.1.jar,commons-logging-1.1.1.jar" ' +
+            'token="' + token_param + '" ' +
+            'type="application/x-java-applet;version=1.5" mayscript > ' +
+            //'type="application/x-java-applet;version=1.5" debug="true" mayscript > ' +
+            '<noembed> ' +
+            'No Java Support. ' +
+            '</noembed> ' +
+            '</embed> ';
+        search_div.appendChild(applet);
+    }
+}
+
 function disable_field(field,condition) {
 	var comando = "if ("+condition+") { document.getElementById('"+field.id+"').disabled=true;} else { document.getElementById('"+field.id+"').disabled=false; }";
@@ -137,4 +220,39 @@
 			write_msg(get_lang("Error in SMTP sending read confirmation."));
 	}
+    
+	if(msg_info.source)
+	{
+        // Abrindo um e-mail criptografado
+        // Verifica se existe o objeto applet
+        if (!Element('cert_applet')){
+            // se não existir, mostra mensagem de erro.
+            write_msg(get_lang('The preference "%1" isn\'t enabled.', get_lang('Enable digitally sign/cipher the message?')));
+        } else {
+            // se existir prepara os dados para serem enviados e chama a
+            // operação na applet
+
+            connector.showProgressBar();
+
+           // if ((msg_info.DispositionNotificationTo) && ((msg_info.Unseen == 'U') || (msg_info.Recent == 'N'))){
+            /*	var confNotification = confirm(get_lang("The sender waits your notification of reading. Do you want to confirm this?"), "");
+                if (confNotification)*/
+            //        cExecute ("$this.imap_functions.send_notification&notificationto="+msg_info.DispositionNotificationTo+"&subject="+url_encode(msg_info.subject), handler_sendNotification);
+           // }
+
+            Element('cert_applet').doButtonClickAction('decript',
+                                                        msg_info.msg_number,
+                                                        msg_info.source,
+                                                        msg_info.msg_folder); // Passa os dados para a applet
+        }
+		return;
+
+	}
+
+
+	if (msg_info.status_get_msg_info == 'false')
+	{
+		write_msg(get_lang("Problems reading your message")+ ".");
+		return;
+	}
 
 	if (msg_info.status == 'false'){
@@ -142,8 +260,10 @@
 	}
 	else{
+        var ID = msg_info.original_ID ? msg_info.original_ID : msg_info.msg_number;
+        var id_msg_read = ID+"_r";
+
 		if (preferences.use_shortcuts == '1')
-			select_msg(msg_info.msg_number, 'null');
+			select_msg(ID, 'null');
 		// Call function to draw message
-		var id_msg_read = msg_info.msg_number +"_r";
 		// If needed, delete old border
 		if (openTab.type[currentTab] == 2 || openTab.type[currentTab] == 3)
@@ -173,8 +293,10 @@
 
 		var domains = "";
-		if ((msg_info.DispositionNotificationTo) && (!msg_is_read(msg_info.msg_number) || (msg_info.Recent == 'N')))
+		if ((msg_info.DispositionNotificationTo) && (!msg_is_read(ID) || (msg_info.Recent == 'N')))
 		{			
 			if (preferences.notification_domains != undefined && preferences.notification_domains != "")
+            {
 				domains = preferences.notification_domains.split(',');
+            }
 			else
 			{				
@@ -194,11 +316,12 @@
 		}
 		//Change msg class to read.
-		if (!msg_is_read(msg_info.msg_number))
+		if (!msg_is_read(ID))
 		{
-			set_msg_as_read(msg_info['msg_number'], true);
-			if (msg_info.cacheHit)
-				set_message_flag(msg_info.msg_number, "seen"); // avoid caducous (lazy) data
-		}
-
+            set_msg_as_read(ID, true);
+			if (msg_info.cacheHit || (!proxy_mensagens.is_local_folder(get_current_folder()) && msg_info.original_ID))
+            {
+				set_message_flag(ID, "seen"); // avoid caducous (lazy) data
+            }
+        }
 	}
 }
@@ -1214,4 +1337,46 @@
 
 function send_message_return(data, ID){
+
+    var sign = false;
+	var crypt = false;
+
+    if ((preferences.use_assinar_criptografar != '0') && (preferences.use_signature_digital_cripto != '0')){
+		var checkSign = document.getElementById('return_digital_'+ID)
+		if (checkSign.checked){
+			sign = true;
+		}
+
+		var checkCript = document.getElementById('return_cripto_'+ID);
+		if (checkCript.checked){
+			crypt = true;
+		}
+	}
+
+    if (typeof(data) == 'object' && !data.success)
+	{
+        connector = new  cConnector();
+        connector.showProgressBar();
+
+        if (sign || crypt){
+            var operation = '';
+			if (sign){
+				operation = 'sign';
+			}
+			else { // crypt
+                //TODO: Colocar mensagem de erro, e finalizar o método.
+				operation = 'nop';
+			}
+        }
+
+        if (data.body){
+            Element('cert_applet').doButtonClickAction(operation, ID, data.body);
+        }
+        else {
+			alert(data.error);
+		}
+
+		return;
+    }
+
 	if(data && data.success == true ){
 		// if send ok, set a flag as answered or forwarded
@@ -1252,4 +1417,60 @@
 			write_msg(get_lang("Connection failed with %1 Server. Try later.", "Web"));
 	}
+}
+
+function appletReturn(smime, ID, operation, folder){
+	//alert('os dados chegaram!');
+    //alert("ID: " + ID + "\n" + smime);
+	if(operation=='decript')
+	{
+		var handler = function(data){
+
+			if(data.msg_day == '')
+			{
+                header=expresso_local_messages.get_msg_date(data.original_ID, proxy_mensagens.is_local_folder(get_current_folder()));
+
+				data.fulldate=header.fulldate;
+				data.smalldate=header.smalldate;
+				data.msg_day = header.msg_day;
+				data.msg_hour = header.msg_hour;
+
+			}
+			this.show_msg(data);
+		}
+		para="&source="+smime+"&ID="+ID+"&folder="+folder;
+		cExecute ("$this.imap_functions.show_decript&", handler, para);
+	}else
+	{
+        ID_tmp = ID;
+        // Lê a variável e chama a nova função cExecuteForm
+        // Processa e envia para o servidor web
+        // Faz o request do connector novamente. Talvez implementar no connector
+        // para manter coerência.
+
+        var handler_send_smime = function(data){
+            send_message_return(data, this.ID_tmp); // this is a hack to escape quotation form connector bug
+        };
+
+        var textArea = document.createElement("TEXTAREA");
+        textArea.style.display='none';
+        textArea.name = "smime";
+        textArea.value += smime;
+
+        // Lê a variável e chama a nova função cExecuteForm
+        // Processa e envia para o servidor web
+        // Faz o request do connector novamente. Talvez implementar no connector
+        // para manter coerência.
+        if (is_ie){
+            var i = 0;
+            while (document.forms(i).name != "form_message_"+ID){i++}
+            form = document.forms(i);
+        }
+        else
+            form = document.forms["form_message_"+ID];
+
+        form.appendChild(textArea);
+
+        cExecuteForm ("$this.imap_functions.send_mail", form, handler_send_smime, ID);
+    }
 }
 
Index: /trunk/expressoMail1_2/js/draw_api.js
===================================================================
--- /trunk/expressoMail1_2/js/draw_api.js	(revision 1000)
+++ /trunk/expressoMail1_2/js/draw_api.js	(revision 1035)
@@ -514,7 +514,7 @@
 		
 		td_element2 = document.createElement("TD");
-		td_element2.setAttribute("width", "2%");		
+		td_element2.setAttribute("width", "7%");
 		td_element3 = document.createElement("TD");
-		td_element3.setAttribute("width", "31%");
+		td_element3.setAttribute("width", "29%");
 		td_element3.onclick = function () {sort_box(search_box_type,'SORTFROM');};
 		td_element3.id = "message_header_SORTFROM_"+numBox;
@@ -523,5 +523,5 @@
 		
 		td_element4 = document.createElement("TD");
-		td_element4.setAttribute("width", "41%");
+		td_element4.setAttribute("width", "38%");
 		td_element4.onclick = function () {sort_box(search_box_type,'SORTSUBJECT');};
 		td_element4.id = "message_header_SORTSUBJECT_"+numBox;
@@ -752,9 +752,20 @@
 		td_element21.id = "td_message_answered_"+headers_msgs.msg_number;
 
+		if (headers_msgs.attachment && headers_msgs.attachment.number_attachments > 0) {
+			attach_name = headers_msgs.attachment.names.split(", ");
+			for(var item in attach_name)
+			{
+				if (url_decode(attach_name[item]) != 'smime.p7s' && url_decode(attach_name[item]) != 'smime.p7m'){
+					td_element21.innerHTML = "<img src ='templates/"+template+"/images/clip.gif' title='" + url_decode(attach_name[item]) + "'>";
+					break;
+				}
+			}
+		}
+
 		if ((headers_msgs.Forwarded == 'F')  || (headers_msgs.Draft == 'X' && headers_msgs.Answered == 'A')){
 			td_element21.innerHTML = "<img src ='templates/"+template+"/images/forwarded.gif' title='"+get_lang('Forwarded')+"'>";
 			headers_msgs.Draft = '' 
 			headers_msgs.Answered = '';
-			headers_msgs.Forwarded == 'F';
+			headers_msgs.Forwarded = 'F';
 		}
 		else if (headers_msgs.Draft == 'X')
@@ -768,18 +779,44 @@
 		td_element22.className = "td_msg";
 		td_element22.setAttribute("width", "1%");
-		td_element22.id = "td_message_important_"+headers_msgs.msg_number;
+		td_element22.id = "td_message_signed_"+headers_msgs.msg_number;
+
+        //td_element23 = document.createElement("TD");
+		//td_element23.setAttribute("width", "1%");
+		//td_element23.id = "td_message_signed_"+headers_msgs.msg_number;
+        switch(headers_msgs.ContentType)
+		{
+            case "signature":
+			{
+				td_element22.innerHTML = "<img src ='templates/"+template+"/images/signed_msg.gif' title='" + get_lang('Signed message') + "'>";
+				break;
+			}
+            case "cipher":
+			{
+				td_element22.innerHTML = "<img src ='templates/"+template+"/images/lock.gif' title='" + get_lang('Crypted message') + "'>";
+				break;
+			}
+            default:
+			{
+				break;
+			}
+		}
+
+        td_element23 = document.createElement("TD");
+		td_element23.className = "td_msg"
+		td_element23.setAttribute("width", "1%");
+		td_element23.id = "td_message_important_"+headers_msgs.msg_number;
 
 		if (headers_msgs.Flagged == 'F' || (headers_msgs.Importance.toLowerCase().indexOf("high") != -1 && preferences.use_important_flag == 'True'))
 		{
-			td_element22.innerHTML = "<img src ='templates/"+template+"/images/important.gif' title='"+get_lang('Important')+"'>";
+			td_element23.innerHTML = "<img src ='templates/"+template+"/images/important.gif' title='"+get_lang('Important')+"'>";
 		}
 		else
-			td_element22.innerHTML = "&nbsp;&nbsp;&nbsp;";
-
-		td_element23 = document.createElement("TD");
-		td_element23.className = "td_msg";
-		td_element23.setAttribute("width", "1%");
-		td_element23.id = "td_message_sent_"+headers_msgs.msg_number;
-		td_element23.innerHTML = "&nbsp;&nbsp;&nbsp;";
+			td_element23.innerHTML = "&nbsp;&nbsp;&nbsp;";
+
+		td_element24 = document.createElement("TD");
+		td_element24.className = "td_msg";
+		td_element24.setAttribute("width", "1%");
+		td_element24.id = "td_message_sent_"+headers_msgs.msg_number;
+		td_element24.innerHTML = "&nbsp;&nbsp;&nbsp;";
 		// preload image
 		var _img_sent = new Image();
@@ -803,5 +840,5 @@
 			else{				
 				if(headers_msgs.to.email.toLowerCase() != Element("user_email").value)
-					td_element23.innerHTML = "<img valign='center' src ='templates/"+template+"/images/sent.gif' title='"+get_lang('Sent')+"'>";
+					td_element24.innerHTML = "<img valign='center' src ='templates/"+template+"/images/sent.gif' title='"+get_lang('Sent')+"'>";
 			
 				if ((headers_msgs.to)&&(headers_msgs.to.name != null))
@@ -880,4 +917,5 @@
 		tr_element.appendChild(td_element22);
 		tr_element.appendChild(td_element23);
+        tr_element.appendChild(td_element24);
 		tr_element.appendChild(td_element3);
 		tr_element.appendChild(td_element4);
@@ -966,30 +1004,50 @@
 	// Old
 	//img_next_msg.onclick = function () {cExecute ("$this.imap_functions.get_info_next_msg&msg_number="+ info_msg.msg_number + "&msg_folder="+ info_msg.msg_folder + "&sort_box_type="+ sort_box_type +  "&search_box_type="+ search_box_type +"&sort_box_reverse="+ sort_box_reverse +"&reuse_border="+ID, show_msg)};
-	var folder = document.getElementById(ID.substr(0, ID.indexOf('_')));
+    var folder_id = 0;
+    folder_id = info_msg.original_ID ? info_msg.original_ID: info_msg.msg_number;
+	var folder = document.getElementById(folder_id);
 	if (!folder){
 		delete_border(ID);
 		return;
 		}
-	if (folder.nextSibling){
-		var nextMsgBox = folder.nextSibling.name?folder.nextSibling.name:info_msg.msg_folder;
-		img_next_msg.onclick = function()
+    if (folder){ // mensagem local criptografada nao tem ID da pasta local
+        if (folder.nextSibling){
+            var nextMsgBox = folder.nextSibling.name?folder.nextSibling.name:info_msg.msg_folder;
+
+            if (nextMsgBox == "INBOX/decifradas")// teste para ver se a mensagem vem da pasta oculta decifradas
+                    nextMsgBox = get_current_folder();
+
+            img_next_msg.onclick = function()
+            {
+                currentTab = ID;
+                openTab.type[ID] = 2;
+                            proxy_mensagens.get_msg(parseInt(folder.nextSibling.id),nextMsgBox,true,show_msg);
+                //cExecute("$this.imap_functions.get_info_msg&msg_number="+folder.nextSibling.id+"&msg_folder="+nextMsgBox, show_msg);
+            };
+        }
+        else
+        {
+            img_next_msg.src = "./templates/"+template+"/images/down.gray.button.png";
+            img_next_msg.style.cursor = 'default';
+
+        }
+    }
+    else
+    {
+        img_next_msg.src = "./templates/"+template+"/images/down.gray.button.png";
+		img_next_msg.style.cursor = 'default';
+		if (!proxy_mensagens.is_local_folder(get_current_folder()) && !(info_msg.msg_folder == "INBOX/decifradas")) // testa se a mensagem e local
 		{
-			currentTab = ID;
-			openTab.type[ID] = 2;
-                        proxy_mensagens.get_msg(parseInt(folder.nextSibling.id),nextMsgBox,true,show_msg);
-			//cExecute("$this.imap_functions.get_info_msg&msg_number="+folder.nextSibling.id+"&msg_folder="+nextMsgBox, show_msg);
-		};
-	}
-	else
-		img_next_msg.onclick = function()
-			{
-				/*current_page++;
-				msg_range_end = (current_page*preferences.max_email_per_page);
-				msg_range_begin = (msg_range_end-(preferences.max_email_per_page)+1);
-				kill_current_box();
-				cExecute ('$this.imap_functions.get_range_msgs2&folder='+current_folder+'&msg_range_begin='+msg_range_begin+'&msg_range_end='+msg_range_end+'&sort_box_reverse=1', function handler(data){draw_box(data, current_folder);}) */
-					delete_border(ID);
-			};
-
+            img_next_msg.onclick = function()
+                {
+                    /*current_page++;
+                    msg_range_end = (current_page*preferences.max_email_per_page);
+                    msg_range_begin = (msg_range_end-(preferences.max_email_per_page)+1);
+                    kill_current_box();
+                    cExecute ('$this.imap_functions.get_range_msgs2&folder='+current_folder+'&msg_range_begin='+msg_range_begin+'&msg_range_end='+msg_range_end+'&sort_box_reverse=1', function handler(data){draw_box(data, current_folder);}) */
+                        delete_border(ID);
+                };
+        }
+    }
 	var img_space = document.createElement("SPAN");
 	img_space.innerHTML = "&nbsp;";
@@ -1002,26 +1060,43 @@
 	//Old
 	//img_previous_msg.onclick = function () {cExecute ("$this.imap_functions.get_info_previous_msg&msgs_number="+ info_msg.msg_number + "&folder="+ info_msg.msg_folder + "&sort_box_type="+ sort_box_type+ "&search_box_type="+ search_box_type + "&sort_box_reverse="+ sort_box_reverse +"&reuse_border="+ID, show_msg)}
-	folder = document.getElementById(ID.substr(0, ID.indexOf('_')));
+	//folder = document.getElementById(ID.substr(0, ID.indexOf('_')));
 	if (!folder){
 	        delete_border(ID);
 		return;
 		}
-	if (folder.previousSibling)
+    if (folder){ // mensagem local criptografada nao tem ID da pasta local
+        if (folder.previousSibling)
+        {
+            var previousMsgBox = folder.previousSibling.name?folder.previousSibling.name:info_msg.msg_folder;
+
+            if (previousMsgBox == "INBOX/decifradas") // teste para ver se a mensagem vem da pasta oculta decifradas
+                    previousMsgBox = get_current_folder();
+
+            img_previous_msg.onclick = function()
+            {
+                currentTab = ID;
+                openTab.type[ID] = 2;
+                //cExecute("$this.imap_functions.get_info_msg&msg_number="+folder.previousSibling.id+"&msg_folder=" + previousMsgBox, show_msg);
+                            proxy_mensagens.get_msg(parseInt(folder.previousSibling.id),previousMsgBox,true,show_msg);
+            };
+        }
+        else
+        {
+            img_previous_msg.src = "./templates/"+template+"/images/up.gray.button.png";
+            img_previous_msg.style.cursor = 'default';
+        }
+	}
+	else
 	{
-		var previousMsgBox = folder.previousSibling.name?folder.previousSibling.name:info_msg.msg_folder;
-		img_previous_msg.onclick = function()
-		{
-			currentTab = ID;
-			openTab.type[ID] = 2;
-			//cExecute("$this.imap_functions.get_info_msg&msg_number="+folder.previousSibling.id+"&msg_folder=" + previousMsgBox, show_msg);
-                        proxy_mensagens.get_msg(parseInt(folder.previousSibling.id),previousMsgBox,true,show_msg);
-		};
-	}
-	else
-		img_previous_msg.onclick = function()
-		{
-			delete_border(ID);
-		};
-
+		img_previous_msg.src = "./templates/"+template+"/images/up.gray.button.png";
+		img_previous_msg.style.cursor = 'default';
+		if (!proxy_mensagens.is_local_folder(get_current_folder()) && !(info_msg.msg_folder == "INBOX/decifradas")) // testa se a mensagem e local
+        {
+            img_previous_msg.onclick = function()
+            {
+                delete_border(ID);
+            };
+        }
+    }
 	next_previous_msg_td.appendChild(img_previous_msg);
 	next_previous_msg_td.appendChild(img_space);
@@ -1107,7 +1182,7 @@
 	option_mark.align = "left";
 	option_mark.width = "50%";
-	var option_mark_as_unseen = '<span class="message_options" onclick="set_messages_flag(\'unseen\','+info_msg.msg_number+');write_msg(\''+get_lang('Message marked as ')+get_lang("Unseen")+'.\');">'+get_lang("Unseen")+'</span>, ';
-	var option_mark_as_important = '<span class="message_options" onclick="set_messages_flag(\'flagged\','+info_msg.msg_number+');write_msg(\''+get_lang('Message marked as ')+get_lang("Important")+'.\');">'+get_lang("Important")+'</span>, ';
-	var option_mark_as_normal = '<span class="message_options" onclick="set_messages_flag(\'unflagged\','+info_msg.msg_number+');write_msg(\''+get_lang('Message marked as ')+get_lang("Normal")+'.\');">'+get_lang("Normal")+'</span>';
+	var option_mark_as_unseen = '<span class="message_options" onclick="set_messages_flag(\'unseen\','+folder_id+');write_msg(\''+get_lang('Message marked as ')+get_lang("Unseen")+'.\');">'+get_lang("Unseen")+'</span>, ';
+	var option_mark_as_important = '<span class="message_options" onclick="set_messages_flag(\'flagged\','+folder_id+');write_msg(\''+get_lang('Message marked as ')+get_lang("Important")+'.\');">'+get_lang("Important")+'</span>, ';
+	var option_mark_as_normal = '<span class="message_options" onclick="set_messages_flag(\'unflagged\','+folder_id+');write_msg(\''+get_lang('Message marked as ')+get_lang("Normal")+'.\');">'+get_lang("Normal")+'</span>';
 	option_mark.innerHTML = option_mark_as_unseen+option_mark_as_important+option_mark_as_normal;
 	option_hide_more.innerHTML = get_lang('Options');
@@ -1192,4 +1267,60 @@
 	tbody_message_options.appendChild(tr_other_options);
 	////////// END OTHER OPTIONS ////////////////
+
+    	////////// BEGIN SIGNATURE //////////////////
+	if (info_msg.signature && info_msg.signature.length > 0)
+	{
+		var tr_signature = document.createElement("TR");
+		var td_signature = document.createElement("TD");
+		td_signature.className = 'tr_message_header';
+		tr_signature.id = 'tr_signature_'+ID;
+		td_signature.colSpan = "5";
+		tr_signature.style.display = 'none';
+
+		for (i in info_msg.signature)
+			td_signature.innerHTML += '<span>'+info_msg.signature[i]+'</span> <br /> ';
+		var signature_status_pos = info_msg.signature[0].indexOf(get_lang('Message untouched'));
+		td_signature.id = "td_signature_"+ID;
+		if(signature_status_pos < 0 )
+		{
+		td.innerHTML += '&nbsp;<img style="cursor:pointer" src="templates/'+template+'/images/signed_error.gif" title="'+get_lang("Details")+'">';
+		tr_signature.style.display = '';
+		}
+		else
+		{
+		td.innerHTML += '&nbsp;<img style="cursor:pointer" src="templates/'+template+'/images/signed_table.gif" title="'+get_lang("Details")+'">';
+		}
+		td.onclick = function(){
+		var _height = Element("div_message_scroll_"+ID).style.height;
+		_height = parseInt(_height.replace("px",""));
+		var _offset = 130;
+		if (this.value == 'more_cert'){
+			//this.innerHTML += "<b><u>Mais Informaï¿œï¿œes</u></b>";
+			this.value = 'hide_cert';
+			Element("div_message_scroll_"+ID).style.height = (_height + _offset)+"px";
+			Element('tr_signature_'+ID).style.display = 'none';
+			Element('td_signature_'+ID).style.display = 'none';
+
+		}
+		else{
+			//this.innerHTML += "Mais Informaï¿œï¿œes";
+			this.value = 'more_cert';
+			Element("div_message_scroll_"+ID).style.height = (_height - _offset)+"px";
+			Element('tr_signature_'+ID).style.display = '';
+			Element('td_signature_'+ID).style.display = '';
+		}
+	};
+
+		tr_signature.appendChild(td_signature);
+		tbody_message_options.appendChild(tr_signature);
+	/******************************************* Old signature   ***********************************************/
+		//if (info_msg.signature != "void")
+		//	td.innerHTML += '&nbsp;<img style="cursor:pointer" onclick="alert(\''+ get_lang("This message is signed, and you can trust.") + info_msg.signature +'\');" src="'+tpl_img_path+'/signed.gif">';
+		//else
+		//	td.innerHTML += "&nbsp;<img style='cursor:pointer' onclick='alert(\""+get_lang("This message is signed, but it is invalid. You should not trust on it.")+"\");' title='"+get_lang("Voided message")+"' src='"+tpl_img_path+"/invalid.gif'>";
+	/*****************************************															********/
+	}
+	//////////// END SIGNATURE ////////////////
+
 	table_message_options.appendChild(tbody_message_options);
 	td0.appendChild(table_message_options);
@@ -2072,5 +2203,50 @@
 	input_return_receipt.name = "input_return_receipt";
 	input_return_receipt.setAttribute("tabIndex","-1");
-	td_return_receipt.appendChild(input_return_receipt);	
+	td_return_receipt.appendChild(input_return_receipt);
+
+
+//alert("preferences.use_assinar_criptografar " + preferences.use_assinar_criptografar);
+//alert("preferences.use_signature_digital_cripto " + preferences.use_signature_digital_cripto);
+//alert("preferences.use_signature_digital " + preferences.use_signature_digital);
+//alert("preferences.use_signature_cripto " + preferences.use_signature_cripto);
+
+    if(preferences.use_assinar_criptografar==1)
+	{
+		if(preferences.use_signature_digital_cripto==1)
+		{
+			td_return_receipt.innerHTML +=  "&nbsp;&nbsp;" + get_lang("Digitally sign message?")+"";
+			var input_return_digital = document.createElement('input');
+			input_return_digital.type = "checkbox";
+			input_return_digital.className = "checkbox";
+			input_return_digital.id = "return_digital_"+ID;
+			input_return_digital.name = "input_return_digital";
+			input_return_digital.setAttribute("tabIndex","-1");
+			if(preferences.use_signature_digital==1)
+			{
+				input_return_digital.defaultChecked=true;
+			}
+			td_return_receipt.appendChild(input_return_digital);
+                        //descomentariar a linha abaixo para criptografia
+			td_return_receipt.innerHTML +=  "&nbsp;&nbsp;" + get_lang("Digitally crypt message?")+"";
+			var input_return_cripto = document.createElement('input');
+			input_return_cripto.type = "checkbox";
+			input_return_cripto.className = "checkbox";
+			input_return_cripto.id = "return_cripto_"+ID;
+			input_return_cripto.name = "input_return_cripto";
+			input_return_cripto.setAttribute("tabIndex","-1");
+			//input_return_cripto.style.display = "none";
+			input_return_cripto.defaultChecked=false;
+			//Descomentariar o bloco abaixo para criptografia
+
+			if(preferences.use_signature_cripto==1)
+			{
+				input_return_cripto.defaultChecked=true;
+			}
+
+			td_return_receipt.appendChild(input_return_cripto);
+
+		}
+	}
+
 	tr5.appendChild(td5);
 	tr5.appendChild(td_return_receipt);
Index: /trunk/expressoMail1_2/index.php
===================================================================
--- /trunk/expressoMail1_2/index.php	(revision 905)
+++ /trunk/expressoMail1_2/index.php	(revision 1035)
@@ -28,5 +28,5 @@
 		'nonavbar' => False,
 		'currentapp' => 'expressoMail1_2',
-		'update_version'	=> '1.234',
+		'update_version'	=> '1.334',
 		'enable_nextmatchs_class' => True
 	);
@@ -90,5 +90,10 @@
 	$_SESSION['phpgw_info']['user']['preferences']['expressoMail']['use_important_flag'] = $current_config['expressoMail_enable_important_flag'];
 	$_SESSION['phpgw_info']['user']['preferences']['expressoMail']['use_local_messages'] = $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_local_messages'] ? $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_local_messages'] : "0";
-	$_SESSION['phpgw_info']['user']['preferences']['expressoMail']['keep_archived_messages'] = $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['keep_archived_messages'] ? $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['keep_archived_messages'] : "0"; 
+	$_SESSION['phpgw_info']['user']['preferences']['expressoMail']['keep_archived_messages'] = $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['keep_archived_messages'] ? $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['keep_archived_messages'] : "0";
+    $_SESSION['phpgw_info']['user']['preferences']['expressoMail']['use_assinar_criptografar'] = $GLOBALS['phpgw_info']['server']['use_assinar_criptografar'] ?  $GLOBALS['phpgw_info']['server']['use_assinar_criptografar'] : "0";
+    $_SESSION['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital_cripto'] = $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital_cripto'] ? $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital_cripto'] : "0";
+    $_SESSION['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital'] = $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital'] ? $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_digital'] : "0";
+    $_SESSION['phpgw_info']['user']['preferences']['expressoMail']['num_max_certs_to_cipher'] = $GLOBALS['phpgw_info']['server']['num_max_certs_to_cipher'] ?  $GLOBALS['phpgw_info']['server']['num_max_certs_to_cipher'] : "10";
+    $_SESSION['phpgw_info']['user']['preferences']['expressoMail']['use_signature_cripto'] = $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_cripto'] ? $GLOBALS['phpgw_info']['user']['preferences']['expressoMail']['use_signature_cripto'] : "0";
 
 	$template = CreateObject('phpgwapi.Template',PHPGW_APP_TPL);
@@ -135,5 +140,18 @@
     $_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSpamFolder'] 	= $_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSpamFolder']	? $_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSpamFolder']		: lang("Spam");
     $_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSentFolder']	= $_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSentFolder'] 	? $_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSentFolder'] 		: lang("Sent");
-    
+
+    // gera paramero com tokens suportados ....
+    $var_tokens = '';
+    for($ii = 1; $ii < 11; $ii++)
+    {
+        if($GLOBALS['phpgw_info']['server']['test_token' . $ii . '1'])
+            $var_tokens .= $GLOBALS['phpgw_info']['server']['test_token' . $ii . '1'] . ',';
+    }
+
+    if(!$var_tokens)
+    {
+        $var_tokens = 'ePass2000Lx;/usr/lib/libepsng_p11.so,ePass2000Win;c:/windows/system32/ngp11v211.dll';
+    }
+
     echo '<script> var special_folders = new Array(4);
    	special_folders["'.$_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultTrashFolder'].'"] = \'Trash\';
@@ -144,5 +162,7 @@
     var draftsfolder = "'.$_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultDraftsFolder'].'";
     var sentfolder = "'.$_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSentFolder'].'";
-    var spamfolder = "'.$_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSpamFolder'].'";                 
+    var spamfolder = "'.$_SESSION['phpgw_info']['expressomail']['email_server']['imapDefaultSpamFolder'].'";
+    var token_param = "'.$var_tokens.'";
+    var locale = "'.$GLOBALS['phpgw']->common->getPreferredLanguage().'";
     </script>';
 
Index: /trunk/expressoMail1_2/templates/default/preferences.tpl
===================================================================
--- /trunk/expressoMail1_2/templates/default/preferences.tpl	(revision 695)
+++ /trunk/expressoMail1_2/templates/default/preferences.tpl	(revision 1035)
@@ -2,5 +2,29 @@
 <script src="js/main.js"></script>
 <center>
-
+<script language="JavaScript" type="text/javascript">
+<!--
+  function exibir_ocultar(situacao)
+  {
+     var xtr1 = document.getElementById('tr01');
+     var xtr2 = document.getElementById('tr02');
+     var xc1 = document.getElementById('c01');
+     var xc2 = document.getElementById('c02');
+     if(situacao==true)
+       {
+    xtr1.style.display='';
+    xtr2.style.display='';
+    xc1.checked=false;
+    xc2.checked=false;
+       }
+      else
+       {
+    xtr1.style.display='none';
+    xtr2.style.display='none';
+    xc1.checked=false;
+    xc2.checked=false;
+       }
+  }
+ -->
+</script> 
 <table width="65%" border="0" cellspacing="2" cellpadding="2">
 
@@ -136,4 +160,31 @@
         <td colspan="2" align="center">{lang_config_signature}</td>
     </tr>
+    <tr bgcolor="{tr_color2}"  {display_digital_cripto}>
+        <td>
+			{lang_use_signature_digital_cripto}
+		</td>
+		<td align="center">
+			<input type="checkbox" name="use_signature_digital_cripto" value=1 {checked_use_signature_digital_cripto} onClick="javascript:exibir_ocultar(this.checked)">
+		</td>
+    </tr>
+
+    <tr  bgcolor="{tr_color1}" id="tr01" {display_digital}>
+	<td>
+			{lang_use_signature_digital}
+		</td>
+		<td  align="center" >
+			 <input id="c01" type="checkbox" name="use_signature_digital" value=1 {checked_use_signature_digital}>
+		</td>
+    </tr>
+
+    <tr bgcolor="{tr_color2}" id="tr02" {display_cripto} >
+	<td>
+			{lang_use_signature_cripto}
+		</td>
+		<td  align="center">
+			 <input id="c02" type="checkbox" name="use_signature_cripto" value=1 {checked_use_signature_cripto}>
+		</td>
+    </tr>
+
      <tr bgcolor="{tr_color1}">
         <td>
Index: /trunk/expressoMail1_2/templates/default/index.tpl
===================================================================
--- /trunk/expressoMail1_2/templates/default/index.tpl	(revision 955)
+++ /trunk/expressoMail1_2/templates/default/index.tpl	(revision 1035)
@@ -28,5 +28,5 @@
 				</table>
 				<div style="height:4px"></div>
-				<div align="center" style="white-space:nowrap">
+				<div id="search_div" align="center" style="white-space:nowrap">
 					<input type="text" id="em_message_search" size="16" maxlength="22" onfocus="javascript:onFocusQuickSearchEmail(this); return false;"/>
 					<a class='' onMouseOut="window.status='';return true;" title='{lang_Open_Search_Window}' onMouseOver="window.status='{lang_Open_Search_Window}';return true;" href="javascript:void(0);"  onClick="javascript:search_emails(Element('em_message_search').value)">
Index: /trunk/expressoMail1_2/templates/azul/index.tpl
===================================================================
--- /trunk/expressoMail1_2/templates/azul/index.tpl	(revision 1023)
+++ /trunk/expressoMail1_2/templates/azul/index.tpl	(revision 1035)
@@ -15,5 +15,5 @@
 						<tr><td class='content-menu'>
 							<table border="0" cellspacing="0" cellpadding="0" border="0"><tbody>
-								<tr><td><div align="center" style="white-space:nowrap">
+								<tr><td><div id="search_div" align="center" style="white-space:nowrap">
 					<input type="text" id="em_message_search" size="16" maxlength="22" onfocus="javascript:onFocusQuickSearchEmail(this); return false;"/>
 					<a class='' onMouseOut="window.status='';return true;" title='{lang_Open_Search_Window}' onMouseOver="window.status='{lang_Open_Search_Window}';return true;" href="javascript:void(0);"  onClick="javascript:search_emails(Element('em_message_search').value)">
