add max half-open connections
This commit is contained in:
parent
7196070f59
commit
94ca1789d5
|
@ -14,6 +14,7 @@ Deluge 0.5.6 (xx October 2007)
|
||||||
* Use SVG for internal logo usage (except on Win32)
|
* Use SVG for internal logo usage (except on Win32)
|
||||||
* Use theme for tray icon instead of hard-coded
|
* Use theme for tray icon instead of hard-coded
|
||||||
* Properly release port on shutdown
|
* Properly release port on shutdown
|
||||||
|
* New max half-open connections setting to deal with cheap/broken routers
|
||||||
* Inherit UPnP fixes from libtorrent
|
* Inherit UPnP fixes from libtorrent
|
||||||
* Use threading for everything, instead of spawnning
|
* Use threading for everything, instead of spawnning
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,10 +1,10 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
|
||||||
<!--Generated with glade3 3.2.2 on Sun Sep 30 18:47:40 2007 by markybob@peg-->
|
<!--Generated with glade3 3.2.2 on Tue Oct 9 20:54:45 2007 by markybob@peg-->
|
||||||
<glade-interface>
|
<glade-interface>
|
||||||
<widget class="GtkAssistant" id="wizard">
|
<widget class="GtkAssistant" id="wizard">
|
||||||
<property name="width_request">500</property>
|
<property name="width_request">500</property>
|
||||||
<property name="height_request">320</property>
|
<property name="height_request">335</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="border_width">2</property>
|
<property name="border_width">2</property>
|
||||||
<property name="title" translatable="yes">First Launch Configuration</property>
|
<property name="title" translatable="yes">First Launch Configuration</property>
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
<widget class="GtkTable" id="table1">
|
<widget class="GtkTable" id="table1">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
<property name="n_rows">5</property>
|
<property name="n_rows">6</property>
|
||||||
<property name="n_columns">2</property>
|
<property name="n_columns">2</property>
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkAlignment" id="alignment7">
|
<widget class="GtkAlignment" id="alignment7">
|
||||||
|
@ -234,6 +234,7 @@
|
||||||
<widget class="GtkLabel" id="label7">
|
<widget class="GtkLabel" id="label7">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The number of active torrents that Deluge will run. Set to -1 for unlimited.</property>
|
||||||
<property name="label" translatable="yes">Maximum Active Torrents:</property>
|
<property name="label" translatable="yes">Maximum Active Torrents:</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -253,6 +254,7 @@
|
||||||
<widget class="GtkLabel" id="label9">
|
<widget class="GtkLabel" id="label9">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum upload slots for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="label" translatable="yes">Maximum Upload Slots:</property>
|
<property name="label" translatable="yes">Maximum Upload Slots:</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -272,6 +274,7 @@
|
||||||
<widget class="GtkLabel" id="label8">
|
<widget class="GtkLabel" id="label8">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum upload speed for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="label" translatable="yes">Maximum Upload Speed (KiB/s):</property>
|
<property name="label" translatable="yes">Maximum Upload Speed (KiB/s):</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -291,6 +294,7 @@
|
||||||
<widget class="GtkLabel" id="label6">
|
<widget class="GtkLabel" id="label6">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
|
||||||
<property name="label" translatable="yes">Maximum Connections:</property>
|
<property name="label" translatable="yes">Maximum Connections:</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -302,28 +306,6 @@
|
||||||
<property name="y_options">GTK_EXPAND</property>
|
<property name="y_options">GTK_EXPAND</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
|
||||||
<widget class="GtkAlignment" id="alignment8">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
|
||||||
<child>
|
|
||||||
<widget class="GtkSpinButton" id="spin_torrents">
|
|
||||||
<property name="visible">True</property>
|
|
||||||
<property name="can_focus">True</property>
|
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
|
||||||
<property name="adjustment">0 -1 100 1 10 10</property>
|
|
||||||
</widget>
|
|
||||||
</child>
|
|
||||||
</widget>
|
|
||||||
<packing>
|
|
||||||
<property name="left_attach">1</property>
|
|
||||||
<property name="right_attach">2</property>
|
|
||||||
<property name="top_attach">4</property>
|
|
||||||
<property name="bottom_attach">5</property>
|
|
||||||
<property name="x_options">GTK_EXPAND</property>
|
|
||||||
<property name="y_options">GTK_EXPAND</property>
|
|
||||||
</packing>
|
|
||||||
</child>
|
|
||||||
<child>
|
<child>
|
||||||
<widget class="GtkAlignment" id="alignment3">
|
<widget class="GtkAlignment" id="alignment3">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
|
@ -333,6 +315,7 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum upload slots for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="adjustment">0 -1 9000 1 10 10</property>
|
<property name="adjustment">0 -1 9000 1 10 10</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -355,6 +338,7 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum upload speed for all torrents. Set -1 for unlimited.</property>
|
||||||
<property name="adjustment">0 -1 9000 1 10 10</property>
|
<property name="adjustment">0 -1 9000 1 10 10</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -377,6 +361,7 @@
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum number of connections allowed. Set -1 for unlimited.</property>
|
||||||
<property name="adjustment">0 -1 9000 1 10 10</property>
|
<property name="adjustment">0 -1 9000 1 10 10</property>
|
||||||
</widget>
|
</widget>
|
||||||
</child>
|
</child>
|
||||||
|
@ -438,6 +423,72 @@
|
||||||
<property name="y_options">GTK_EXPAND</property>
|
<property name="y_options">GTK_EXPAND</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment13">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkLabel" id="label13">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum half-open connections. A high value may crash some cheap routers. Set -1 for unlimited.</property>
|
||||||
|
<property name="label" translatable="yes">Maximum Half-Open Connections:</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
<property name="bottom_attach">6</property>
|
||||||
|
<property name="x_options">GTK_EXPAND</property>
|
||||||
|
<property name="y_options">GTK_EXPAND</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment15">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSpinButton" id="spin_max_half_open">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The maximum half-open connections. A high value may crash some cheap routers. Set -1 for unlimited.</property>
|
||||||
|
<property name="adjustment">8 -1 9000 1 10 10</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">5</property>
|
||||||
|
<property name="bottom_attach">6</property>
|
||||||
|
<property name="x_options">GTK_EXPAND</property>
|
||||||
|
<property name="y_options">GTK_EXPAND</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkAlignment" id="alignment16">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<child>
|
||||||
|
<widget class="GtkSpinButton" id="spin_torrents">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">True</property>
|
||||||
|
<property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
|
||||||
|
<property name="tooltip" translatable="yes">The number of active torrents that Deluge will run. Set to -1 for unlimited.</property>
|
||||||
|
<property name="adjustment">0 -1 9000 1 10 10</property>
|
||||||
|
</widget>
|
||||||
|
</child>
|
||||||
|
</widget>
|
||||||
|
<packing>
|
||||||
|
<property name="left_attach">1</property>
|
||||||
|
<property name="right_attach">2</property>
|
||||||
|
<property name="top_attach">4</property>
|
||||||
|
<property name="bottom_attach">5</property>
|
||||||
|
<property name="x_options">GTK_EXPAND</property>
|
||||||
|
<property name="y_options">GTK_EXPAND</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
</widget>
|
</widget>
|
||||||
<packing>
|
<packing>
|
||||||
<property name="position">1</property>
|
<property name="position">1</property>
|
||||||
|
|
|
@ -69,6 +69,7 @@ DHT_FILENAME = "dht.state"
|
||||||
|
|
||||||
PREF_FUNCTIONS = {
|
PREF_FUNCTIONS = {
|
||||||
"listen_on" : deluge_core.set_listen_on,
|
"listen_on" : deluge_core.set_listen_on,
|
||||||
|
"max_half_open" : deluge_core.set_max_half_open,
|
||||||
"max_connections_global" : deluge_core.set_max_connections_global,
|
"max_connections_global" : deluge_core.set_max_connections_global,
|
||||||
"max_active_torrents" : None, # no need for a function, applied constantly
|
"max_active_torrents" : None, # no need for a function, applied constantly
|
||||||
"max_upload_slots_global" : deluge_core.set_max_upload_slots_global,
|
"max_upload_slots_global" : deluge_core.set_max_upload_slots_global,
|
||||||
|
|
|
@ -132,6 +132,7 @@ class PreferencesDlg:
|
||||||
self.glade.get_widget("spin_tracker_proxy_port").set_value(self.preferences.get("tracker_proxy_port"))
|
self.glade.get_widget("spin_tracker_proxy_port").set_value(self.preferences.get("tracker_proxy_port"))
|
||||||
self.glade.get_widget("spin_dht_proxy_port").set_value(self.preferences.get("dht_proxy_port"))
|
self.glade.get_widget("spin_dht_proxy_port").set_value(self.preferences.get("dht_proxy_port"))
|
||||||
self.glade.get_widget("spin_web_proxy_port").set_value(self.preferences.get("web_proxy_port"))
|
self.glade.get_widget("spin_web_proxy_port").set_value(self.preferences.get("web_proxy_port"))
|
||||||
|
self.glade.get_widget("spin_max_half_open").set_value(float(self.preferences.get("max_half_open")))
|
||||||
self.glade.get_widget("spin_torrents").set_value(float(self.preferences.get("max_active_torrents")))
|
self.glade.get_widget("spin_torrents").set_value(float(self.preferences.get("max_active_torrents")))
|
||||||
self.glade.get_widget("chk_seedbottom").set_active(self.preferences.get("queue_seeds_to_bottom"))
|
self.glade.get_widget("chk_seedbottom").set_active(self.preferences.get("queue_seeds_to_bottom"))
|
||||||
self.glade.get_widget("chk_queue_above_completed").set_sensitive(self.preferences.get("queue_seeds_to_bottom"))
|
self.glade.get_widget("chk_queue_above_completed").set_sensitive(self.preferences.get("queue_seeds_to_bottom"))
|
||||||
|
@ -247,6 +248,7 @@ class PreferencesDlg:
|
||||||
self.preferences.set("tracker_proxy_port", self.glade.get_widget("spin_tracker_proxy_port").get_value())
|
self.preferences.set("tracker_proxy_port", self.glade.get_widget("spin_tracker_proxy_port").get_value())
|
||||||
self.preferences.set("max_connections_global", int(self.glade.get_widget("spin_max_connections_global").get_value()))
|
self.preferences.set("max_connections_global", int(self.glade.get_widget("spin_max_connections_global").get_value()))
|
||||||
self.preferences.set("max_connections_per_torrent", int(self.glade.get_widget("spin_max_connections_per_torrent").get_value()))
|
self.preferences.set("max_connections_per_torrent", int(self.glade.get_widget("spin_max_connections_per_torrent").get_value()))
|
||||||
|
self.preferences.set("max_half_open", int(self.glade.get_widget("spin_max_half_open").get_value()))
|
||||||
self.preferences.set("max_active_torrents", int(self.glade.get_widget("spin_torrents").get_value()))
|
self.preferences.set("max_active_torrents", int(self.glade.get_widget("spin_torrents").get_value()))
|
||||||
self.preferences.set("queue_seeds_to_bottom", self.glade.get_widget("chk_seedbottom").get_active())
|
self.preferences.set("queue_seeds_to_bottom", self.glade.get_widget("chk_seedbottom").get_active())
|
||||||
self.preferences.set("enable_dht", self.glade.get_widget("chk_dht").get_active())
|
self.preferences.set("enable_dht", self.glade.get_widget("chk_dht").get_active())
|
||||||
|
|
|
@ -63,6 +63,7 @@ DEFAULT_PREFS = {
|
||||||
"gui_update_interval" : 1.0,
|
"gui_update_interval" : 1.0,
|
||||||
"listen_on" : [6881,6889],
|
"listen_on" : [6881,6889],
|
||||||
"lock_tray" : False,
|
"lock_tray" : False,
|
||||||
|
"max_half_open" : 8,
|
||||||
"max_active_torrents" : 8,
|
"max_active_torrents" : 8,
|
||||||
"max_connections_global" : 200,
|
"max_connections_global" : 200,
|
||||||
"max_connections_per_torrent" : -1,
|
"max_connections_per_torrent" : -1,
|
||||||
|
|
|
@ -74,6 +74,7 @@ class WizardGTK:
|
||||||
defaults={"listen_on" : [6881,6889],
|
defaults={"listen_on" : [6881,6889],
|
||||||
"send_info": True,
|
"send_info": True,
|
||||||
"random_port": False,
|
"random_port": False,
|
||||||
|
"max_half_open" : 8,
|
||||||
"max_active_torrents" : 8,
|
"max_active_torrents" : 8,
|
||||||
"max_upload_slots_global" : 15,
|
"max_upload_slots_global" : 15,
|
||||||
"max_connections_global" : 200,
|
"max_connections_global" : 200,
|
||||||
|
@ -106,6 +107,8 @@ class WizardGTK:
|
||||||
get("max_upload_speed"))
|
get("max_upload_speed"))
|
||||||
self.wtree.get_widget('spin_torrents').set_value(self.config.\
|
self.wtree.get_widget('spin_torrents').set_value(self.config.\
|
||||||
get("max_active_torrents"))
|
get("max_active_torrents"))
|
||||||
|
self.wtree.get_widget('spin_max_half_open').set_value(self.config.\
|
||||||
|
get("max_half_open"))
|
||||||
|
|
||||||
#show wizard
|
#show wizard
|
||||||
self.window.show()
|
self.window.show()
|
||||||
|
@ -304,6 +307,8 @@ class WizardGTK:
|
||||||
'spin_max_upload').get_value()))
|
'spin_max_upload').get_value()))
|
||||||
self.config.set("max_active_torrents", int(self.wtree.get_widget(\
|
self.config.set("max_active_torrents", int(self.wtree.get_widget(\
|
||||||
'spin_torrents').get_value()))
|
'spin_torrents').get_value()))
|
||||||
|
self.config.set("max_half_open", int(self.wtree.get_widget(\
|
||||||
|
'spin_max_half_open').get_value()))
|
||||||
self.config.set("use_default_dir", self.wtree.get_widget(\
|
self.config.set("use_default_dir", self.wtree.get_widget(\
|
||||||
'radio_save_all_to').get_active())
|
'radio_save_all_to').get_active())
|
||||||
self.config.set("default_download_path", self.wtree.get_widget(\
|
self.config.set("default_download_path", self.wtree.get_widget(\
|
||||||
|
|
Loading…
Reference in New Issue