ceki 2003/06/14 11:45:56
Modified: src/java/org/apache/log4j/net SMTPAppender.java
TelnetAppender.java
Log:
Formatted with Jalopy. Cosmetic changes.
Revision Changes Path
1.32 +163 -134 jakarta-log4j/src/java/org/apache/log4j/net/SMTPAppender.java
Index: SMTPAppender.java
===================================================================
RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/net/SMTPAppender.java,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -r1.31 -r1.32
--- SMTPAppender.java 18 Mar 2003 13:33:32 -0000 1.31
+++ SMTPAppender.java 14 Jun 2003 18:45:56 -0000 1.32
@@ -1,33 +1,77 @@
/*
- * Copyright (C) The Apache Software Foundation. All rights reserved.
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
*
- * This software is published under the terms of the Apache Software
- * License version 1.1, a copy of which has been included with this
- * distribution in the LICENSE.txt file. */
+ * Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "log4j" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, 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.
+ *
+ * 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 org.apache.log4j.net;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.Level;
import org.apache.log4j.helpers.CyclicBuffer;
-import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.LogLog;
-import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.spi.ErrorCode;
+import org.apache.log4j.spi.LoggingEvent;
import org.apache.log4j.spi.TriggeringEventEvaluator;
-import java.util.Properties;
+
import java.util.Date;
+import java.util.Properties;
-import javax.mail.Session;
-import javax.mail.Transport;
import javax.mail.Message;
import javax.mail.MessagingException;
-import javax.mail.internet.MimeMessage;
import javax.mail.Multipart;
-import javax.mail.internet.MimeMultipart;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.InternetAddress;
+import javax.mail.Session;
+import javax.mail.Transport;
import javax.mail.internet.AddressException;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
/**
Send an e-mail when a specific logging event occurs, typically on
@@ -49,123 +93,121 @@
private String smtpHost;
private int bufferSize = 512;
private boolean locationInfo = false;
-
protected CyclicBuffer cb = new CyclicBuffer(bufferSize);
protected Message msg;
-
protected TriggeringEventEvaluator evaluator;
-
-
/**
The default constructor will instantiate the appender with a
[EMAIL PROTECTED] TriggeringEventEvaluator} that will trigger on events with
level ERROR or higher.*/
- public
- SMTPAppender() {
+ public SMTPAppender() {
this(new DefaultEvaluator());
}
-
/**
Use <code>evaluator</code> passed as parameter as the [EMAIL PROTECTED]
TriggeringEventEvaluator} for this SMTPAppender. */
- public
- SMTPAppender(TriggeringEventEvaluator evaluator) {
+ public SMTPAppender(TriggeringEventEvaluator evaluator) {
this.evaluator = evaluator;
}
-
/**
Activate the specified options, such as the smtp host, the
recipient, from, etc. */
- public
- void activateOptions() {
- Properties props = new Properties (System.getProperties());
- if (smtpHost != null)
- props.put("mail.smtp.host", smtpHost);
+ public void activateOptions() {
+ Properties props = new Properties(System.getProperties());
+ if (smtpHost != null) {
+ props.put("mail.smtp.host", smtpHost);
+ }
Session session = Session.getInstance(props, null);
+
//session.setDebug(true);
msg = new MimeMessage(session);
- try {
- if (from != null)
- msg.setFrom(getAddress(from));
- else
- msg.setFrom();
-
- msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
- if(subject != null)
- msg.setSubject(subject);
- } catch(MessagingException e) {
- LogLog.error("Could not activate SMTPAppender options.", e );
- }
+ try {
+ if (from != null) {
+ msg.setFrom(getAddress(from));
+ } else {
+ msg.setFrom();
+ }
+
+ msg.setRecipients(Message.RecipientType.TO, parseAddress(to));
+
+ if (subject != null) {
+ msg.setSubject(subject);
+ }
+ } catch (MessagingException e) {
+ LogLog.error("Could not activate SMTPAppender options.", e);
+ }
}
/**
Perform SMTPAppender specific appending actions, mainly adding
the event to a cyclic buffer and checking if the event triggers
an e-mail to be sent. */
- public
- void append(LoggingEvent event) {
-
- if(!checkEntryConditions()) {
+ public void append(LoggingEvent event) {
+ if (!checkEntryConditions()) {
return;
}
event.getThreadName();
event.getNDC();
- if(locationInfo) {
+
+ if (locationInfo) {
event.getLocationInformation();
}
+
cb.add(event);
- if(evaluator.isTriggeringEvent(event)) {
+
+ if (evaluator.isTriggeringEvent(event)) {
sendBuffer();
}
}
- /**
- This method determines if there is a sense in attempting to append.
+ /**
+ This method determines if there is a sense in attempting to append.
- <p>It checks whether there is a set output target and also if
- there is a set layout. If these checks fail, then the boolean
- value <code>false</code> is returned. */
- protected
- boolean checkEntryConditions() {
- if(this.msg == null) {
+ <p>It checks whether there is a set output target and also if
+ there is a set layout. If these checks fail, then the boolean
+ value <code>false</code> is returned. */
+ protected boolean checkEntryConditions() {
+ if (this.msg == null) {
errorHandler.error("Message object not configured.");
+
return false;
}
- if(this.evaluator == null) {
- errorHandler.error("No TriggeringEventEvaluator is set for appender ["+
- name+"].");
+ if (this.evaluator == null) {
+ errorHandler.error(
+ "No TriggeringEventEvaluator is set for appender [" + name + "].");
+
return false;
}
+ if (this.layout == null) {
+ errorHandler.error("No layout set for appender named [" + name + "].");
- if(this.layout == null) {
- errorHandler.error("No layout set for appender named ["+name+"].");
return false;
}
+
return true;
}
-
- synchronized
- public
- void close() {
+ public synchronized void close() {
this.closed = true;
}
InternetAddress getAddress(String addressStr) {
try {
return new InternetAddress(addressStr);
- } catch(AddressException e) {
- errorHandler.error("Could not parse address ["+addressStr+"].", e,
- ErrorCode.ADDRESS_PARSE_FAILURE);
+ } catch (AddressException e) {
+ errorHandler.error(
+ "Could not parse address [" + addressStr + "].", e,
+ ErrorCode.ADDRESS_PARSE_FAILURE);
+
return null;
}
}
@@ -173,9 +215,11 @@
InternetAddress[] parseAddress(String addressStr) {
try {
return InternetAddress.parse(addressStr, true);
- } catch(AddressException e) {
- errorHandler.error("Could not parse address ["+addressStr+"].", e,
- ErrorCode.ADDRESS_PARSE_FAILURE);
+ } catch (AddressException e) {
+ errorHandler.error(
+ "Could not parse address [" + addressStr + "].", e,
+ ErrorCode.ADDRESS_PARSE_FAILURE);
+
return null;
}
}
@@ -183,26 +227,21 @@
/**
Returns value of the <b>To</b> option.
*/
- public
- String getTo() {
+ public String getTo() {
return to;
}
-
/**
The <code>SMTPAppender</code> requires a [EMAIL PROTECTED]
org.apache.log4j.Layout layout}. */
- public
- boolean requiresLayout() {
+ public boolean requiresLayout() {
return true;
}
/**
Send the contents of the cyclic buffer as an e-mail message.
*/
- protected
- void sendBuffer() {
-
+ protected void sendBuffer() {
// Note: this code already owns the monitor for this
// appender. This frees us from needing to synchronize on 'cb'.
try {
@@ -210,25 +249,35 @@
StringBuffer sbuf = new StringBuffer();
String t = layout.getHeader();
- if(t != null)
- sbuf.append(t);
- int len = cb.length();
- for(int i = 0; i < len; i++) {
- //sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
- LoggingEvent event = cb.get();
- sbuf.append(layout.format(event));
- if(layout.ignoresThrowable()) {
- String[] s = event.getThrowableStrRep();
- if (s != null) {
- for(int j = 0; j < s.length; j++) {
- sbuf.append(s[j]);
- }
- }
- }
+
+ if (t != null) {
+ sbuf.append(t);
}
+
+ int len = cb.length();
+
+ for (int i = 0; i < len; i++) {
+ //sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
+ LoggingEvent event = cb.get();
+ sbuf.append(layout.format(event));
+
+ if (layout.ignoresThrowable()) {
+ String[] s = event.getThrowableStrRep();
+
+ if (s != null) {
+ for (int j = 0; j < s.length; j++) {
+ sbuf.append(s[j]);
+ }
+ }
+ }
+ }
+
t = layout.getFooter();
- if(t != null)
- sbuf.append(t);
+
+ if (t != null) {
+ sbuf.append(t);
+ }
+
part.setContent(sbuf.toString(), layout.getContentType());
Multipart mp = new MimeMultipart();
@@ -237,34 +286,29 @@
msg.setSentDate(new Date());
Transport.send(msg);
- } catch(Exception e) {
+ } catch (Exception e) {
LogLog.error("Error occured while sending e-mail notification.", e);
}
}
-
-
/**
Returns value of the <b>EvaluatorClass</b> option.
*/
- public
- String getEvaluatorClass() {
- return evaluator == null ? null : evaluator.getClass().getName();
+ public String getEvaluatorClass() {
+ return (evaluator == null) ? null : evaluator.getClass().getName();
}
/**
Returns value of the <b>From</b> option.
*/
- public
- String getFrom() {
+ public String getFrom() {
return from;
}
/**
Returns value of the <b>Subject</b> option.
*/
- public
- String getSubject() {
+ public String getSubject() {
return subject;
}
@@ -272,8 +316,7 @@
The <b>From</b> option takes a string value which should be a
e-mail address of the sender.
*/
- public
- void setFrom(String from) {
+ public void setFrom(String from) {
this.from = from;
}
@@ -281,12 +324,10 @@
The <b>Subject</b> option takes a string value which should be a
the subject of the e-mail message.
*/
- public
- void setSubject(String subject) {
+ public void setSubject(String subject) {
this.subject = subject;
}
-
/**
The <b>BufferSize</b> option takes a positive integer
representing the maximum number of logging events to collect in a
@@ -294,8 +335,7 @@
oldest events are deleted as new events are added to the
buffer. By default the size of the cyclic buffer is 512 events.
*/
- public
- void setBufferSize(int bufferSize) {
+ public void setBufferSize(int bufferSize) {
this.bufferSize = bufferSize;
cb.resize(bufferSize);
}
@@ -304,16 +344,14 @@
The <b>SMTPHost</b> option takes a string value which should be a
the host name of the SMTP server that will send the e-mail message.
*/
- public
- void setSMTPHost(String smtpHost) {
+ public void setSMTPHost(String smtpHost) {
this.smtpHost = smtpHost;
}
/**
Returns value of the <b>SMTPHost</b> option.
*/
- public
- String getSMTPHost() {
+ public String getSMTPHost() {
return smtpHost;
}
@@ -321,18 +359,14 @@
The <b>To</b> option takes a string value which should be a
comma separated list of e-mail address of the recipients.
*/
- public
- void setTo(String to) {
+ public void setTo(String to) {
this.to = to;
}
-
-
/**
Returns value of the <b>BufferSize</b> option.
*/
- public
- int getBufferSize() {
+ public int getBufferSize() {
return bufferSize;
}
@@ -343,15 +377,12 @@
be instantiated and assigned as the triggering event evaluator
for the SMTPAppender.
*/
- public
- void setEvaluatorClass(String value) {
- evaluator = (TriggeringEventEvaluator)
- OptionConverter.instantiateByClassName(value,
- TriggeringEventEvaluator.class,
- evaluator);
+ public void setEvaluatorClass(String value) {
+ evaluator =
+ (TriggeringEventEvaluator) OptionConverter.instantiateByClassName(
+ value, TriggeringEventEvaluator.class, evaluator);
}
-
/**
The <b>LocationInfo</b> option takes a boolean value. By
default, it is set to false which means there will be no effort
@@ -363,20 +394,19 @@
<p>Location information extraction is comparatively very slow and
should be avoided unless performance is not a concern.
*/
- public
- void setLocationInfo(boolean locationInfo) {
+ public void setLocationInfo(boolean locationInfo) {
this.locationInfo = locationInfo;
}
/**
Returns value of the <b>LocationInfo</b> option.
*/
- public
- boolean getLocationInfo() {
+ public boolean getLocationInfo() {
return locationInfo;
}
}
+
class DefaultEvaluator implements TriggeringEventEvaluator {
/**
Is this <code>event</code> the e-mail triggering event?
@@ -384,8 +414,7 @@
<p>This method returns <code>true</code>, if the event level
has ERROR level or higher. Otherwise it returns
<code>false</code>. */
- public
- boolean isTriggeringEvent(LoggingEvent event) {
+ public boolean isTriggeringEvent(LoggingEvent event) {
return event.getLevel().isGreaterOrEqual(Level.ERROR);
}
}
1.4 +93 -46 jakarta-log4j/src/java/org/apache/log4j/net/TelnetAppender.java
Index: TelnetAppender.java
===================================================================
RCS file: /home/cvs/jakarta-log4j/src/java/org/apache/log4j/net/TelnetAppender.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- TelnetAppender.java 9 May 2002 19:53:37 -0000 1.3
+++ TelnetAppender.java 14 Jun 2003 18:45:56 -0000 1.4
@@ -1,19 +1,65 @@
/*
- * Copyright (C) The Apache Software Foundation. All rights reserved.
+ * ============================================================================
+ * The Apache Software License, Version 1.1
+ * ============================================================================
*
- * This software is published under the terms of the Apache Software
- * License version 1.1, a copy of which has been included with this
- * distribution in the LICENSE.txt file. */
+ * Copyright (C) 1999 The Apache Software Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. The end-user documentation included with the redistribution, if any, must
+ * include the following acknowledgment: "This product includes software
+ * developed by the Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself, if
+ * and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "log4j" and "Apache Software Foundation" must not be used to
+ * endorse or promote products derived from this software without prior
+ * written permission. For written permission, please contact
+ * [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache", nor may
+ * "Apache" appear in their name, without prior written permission of the
+ * Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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
+ * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
+ * DING, 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.
+ *
+ * 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 org.apache.log4j.net;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.Layout;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LoggingEvent;
+
import java.io.*;
+
import java.net.*;
+
import java.util.*;
-import org.apache.log4j.Layout;
-import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.AppenderSkeleton;
-import org.apache.log4j.helpers.LogLog;
+
/**
<p>The TelnetAppender is a log4j appender that specializes in
@@ -42,13 +88,11 @@
@author <a HREF="mailto:[EMAIL PROTECTED]">Jay Funnell</a>
*/
-
public class TelnetAppender extends AppenderSkeleton {
-
private SocketHandler sh;
private int port = 23;
- /**
+ /**
This appender requires a layout to format the text to the
attached client(s). */
public boolean requiresLayout() {
@@ -61,23 +105,19 @@
try {
sh = new SocketHandler(port);
sh.start();
- }
- catch(Exception e) {
+ } catch (Exception e) {
e.printStackTrace();
}
}
- public
- int getPort() {
+ public int getPort() {
return port;
}
- public
- void setPort(int port) {
+ public void setPort(int port) {
this.port = port;
}
-
/** shuts down the appender. */
public void close() {
sh.finalize();
@@ -87,14 +127,17 @@
message to each connected client. */
protected void append(LoggingEvent event) {
sh.send(this.layout.format(event));
- if(layout.ignoresThrowable()) {
+
+ if (layout.ignoresThrowable()) {
String[] s = event.getThrowableStrRep();
+
if (s != null) {
- int len = s.length;
- for(int i = 0; i < len; i++) {
- sh.send(s[i]);
- sh.send(Layout.LINE_SEP);
- }
+ int len = s.length;
+
+ for (int i = 0; i < len; i++) {
+ sh.send(s[i]);
+ sh.send(Layout.LINE_SEP);
+ }
}
}
}
@@ -105,36 +148,43 @@
clients. It is threaded so that clients can connect/disconnect
asynchronously. */
protected class SocketHandler extends Thread {
-
private boolean done = false;
private Vector writers = new Vector();
private Vector connections = new Vector();
private ServerSocket serverSocket;
private int MAX_CONNECTIONS = 20;
+ public SocketHandler(int port) throws IOException {
+ serverSocket = new ServerSocket(port);
+ }
+
/** make sure we close all network connections when this handler is destroyed.
*/
public void finalize() {
- for(Enumeration e = connections.elements();e.hasMoreElements();) {
+ for (Enumeration e = connections.elements(); e.hasMoreElements();) {
try {
- ((Socket)e.nextElement()).close();
- } catch(Exception ex) {
+ ((Socket) e.nextElement()).close();
+ } catch (Exception ex) {
}
}
+
try {
serverSocket.close();
- } catch(Exception ex) {
+ } catch (Exception ex) {
}
+
done = true;
}
/** sends a message to each of the clients in telnet-friendly output. */
public void send(String message) {
Enumeration ce = connections.elements();
- for(Enumeration e = writers.elements();e.hasMoreElements();) {
- Socket sock = (Socket)ce.nextElement();
- PrintWriter writer = (PrintWriter)e.nextElement();
+
+ for (Enumeration e = writers.elements(); e.hasMoreElements();) {
+ Socket sock = (Socket) ce.nextElement();
+ PrintWriter writer = (PrintWriter) e.nextElement();
writer.print(message);
- if(writer.checkError()) {
+
+ if (writer.checkError()) {
// The client has closed the connection, remove it from our list:
connections.remove(sock);
writers.remove(writer);
@@ -142,35 +192,32 @@
}
}
- /**
- Continually accepts client connections. Client connections
- are refused when MAX_CONNECTIONS is reached.
+ /**
+ Continually accepts client connections. Client connections
+ are refused when MAX_CONNECTIONS is reached.
*/
public void run() {
- while(!done) {
+ while (!done) {
try {
Socket newClient = serverSocket.accept();
PrintWriter pw = new PrintWriter(newClient.getOutputStream());
- if(connections.size() < MAX_CONNECTIONS) {
+
+ if (connections.size() < MAX_CONNECTIONS) {
connections.addElement(newClient);
writers.addElement(pw);
- pw.print("TelnetAppender v1.0 (" + connections.size()
- + " active connections)\r\n\r\n");
+ pw.print(
+ "TelnetAppender v1.0 (" + connections.size()
+ + " active connections)\r\n\r\n");
pw.flush();
} else {
pw.print("Too many connections.\r\n");
pw.flush();
newClient.close();
}
- } catch(Exception e) {
+ } catch (Exception e) {
LogLog.error("Encountered error while in SocketHandler loop.", e);
}
}
}
-
- public SocketHandler(int port) throws IOException {
- serverSocket = new ServerSocket(port);
- }
-
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]