TOP/BOTTOM BUTTONS
This commit is contained in:
tonikelope 2019-12-15 20:34:12 +01:00
parent 029caf23cd
commit faf74fa529
11 changed files with 297 additions and 19 deletions

View File

@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.tonikelope</groupId>
<artifactId>MegaBasterd</artifactId>
<version>6.83</version>
<version>6.84</version>
<packaging>jar</packaging>
<dependencies>
<dependency>

View File

@ -1665,6 +1665,16 @@ public class Download implements Transference, Runnable, SecureSingleThreadNotif
_main_panel.getDownload_manager().downWaitQueue(this);
}
@Override
public void bottomWaitQueue() {
_main_panel.getDownload_manager().bottomWaitQueue(this);
}
@Override
public void topWaitQueue() {
_main_panel.getDownload_manager().topWaitQueue(this);
}
@Override
public boolean isRestart() {
return _restart;

View File

@ -37,9 +37,13 @@
<Component id="slots_label" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="queue_up_button" min="-2" pref="43" max="-2" attributes="0"/>
<Component id="queue_top_button" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="queue_up_button" min="-2" pref="42" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="queue_down_button" min="-2" pref="42" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="queue_bottom_button" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
@ -82,10 +86,12 @@
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="queue_down_button" pref="39" max="32767" attributes="0"/>
<Component id="queue_down_button" max="32767" attributes="0"/>
<Component id="queue_up_button" max="32767" attributes="0"/>
<Component id="queue_top_button" alignment="0" max="32767" attributes="0"/>
<Component id="queue_bottom_button" alignment="0" max="32767" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="slots_spinner" alignment="3" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="slots_label" alignment="3" min="-2" max="-2" attributes="0"/>
@ -346,5 +352,33 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="queue_down_buttonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="queue_top_button">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Dialog" size="14" style="1"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/images/arriba_1.png"/>
</Property>
<Property name="text" type="java.lang.String" value="TOP"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="queue_top_buttonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="queue_bottom_button">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Dialog" size="14" style="1"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/images/abajo_1.png"/>
</Property>
<Property name="text" type="java.lang.String" value="BOTTOM"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="queue_bottom_buttonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -162,6 +162,8 @@ public class DownloadView extends javax.swing.JPanel implements TransferenceView
slot_status_label = new javax.swing.JLabel();
queue_up_button = new javax.swing.JButton();
queue_down_button = new javax.swing.JButton();
queue_top_button = new javax.swing.JButton();
queue_bottom_button = new javax.swing.JButton();
setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 204, 255), 3, true));
@ -288,6 +290,24 @@ public class DownloadView extends javax.swing.JPanel implements TransferenceView
}
});
queue_top_button.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
queue_top_button.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/arriba_1.png"))); // NOI18N
queue_top_button.setText("TOP");
queue_top_button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
queue_top_buttonActionPerformed(evt);
}
});
queue_bottom_button.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
queue_bottom_button.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/abajo_1.png"))); // NOI18N
queue_bottom_button.setText("BOTTOM");
queue_bottom_button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
queue_bottom_buttonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -303,9 +323,13 @@ public class DownloadView extends javax.swing.JPanel implements TransferenceView
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(slots_label))
.addGroup(layout.createSequentialGroup()
.addComponent(queue_up_button, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(queue_top_button)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(queue_up_button, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(queue_down_button, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(queue_bottom_button)
.addGap(0, 0, Short.MAX_VALUE)))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(slots_spinner, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE))
@ -338,9 +362,11 @@ public class DownloadView extends javax.swing.JPanel implements TransferenceView
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(queue_down_button, javax.swing.GroupLayout.DEFAULT_SIZE, 39, Short.MAX_VALUE)
.addComponent(queue_up_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addGap(0, 0, 0)
.addComponent(queue_down_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(queue_up_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(queue_top_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(queue_bottom_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(slots_spinner, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(slots_label)
@ -448,6 +474,32 @@ public class DownloadView extends javax.swing.JPanel implements TransferenceView
});
}//GEN-LAST:event_queue_down_buttonActionPerformed
private void queue_top_buttonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_queue_top_buttonActionPerformed
// TODO add your handling code here:
queue_top_button.setEnabled(false);
THREAD_POOL.execute(() -> {
_download.topWaitQueue();
swingInvoke(() -> {
queue_top_button.setEnabled(true);
});
});
}//GEN-LAST:event_queue_top_buttonActionPerformed
private void queue_bottom_buttonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_queue_bottom_buttonActionPerformed
// TODO add your handling code here:
queue_bottom_button.setEnabled(false);
THREAD_POOL.execute(() -> {
_download.bottomWaitQueue();
swingInvoke(() -> {
queue_bottom_button.setEnabled(true);
});
});
}//GEN-LAST:event_queue_bottom_buttonActionPerformed
@Override
public void pause() {
@ -596,7 +648,9 @@ public class DownloadView extends javax.swing.JPanel implements TransferenceView
private javax.swing.JButton open_folder_button;
private javax.swing.JButton pause_button;
private javax.swing.JProgressBar progress_pbar;
private javax.swing.JButton queue_bottom_button;
private javax.swing.JButton queue_down_button;
private javax.swing.JButton queue_top_button;
private javax.swing.JButton queue_up_button;
private javax.swing.JButton restart_button;
private javax.swing.JLabel slot_status_label;

View File

@ -53,7 +53,7 @@ import javax.swing.UIManager;
*/
public final class MainPanel {
public static final String VERSION = "6.83";
public static final String VERSION = "6.84";
public static final int THROTTLE_SLICE_SIZE = 16 * 1024;
public static final int DEFAULT_BYTE_BUFFER_SIZE = 16 * 1024;
public static final int STREAMER_PORT = 1337;

View File

@ -46,6 +46,10 @@ public interface Transference {
void downWaitQueue();
void bottomWaitQueue();
void topWaitQueue();
void checkSlotsAndWorkers();
ConcurrentLinkedQueue<Long> getPartialProgress();

View File

@ -285,6 +285,83 @@ abstract public class TransferenceManager implements Runnable, SecureSingleThrea
secureNotify();
}
public void topWaitQueue(Transference t) {
synchronized (getWait_queue_lock()) {
ArrayList<Transference> wait_array = new ArrayList();
wait_array.add(t);
for (Transference t1 : getTransference_waitstart_queue()) {
if (t1 != t) {
wait_array.add(t1);
}
}
getTransference_waitstart_queue().clear();
getTransference_waitstart_queue().addAll(wait_array);
getTransference_waitstart_queue().forEach((t1) -> {
swingInvoke(() -> {
getScroll_panel().remove((Component) t1.getView());
getScroll_panel().add((Component) t1.getView());
});
});
getTransference_finished_queue().forEach((t1) -> {
swingInvoke(() -> {
getScroll_panel().remove((Component) t1.getView());
getScroll_panel().add((Component) t1.getView());
});
});
_frozen = false;
}
secureNotify();
}
public void bottomWaitQueue(Transference t) {
synchronized (getWait_queue_lock()) {
ArrayList<Transference> wait_array = new ArrayList();
for (Transference t1 : getTransference_waitstart_queue()) {
if (t1 != t) {
wait_array.add(t1);
}
}
wait_array.add(t);
getTransference_waitstart_queue().clear();
getTransference_waitstart_queue().addAll(wait_array);
getTransference_waitstart_queue().forEach((t1) -> {
swingInvoke(() -> {
getScroll_panel().remove((Component) t1.getView());
getScroll_panel().add((Component) t1.getView());
});
});
getTransference_finished_queue().forEach((t1) -> {
swingInvoke(() -> {
getScroll_panel().remove((Component) t1.getView());
getScroll_panel().add((Component) t1.getView());
});
});
_frozen = false;
}
secureNotify();
}
public void upWaitQueue(Transference t) {
synchronized (getWait_queue_lock()) {

View File

@ -1186,6 +1186,16 @@ public class Upload implements Transference, Runnable, SecureSingleThreadNotifia
}
}
@Override
public void bottomWaitQueue() {
_main_panel.getUpload_manager().bottomWaitQueue(this);
}
@Override
public void topWaitQueue() {
_main_panel.getUpload_manager().topWaitQueue(this);
}
@Override
public int getSlotsCount() {
return getChunkworkers().size();

View File

@ -56,18 +56,22 @@
<Group type="102" alignment="1" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="queue_up_button" min="-2" pref="43" max="-2" attributes="0"/>
<Component id="queue_top_button" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="queue_up_button" min="-2" pref="42" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="queue_down_button" min="-2" pref="42" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="231" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="queue_bottom_button" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="status_label" pref="446" max="32767" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="cbc_label" min="-2" max="-2" attributes="0"/>
<EmptySpace type="separate" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="separate" max="-2" attributes="0"/>
<Component id="slots_label" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="slots_spinner" min="-2" pref="70" max="-2" attributes="0"/>
@ -82,9 +86,12 @@
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="queue_down_button" alignment="0" max="32767" attributes="0"/>
<Component id="queue_up_button" alignment="0" min="-2" pref="39" max="-2" attributes="0"/>
<Component id="queue_up_button" max="32767" attributes="0"/>
<Component id="queue_top_button" max="32767" attributes="0"/>
<Component id="queue_down_button" max="32767" attributes="0"/>
<Component id="queue_bottom_button" max="32767" attributes="0"/>
</Group>
<EmptySpace min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="slots_spinner" alignment="3" min="-2" pref="32" max="-2" attributes="0"/>
<Component id="slots_label" alignment="3" min="-2" max="-2" attributes="0"/>
@ -340,5 +347,33 @@
<Property name="doubleBuffered" type="boolean" value="true"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="queue_top_button">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Dialog" size="14" style="1"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/images/arriba_1.png"/>
</Property>
<Property name="text" type="java.lang.String" value="TOP"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="queue_top_buttonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JButton" name="queue_bottom_button">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Dialog" size="14" style="1"/>
</Property>
<Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor">
<Image iconType="3" name="/images/abajo_1.png"/>
</Property>
<Property name="text" type="java.lang.String" value="BOTTOM"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="queue_bottom_buttonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Form>

View File

@ -144,6 +144,8 @@ public class UploadView extends javax.swing.JPanel implements TransferenceView {
queue_up_button = new javax.swing.JButton();
queue_down_button = new javax.swing.JButton();
cbc_label = new javax.swing.JLabel();
queue_top_button = new javax.swing.JButton();
queue_bottom_button = new javax.swing.JButton();
setBorder(new javax.swing.border.LineBorder(new java.awt.Color(153, 204, 255), 3, true));
@ -269,6 +271,24 @@ public class UploadView extends javax.swing.JPanel implements TransferenceView {
cbc_label.setText("CBC-MAC 000%");
cbc_label.setDoubleBuffered(true);
queue_top_button.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
queue_top_button.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/arriba_1.png"))); // NOI18N
queue_top_button.setText("TOP");
queue_top_button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
queue_top_buttonActionPerformed(evt);
}
});
queue_bottom_button.setFont(new java.awt.Font("Dialog", 1, 14)); // NOI18N
queue_bottom_button.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/abajo_1.png"))); // NOI18N
queue_bottom_button.setText("BOTTOM");
queue_bottom_button.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
queue_bottom_buttonActionPerformed(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
@ -300,15 +320,19 @@ public class UploadView extends javax.swing.JPanel implements TransferenceView {
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(queue_up_button, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(queue_top_button)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(queue_up_button, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(queue_down_button, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(231, 231, 231))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(queue_bottom_button)
.addGap(0, 0, Short.MAX_VALUE))
.addGroup(layout.createSequentialGroup()
.addComponent(status_label, javax.swing.GroupLayout.DEFAULT_SIZE, 446, Short.MAX_VALUE)
.addGap(18, 18, 18)
.addComponent(cbc_label)
.addGap(18, 18, 18)))
.addComponent(cbc_label)))
.addGap(18, 18, 18)
.addComponent(slots_label)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(slots_spinner, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)))
@ -319,8 +343,11 @@ public class UploadView extends javax.swing.JPanel implements TransferenceView {
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(queue_up_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(queue_top_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(queue_down_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(queue_up_button, javax.swing.GroupLayout.PREFERRED_SIZE, 39, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(queue_bottom_button, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(slots_spinner, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(slots_label)
@ -448,6 +475,31 @@ public class UploadView extends javax.swing.JPanel implements TransferenceView {
});
}//GEN-LAST:event_queue_down_buttonActionPerformed
private void queue_top_buttonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_queue_top_buttonActionPerformed
// TODO add your handling code here:
queue_top_button.setEnabled(false);
THREAD_POOL.execute(() -> {
_upload.topWaitQueue();
swingInvoke(() -> {
queue_top_button.setEnabled(true);
});
});
}//GEN-LAST:event_queue_top_buttonActionPerformed
private void queue_bottom_buttonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_queue_bottom_buttonActionPerformed
// TODO add your handling code here:
queue_bottom_button.setEnabled(false);
THREAD_POOL.execute(() -> {
_upload.bottomWaitQueue();
swingInvoke(() -> {
queue_bottom_button.setEnabled(true);
});
});
}//GEN-LAST:event_queue_bottom_buttonActionPerformed
public void updateCBC(String status) {
swingInvoke(() -> {
@ -595,7 +647,9 @@ public class UploadView extends javax.swing.JPanel implements TransferenceView {
private javax.swing.JButton folder_link_button;
private javax.swing.JButton pause_button;
private javax.swing.JProgressBar progress_pbar;
private javax.swing.JButton queue_bottom_button;
private javax.swing.JButton queue_down_button;
private javax.swing.JButton queue_top_button;
private javax.swing.JButton queue_up_button;
private javax.swing.JButton restart_button;
private javax.swing.JLabel slot_status_label;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 189 KiB