summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/protocol-constants.h1
-rw-r--r--src/torrent-cell-renderer.c182
-rw-r--r--src/torrent-cell-renderer.h1
-rw-r--r--src/torrent.c11
-rw-r--r--src/torrent.h1
-rw-r--r--src/trg-torrent-model.c71
-rw-r--r--src/trg-torrent-model.h2
-rw-r--r--src/trg-torrent-tree-view.c2
8 files changed, 130 insertions, 141 deletions
diff --git a/src/protocol-constants.h b/src/protocol-constants.h
index c4a21eb..293a937 100644
--- a/src/protocol-constants.h
+++ b/src/protocol-constants.h
@@ -68,6 +68,7 @@
#define FIELD_ISFINISHED "isFinished"
#define FIELD_ISPRIVATE "isPrivate"
#define FIELD_ERRORSTR "errorString"
+#define FIELD_ERROR "error"
#define FIELD_BANDWIDTH_PRIORITY "bandwidthPriority"
#define FIELD_UPLOAD_LIMIT "uploadLimit"
#define FIELD_UPLOAD_LIMITED "uploadLimited"
diff --git a/src/torrent-cell-renderer.c b/src/torrent-cell-renderer.c
index d49de36..1d20f6f 100644
--- a/src/torrent-cell-renderer.c
+++ b/src/torrent-cell-renderer.c
@@ -20,39 +20,24 @@
#include "torrent.h"
#include "util.h"
-/* #define TEST_RTL */
-
- /*"status", TORRENT_COLUMN_FLAGS,
- "ratio", TORRENT_COLUMN_RATIO,
- "downloaded", TORRENT_COLUMN_DOWNLOADED,
- "name", TORRENT_COLUMN_NAME,
- "sizeWhenDone", TORRENT_COLUMN_SIZE,
- "uploaded", TORRENT_COLUMN_UPLOADED,
- "percentComplete", TORRENT_COLUMN_DONE,
- "upSpeed", TORRENT_COLUMN_UPSPEED,
- "downSpeed", TORRENT_COLUMN_DOWNSPEED,
- "leechers", TORRENT_COLUMN_LEECHERS,
- "seeds", TORRENT_COLUMN_SEEDS,
- "eta", TORRENT_COLUMN_ETA,
- "json", TORRENT_COLUMN_JSON,
- "connected", TORRENT_COLUMN_PEERS_CONNECTED,*/
-
enum
{
P_STATUS = 1,
P_RATIO,
P_DOWNLOADED,
+ P_ERROR,
P_NAME,
P_SIZEWHENDONE,
P_UPLOADED,
P_PERCENTCOMPLETE,
P_UPSPEED,
P_DOWNSPEED,
- P_LEECHERS,
- P_SEEDS,
+ P_PEERSGETTINGFROMUS,
+ P_PEERSTOUS,
P_ETA,
P_JSON,
P_CONNECTED,
+ P_FILECOUNT,
P_BAR_HEIGHT,
P_COMPACT
};
@@ -111,7 +96,9 @@ struct TorrentCellRendererPrivate
gint64 peersFromUs;
gint64 peersToUs;
gint64 connected;
+ guint fileCount;
gint64 eta;
+ gint64 error;
gboolean compact;
};
@@ -288,7 +275,12 @@ getStatusString( GString * gstr,
//TODO: handle metadata for downloading
//TODO: handle errors
- if (priv->flags & TORRENT_FLAG_DOWNLOADING) {
+ if ( priv->error ) {
+ const char * fmt[] = { NULL, N_( "Tracker gave a warning: \"%s\"" ),
+ N_( "Tracker gave an error: \"%s\"" ),
+ N_( "Error: %s" ) };
+ g_string_append_printf( gstr, _( fmt[priv->error] ), torrent_get_errorstr(priv->json) );
+ } else if (priv->flags & TORRENT_FLAG_DOWNLOADING) {
g_string_append_printf( gstr,
ngettext( "Downloading from %1$'d of %2$'d connected peer",
"Downloading from %1$'d of %2$'d connected peers",
@@ -324,19 +316,20 @@ getStatusString( GString * gstr,
static GdkPixbuf*
get_icon( TorrentCellRenderer *r, GtkIconSize icon_size, GtkWidget * for_widget )
{
+ struct TorrentCellRendererPrivate *p = r->priv;
+
const char * mime_type;
- /*const tr_info * info = tr_torrentInfo( tor );
- if( info->fileCount == 0 )
+ if( p->fileCount == 0 )
mime_type = UNKNOWN_MIME_TYPE;
- else if( info->fileCount > 1 )
+ else if( p->fileCount > 1 )
mime_type = DIRECTORY_MIME_TYPE;
- else if( strchr( info->files[0].name, '/' ) != NULL )
+ /*else if( strchr( info->files[0].name, '/' ) != NULL )
mime_type = DIRECTORY_MIME_TYPE;
else
mime_type = gtr_get_mime_type_from_filename( info->files[0].name );*/
-
- mime_type = DIRECTORY_MIME_TYPE;
+ else
+ mime_type = FILE_MIME_TYPE;
//return NULL;
return gtr_get_mime_type_icon( mime_type, icon_size, for_widget );
@@ -495,10 +488,10 @@ torrent_cell_renderer_get_size( GtkCellRenderer * cell,
static void
get_text_color( GtkWidget * w, TorrentCellRenderer *r, GtrColor * setme )
{
- /*static const GdkRGBA red = { 1.0, 0, 0, 0 };
- if( st->error )
+ static const GdkRGBA red = { 1.0, 0, 0, 0 };
+ if( r->priv->error )
*setme = red;
- else */if( r->priv->flags & TORRENT_FLAG_PAUSED )
+ else if( r->priv->flags & TORRENT_FLAG_PAUSED )
gtk_style_context_get_color( gtk_widget_get_style_context( w ), GTK_STATE_FLAG_INSENSITIVE, setme );
else
gtk_style_context_get_color( gtk_widget_get_style_context( w ), GTK_STATE_FLAG_NORMAL, setme );
@@ -557,35 +550,70 @@ torrent_cell_renderer_render( GtkCellRenderer * cell,
}
}
-static void
-torrent_cell_renderer_set_property( GObject * object,
- guint property_id,
- const GValue * v,
- GParamSpec * pspec )
-{
- TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object );
- struct TorrentCellRendererPrivate * p = self->priv;
-
- switch( property_id )
- {
- case P_JSON: p->json = g_value_get_pointer( v ); break;
- case P_STATUS: p->flags = g_value_get_uint( v ); break;
- case P_SIZEWHENDONE: p->sizeWhenDone = g_value_get_int64( v ); break;
- case P_DOWNLOADED: p->downloaded = g_value_get_int64( v ); break;
- case P_UPLOADED: p->uploadedEver = g_value_get_int64( v ); break;
- case P_UPSPEED: p->upSpeed = g_value_get_int64( v ); break;
- case P_DOWNSPEED: p->downSpeed = g_value_get_int64( v ); break;
- case P_LEECHERS: p->peersFromUs = g_value_get_int64( v ); break;
- case P_CONNECTED: p->connected = g_value_get_int64( v ); break;
- case P_ETA: p->eta = g_value_get_int64( v ); break;
- case P_SEEDS: p->peersToUs = g_value_get_int64( v ); break;
- case P_NAME: p->name = g_value_get_string( v ); break;
- case P_RATIO: p->ratio = g_value_get_double( v ); break;
- case P_PERCENTCOMPLETE: p->done = g_value_get_double( v ); break;
- case P_BAR_HEIGHT: p->bar_height = g_value_get_int( v ); break;
- case P_COMPACT: p->compact = g_value_get_boolean( v ); break;
- default: G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec ); break;
- }
+static void torrent_cell_renderer_set_property(GObject * object,
+ guint property_id, const GValue * v, GParamSpec * pspec) {
+ TorrentCellRenderer * self = TORRENT_CELL_RENDERER( object );
+ struct TorrentCellRendererPrivate * p = self->priv;
+
+ switch (property_id) {
+ case P_JSON:
+ p->json = g_value_get_pointer(v);
+ break;
+ case P_STATUS:
+ p->flags = g_value_get_uint(v);
+ break;
+ case P_SIZEWHENDONE:
+ p->sizeWhenDone = g_value_get_int64(v);
+ break;
+ case P_DOWNLOADED:
+ p->downloaded = g_value_get_int64(v);
+ break;
+ case P_UPLOADED:
+ p->uploadedEver = g_value_get_int64(v);
+ break;
+ case P_UPSPEED:
+ p->upSpeed = g_value_get_int64(v);
+ break;
+ case P_DOWNSPEED:
+ p->downSpeed = g_value_get_int64(v);
+ break;
+ case P_PEERSGETTINGFROMUS:
+ p->peersFromUs = g_value_get_int64(v);
+ break;
+ case P_CONNECTED:
+ p->connected = g_value_get_int64(v);
+ break;
+ case P_FILECOUNT:
+ p->fileCount = g_value_get_uint(v);
+ break;
+ case P_ETA:
+ p->eta = g_value_get_int64(v);
+ break;
+ case P_PEERSTOUS:
+ p->peersToUs = g_value_get_int64(v);
+ break;
+ case P_ERROR:
+ p->error = g_value_get_int64(v);
+ break;
+ case P_NAME:
+ p->name = g_value_get_string(v);
+ break;
+ case P_RATIO:
+ p->ratio = g_value_get_double(v);
+ break;
+ case P_PERCENTCOMPLETE:
+ p->done = g_value_get_double(v);
+ break;
+ case P_BAR_HEIGHT:
+ p->bar_height = g_value_get_int(v);
+ break;
+ case P_COMPACT:
+ p->compact = g_value_get_boolean(v);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, pspec);
+ break;
+ }
}
static void
@@ -679,6 +707,18 @@ torrent_cell_renderer_class_init( TorrentCellRendererClass * klass )
0, G_MAXUINT, 0,
G_PARAM_READWRITE ) );
+ g_object_class_install_property( gobject_class, P_FILECOUNT,
+ g_param_spec_uint( "fileCount", NULL,
+ "fileCount",
+ 0, G_MAXUINT, 0,
+ G_PARAM_READWRITE ) );
+
+ g_object_class_install_property( gobject_class, P_ERROR,
+ g_param_spec_int64( "error", NULL,
+ "error",
+ 0, G_MAXINT64, 0,
+ G_PARAM_READWRITE ) );
+
g_object_class_install_property( gobject_class, P_UPSPEED,
g_param_spec_int64( "upSpeed", NULL,
"upSpeed",
@@ -703,22 +743,22 @@ torrent_cell_renderer_class_init( TorrentCellRendererClass * klass )
0, G_MAXINT64, 0,
G_PARAM_READWRITE ) );
- g_object_class_install_property( gobject_class, P_LEECHERS,
- g_param_spec_int64( "leechers", NULL,
- "leechers",
+ g_object_class_install_property( gobject_class, P_PEERSGETTINGFROMUS,
+ g_param_spec_int64( "peersGettingFromUs", NULL,
+ "peersGettingFromUs",
-1, G_MAXINT64, 0,
G_PARAM_READWRITE ) );
- g_object_class_install_property( gobject_class, P_SEEDS,
- g_param_spec_int64( "seeds", NULL,
- "seeds",
+ g_object_class_install_property( gobject_class, P_PEERSTOUS,
+ g_param_spec_int64( "peersToUs", NULL,
+ "peersToUs",
-1, G_MAXINT64, 0,
G_PARAM_READWRITE ) );
g_object_class_install_property( gobject_class, P_ETA,
g_param_spec_int64( "eta", NULL,
"eta",
- -1, G_MAXINT64, 0,
+ -2, G_MAXINT64, 0,
G_PARAM_READWRITE ) );
g_object_class_install_property( gobject_class, P_CONNECTED,
@@ -790,16 +830,13 @@ render_compact( TorrentCellRenderer * cell,
GdkRectangle fill_area;
GdkPixbuf * icon;
GtrColor text_color;
- gboolean seed;
-
- //TODO: Handle errors
+ //TODO
+ //gboolean seed;
struct TorrentCellRendererPrivate * p = cell->priv;
- //const tr_torrent * tor = p->tor;
- //const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor );
const gboolean active = ( p->flags & ~TORRENT_FLAG_PAUSED ) && ( p->flags & ~TORRENT_FLAG_DOWNLOADING_WAIT ) && ( p->flags & ~TORRENT_FLAG_SEEDING_WAIT );
- const gboolean sensitive = active;// || st->error;
+ const gboolean sensitive = active || p->error;
GString * gstr_stat = p->gstr1;
icon = get_icon( cell, COMPACT_ICON_SIZE, widget );
@@ -869,11 +906,12 @@ render_full( TorrentCellRenderer * cell,
GdkRectangle prct_area;
GdkPixbuf * icon;
GtrColor text_color;
+ //TODO
//gboolean seed;
struct TorrentCellRendererPrivate * p = cell->priv;
const gboolean active = ( p->flags & ~TORRENT_FLAG_PAUSED ) && ( p->flags & ~TORRENT_FLAG_DOWNLOADING_WAIT ) && ( p->flags & ~TORRENT_FLAG_SEEDING_WAIT );
- const gboolean sensitive = active;// || st->error;
+ const gboolean sensitive = active || p->error;
GString * gstr_prog = p->gstr1;
GString * gstr_stat = p->gstr2;
diff --git a/src/torrent-cell-renderer.h b/src/torrent-cell-renderer.h
index 7e59483..14da210 100644
--- a/src/torrent-cell-renderer.h
+++ b/src/torrent-cell-renderer.h
@@ -18,6 +18,7 @@
#define GTR_UNICODE_UP "\xE2\x86\x91"
#define GTR_UNICODE_DOWN "\xE2\x86\x93"
#define DIRECTORY_MIME_TYPE "folder"
+#define FILE_MIME_TYPE "file"
#define UNKNOWN_MIME_TYPE "unknown"
#define TORRENT_CELL_RENDERER_TYPE ( torrent_cell_renderer_get_type( ) )
diff --git a/src/torrent.c b/src/torrent.c
index e86cda8..d605835 100644
--- a/src/torrent.c
+++ b/src/torrent.c
@@ -282,7 +282,7 @@ torrent_get_flags(JsonObject * t, gint64 rpcv, gint64 status,
flags |= TORRENT_FLAG_ACTIVE;
}
- if (strlen(torrent_get_errorstr(t)) > 0)
+ if (torrent_get_error(t) > 0)
flags |= TORRENT_FLAG_ERROR;
return flags;
@@ -320,6 +320,14 @@ const gchar *torrent_get_errorstr(JsonObject * t)
return json_object_get_string_member(t, FIELD_ERRORSTR);
}
+gint64 torrent_get_error(JsonObject *t)
+{
+ if (!json_object_has_member(t, FIELD_ERROR))
+ return 0;
+ else
+ return json_object_get_int_member(t, FIELD_ERROR);
+}
+
gchar *torrent_get_status_string(gint64 rpcv, gint64 value, guint flags)
{
if (rpcv >= NEW_STATUS_RPC_VERSION) {
@@ -420,7 +428,6 @@ JsonArray *get_torrents(JsonObject * response)
JsonArray *torrent_get_files(JsonObject * args)
{
- g_assert(json_object_get_array_member(args, FIELD_FILES));
return json_object_get_array_member(args, FIELD_FILES);
}
diff --git a/src/torrent.h b/src/torrent.h
index 16c1ad9..1bafd14 100644
--- a/src/torrent.h
+++ b/src/torrent.h
@@ -52,6 +52,7 @@ gint64 torrent_get_eta(JsonObject * t);
gint64 torrent_get_uploaded(JsonObject * t);
gint64 torrent_get_downloaded(JsonObject * t);
const gchar *torrent_get_errorstr(JsonObject * t);
+gint64 torrent_get_error(JsonObject *t);
const gchar *torrent_get_download_dir(JsonObject * t);
const gchar *torrent_get_comment(JsonObject * t);
gint64 torrent_get_have_unchecked(JsonObject * t);
diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c
index 2df9603..60979aa 100644
--- a/src/trg-torrent-model.c
+++ b/src/trg-torrent-model.c
@@ -199,6 +199,7 @@ static void trg_torrent_model_init(TrgTorrentModel * self)
column_types[TORRENT_COLUMN_ICON] = G_TYPE_STRING;
column_types[TORRENT_COLUMN_NAME] = G_TYPE_STRING;
+ column_types[TORRENT_COLUMN_ERROR] = G_TYPE_INT64;
column_types[TORRENT_COLUMN_SIZEWHENDONE] = G_TYPE_INT64;
column_types[TORRENT_COLUMN_PERCENTDONE] = G_TYPE_DOUBLE;
column_types[TORRENT_COLUMN_STATUS] = G_TYPE_STRING;
@@ -234,6 +235,7 @@ static void trg_torrent_model_init(TrgTorrentModel * self)
column_types[TORRENT_COLUMN_TRACKERHOST] = G_TYPE_STRING;
column_types[TORRENT_COLUMN_QUEUE_POSITION] = G_TYPE_INT64;
column_types[TORRENT_COLUMN_LASTACTIVE] = G_TYPE_INT64;
+ column_types[TORRENT_COLUMN_FILECOUNT] = G_TYPE_UINT;
gtk_list_store_set_column_types(GTK_LIST_STORE(self),
TORRENT_COLUMN_COLUMNS, column_types);
@@ -470,76 +472,12 @@ update_torrent_iter(TrgTorrentModel * model,
peerfrom_get_resume(pf));
}
}
-#ifdef DEBUG
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_ICON, statusIcon, -1);
- gtk_list_store_set(ls, iter,
- TORRENT_COLUMN_NAME, torrent_get_name(t), -1);
- gtk_list_store_set(ls, iter,
- TORRENT_COLUMN_SIZEWHENDONE, torrent_get_size(t), -1);
- gtk_list_store_set(ls, iter,
- TORRENT_COLUMN_PERCENTDONE,
- (newFlags & TORRENT_FLAG_CHECKING) ?
- torrent_get_recheck_progress(t)
- : torrent_get_percent_done(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_STATUS, statusString, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_DOWNSPEED, downRate, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FLAGS, newFlags, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_UPSPEED, upRate, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_ETA, torrent_get_eta(t),
- -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_UPLOADED, uploaded, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_DOWNLOADED, downloaded,
- -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_RATIO, uploaded > 0
- && downloaded >
- 0 ? (double) uploaded / (double) downloaded : 0,
- -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_ID, id, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_JSON, t, -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_UPDATESERIAL, serial, -1);
- gtk_list_store_set(ls, iter,
- TORRENT_COLUMN_ADDED, torrent_get_added_date(t),
- -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_DOWNLOADDIR, downloadDir,
- -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_BANDWIDTH_PRIORITY,
- torrent_get_bandwidth_priority(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_DONE_DATE,
- torrent_get_done_date(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMPEX,
- peerfrom_get_pex(pf), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMDHT,
- peerfrom_get_dht(pf), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMTRACKERS,
- peerfrom_get_trackers(pf), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMLTEP,
- peerfrom_get_ltep(pf), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMRESUME,
- peerfrom_get_resume(pf), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_FROMINCOMING,
- peerfrom_get_incoming(pf), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEER_SOURCES, peerSources,
- -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEERS_CONNECTED,
- torrent_get_peers_connected(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEERS_TO_US,
- torrent_get_peers_sending_to_us(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_PEERS_FROM_US,
- torrent_get_peers_getting_from_us(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_TRACKERHOST,
- firstTrackerHost ? firstTrackerHost : "", -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_QUEUE_POSITION,
- torrent_get_queue_position(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_LASTACTIVE,
- torrent_get_activity_date(t), -1);
- gtk_list_store_set(ls, iter, TORRENT_COLUMN_HAVE_VALID,
- haveValid, -1);
-
-#else
gtk_list_store_set(ls, iter, TORRENT_COLUMN_ICON, statusIcon,
TORRENT_COLUMN_ADDED, torrent_get_added_date(t),
+ TORRENT_COLUMN_FILECOUNT, json_array_get_length(torrent_get_files(t)),
TORRENT_COLUMN_DONE_DATE, torrent_get_done_date(t),
TORRENT_COLUMN_NAME, torrent_get_name(t),
+ TORRENT_COLUMN_ERROR, torrent_get_error(t),
TORRENT_COLUMN_SIZEWHENDONE, torrent_get_size(t),
TORRENT_COLUMN_PERCENTDONE,
(newFlags & TORRENT_FLAG_CHECKING) ?
@@ -581,7 +519,6 @@ update_torrent_iter(TrgTorrentModel * model,
TORRENT_COLUMN_TRACKERHOST,
firstTrackerHost ? firstTrackerHost : "",
TORRENT_COLUMN_UPDATESERIAL, serial, -1);
-#endif
if (!lastDownloadDir || g_strcmp0(downloadDir, lastDownloadDir)) {
gchar *shortDownloadDir = shorten_download_dir(tc, downloadDir);
diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h
index ddc5e98..7869da9 100644
--- a/src/trg-torrent-model.h
+++ b/src/trg-torrent-model.h
@@ -139,6 +139,8 @@ enum {
TORRENT_COLUMN_TRACKERHOST,
TORRENT_COLUMN_QUEUE_POSITION,
TORRENT_COLUMN_LASTACTIVE,
+ TORRENT_COLUMN_FILECOUNT,
+ TORRENT_COLUMN_ERROR,
TORRENT_COLUMN_COLUMNS
};
diff --git a/src/trg-torrent-tree-view.c b/src/trg-torrent-tree-view.c
index 87208a2..8eba1bf 100644
--- a/src/trg-torrent-tree-view.c
+++ b/src/trg-torrent-tree-view.c
@@ -169,6 +169,8 @@ static void setup_classic_layout(TrgTorrentTreeView *tv)
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes("",
renderer,
"status", TORRENT_COLUMN_FLAGS,
+ "error", TORRENT_COLUMN_ERROR,
+ "fileCount", TORRENT_COLUMN_FILECOUNT,
"ratio", TORRENT_COLUMN_RATIO,
"downloaded", TORRENT_COLUMN_DOWNLOADED,
"sizeWhenDone", TORRENT_COLUMN_SIZEWHENDONE,