Problems with paging in JTable

0

I am creating an application where I fill in the data from a table through the database, but there are many then wanted to organize better.

However, the results displayed in the table are not constants. The implemented methods behave differently even with the same button being pressed.

When I use alunos_1.json , which has a page with less than the maximum number of records allowed, the table loads and everything works the way I said it, however when I load a json alunos.json that has a maximum divisible number of records does not work.

Table Class

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

public class Teste extends JFrame{
   //MAIN METHOD
  public static void main(String[] args)
  {

       EventQueue.invokeLater(new Runnable()
       {
           public void run()
           {
               //INITIALIZE JFRAME FORM
               teste.Teste form=new teste.Teste();
               form.setVisible(true);;
           }
       });

  }

  TesteTableModel tableModel = new TesteTableModel();
  List<TesteModel> resultado = new ArrayList<TesteModel>();
  List<TesteModel> lista = new ArrayList<TesteModel>();
  int indiceLista, maxLista, resto, totalPag = 0;
  int paginaAtual = 1;

  private static final int ITENS_POR_PAG = 5;

  private java.awt.Button btnRemover, btnProxima, btnAnterior, btnPrimeira, btnUltima;
  private javax.swing.JPanel jPanel1;
  private javax.swing.JScrollPane jScrollPane;
  private javax.swing.JTable jTable;
  private java.awt.ScrollPane scrollPane;


  //CONSTRUCTOR
  public Teste()
  {
        scrollPane = new java.awt.ScrollPane();
        jScrollPane = new javax.swing.JScrollPane();
        jTable = new javax.swing.JTable();
        btnRemover = new java.awt.Button();
        btnAnterior = new java.awt.Button();
        btnProxima = new java.awt.Button();
        btnUltima = new java.awt.Button();
        btnPrimeira = new java.awt.Button();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setPreferredSize(new java.awt.Dimension(500, 400));

        jTable.setModel(tableModel);

        jScrollPane.setViewportView(jTable);

        scrollPane.add(jScrollPane);

        btnRemover.setLabel("Remover");

        btnAnterior.setLabel("<");

        btnProxima.setLabel(">");

        btnUltima.setLabel(">>");

        btnPrimeira.setLabel("<<");

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(scrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addComponent(btnRemover, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 293, Short.MAX_VALUE)
                .addComponent(btnPrimeira, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btnAnterior, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(btnProxima, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(5, 5, 5)
                .addComponent(btnUltima, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(scrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 316, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 50, Short.MAX_VALUE)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(btnRemover, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnAnterior, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnProxima, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnUltima, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(btnPrimeira, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        btnRemover.getAccessibleContext().setAccessibleName("btnRemover");

        pack();

        btnRemover.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                tableModel.deletarLinhas();
            }
        });

        btnProxima.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                if(indiceLista <= lista.size()){
                    btnAnterior.setEnabled(true);
                    btnPrimeira.setEnabled(true);
                    resultado = carregaProximaPagina(lista);

                    for(TesteModel teste: resultado){
                        tableModel.addRow(teste);
                    }
                }
            }
        });

        btnAnterior.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0){
                if(indiceLista != 0){
                    btnProxima.setEnabled(true);
                    btnUltima.setEnabled(true);
                    resultado = carregaPaginaAnterior(lista);

                    for(TesteModel teste: resultado){
                        tableModel.addRow(teste);
                    }
                }
            }
        });

        btnUltima.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                resultado = carregaUltimaPagina(lista);

                for(TesteModel teste: resultado){
                    tableModel.addRow(teste);
                }
            }
        });

        btnPrimeira.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                resultado = carregaPrimeiraPagina(lista);

                for(TesteModel teste: resultado){
                    tableModel.addRow(teste);
                }
            }
        });

         //Preenche dados iniciais da tabela
        lista = tableModel.lerJSON();

        paginaAtual = (int) lista.size() / ITENS_POR_PAG;
        resto = lista.size() % ITENS_POR_PAG;

        System.out.println("\npagina:" + paginaAtual
                + "\nresto:" + resto);

        resultado = carregaProximaPagina(lista);

        for(TesteModel teste: resultado){
            tableModel.addRow(teste);
        }

        btnAnterior.setEnabled(false);
        btnPrimeira.setEnabled(false);

    }                       

    private void limparTabela() {  
        while (jTable.getModel().getRowCount() > 0) {  
           ((TesteTableModel) jTable.getModel()).removeRow(0);  
       } 
    } 

    public List<TesteModel> carregaProximaPagina(List<TesteModel> testes){
        limparTabela();
        List<TesteModel> resultado = new ArrayList<TesteModel>();
        if(resto > 0){
            if(paginaAtual > 0){
                indiceLista = maxLista;
                maxLista += ITENS_POR_PAG;
                for(int i = indiceLista; i < maxLista; i++){
                    resultado.add(testes.get(i));
                }
                System.out.println("\nindiceLista:" + indiceLista
                        + "\nmaxLista:" + maxLista
                        + "\npagina:" + paginaAtual);
            } else { 
                indiceLista = maxLista;
                maxLista += resto;
                for(int i = indiceLista; i < maxLista; i++){
                    resultado.add(testes.get(i));
                }
                btnProxima.setEnabled(false);
                btnUltima.setEnabled(false);
                System.out.println("\nindiceLista:" + indiceLista
                        + "\nmaxLista:" + maxLista
                        + "\npagina:" + paginaAtual);
            }
        }
        paginaAtual--;       
        return resultado;
    }

    public List<TesteModel> carregaPaginaAnterior(List<TesteModel> testes){
        limparTabela();
        List<TesteModel> resultado = new ArrayList<TesteModel>();
        if(paginaAtual == 0){
            maxLista = indiceLista;
            indiceLista = maxLista - ITENS_POR_PAG;

            for(int i = indiceLista; i < maxLista; i++){
                resultado.add(testes.get(i));
            }
            System.out.println("\nindiceLista:" + indiceLista
                    + "\nmaxLista:" + maxLista
                    + "\npagina:" + paginaAtual);
        } else {
            if(paginaAtual == ((int) testes.size() / ITENS_POR_PAG)){
                btnAnterior.setEnabled(false);
                btnPrimeira.setEnabled(false);
            }

            indiceLista -= ITENS_POR_PAG;
            maxLista -= ITENS_POR_PAG;
            for(int i = indiceLista; i < maxLista; i++){
                resultado.add(testes.get(i));
            }
            System.out.println("\nindiceLista:" + indiceLista
                    + "\nmaxLista:" + maxLista
                    + "\npagina:" + paginaAtual);
        }
        paginaAtual++;
        return resultado;
    }

    public List<TesteModel> carregaPrimeiraPagina(List<TesteModel> testes){
        limparTabela();
        List<TesteModel> resultado = new ArrayList<TesteModel>();

        totalPag = (int) lista.size() / ITENS_POR_PAG;

        indiceLista = 0;
        maxLista = ITENS_POR_PAG;
        for(int i = indiceLista; i < maxLista; i++){
            resultado.add(testes.get(i));
        }
        System.out.println("\nindiceLista:" + indiceLista
                + "\nmaxLista:" + maxLista
                + "\npagina:" + paginaAtual);

        return resultado;
    }

    public List<TesteModel> carregaUltimaPagina(List<TesteModel> testes){
        limparTabela();
        List<TesteModel> resultado = new ArrayList<TesteModel>();

        totalPag = (int) lista.size() / ITENS_POR_PAG;

        if(resto != 0) {
            indiceLista = ITENS_POR_PAG * totalPag;
            maxLista = indiceLista + resto;
            for(int i = indiceLista; i < maxLista; i++){
                resultado.add(testes.get(i));
            }
            paginaAtual = 0;
            System.out.println("\nindiceLista:" + indiceLista
                    + "\nmaxLista:" + maxLista
                    + "\npagina:" + paginaAtual);
        } else {
            indiceLista = ITENS_POR_PAG * totalPag;
            maxLista = indiceLista + ITENS_POR_PAG;
            for(int i = indiceLista; i < maxLista; i++){
                resultado.add(testes.get(i));
            }
            System.out.println("\nindiceLista:" + indiceLista
                    + "\nmaxLista:" + maxLista
                    + "\npagina:" + paginaAtual);
        }
        return resultado;
    }

}

TestTableModel

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import javax.swing.JOptionPane;
import javax.swing.table.AbstractTableModel;
import jdk.nashorn.internal.parser.JSONParser;
import org.json.JSONObject;

public class TesteTableModel extends AbstractTableModel {


    private List<TesteModel> dados = new ArrayList<>();
    private String[] colunas = {"Selecionar", "Nome"};


    public Class<?> getColumnClass(int columnIndex) {
        return columnIndex == 0 ? Boolean.class : super.getColumnClass(columnIndex);
    }

    @Override
    public String getColumnName(int column){
        return colunas[column];
    }

    @Override
    public int getColumnCount() {
        return colunas.length;
    }

    @Override
    public int getRowCount() {
        return dados.size();
    }

    @Override
    public Object getValueAt(int linha, int coluna) {
        switch(coluna){
            case 0:
                return dados.get(linha).getSelecionado();
            case 1:
                return dados.get(linha).getNome();
        }

        return null;
    }

    public void setValueAt(Object valor, int linha, int coluna) {
        TesteModel tm = dados.get(linha);
        switch (coluna) {
        case 0:
            tm.setSelecionado(new Boolean((Boolean) valor));
            break;
        }
        fireTableDataChanged();
    }

    public void addRow(TesteModel tm) {
        this.dados.add(tm);
        this.fireTableDataChanged();    
    }

    public void removeRow(int linha){
        this.dados.remove(linha);
        this.fireTableRowsDeleted(linha, linha);
    }

    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return columnIndex == 0; 
    }

    public void deletarLinhas() {

    for (int i = getRowCount() - 1; i >= 0; i--) {
        if (dados.get(i).getSelecionado()) {
        removeRow(i);
            }
    }
    }

    public String lerArquivo() {
        String linha = "";

        try {
          FileReader arq = new FileReader("C:\Users\maily\Documents\NetBeansProjects\Teste\src\teste\alunos_1.json");
          BufferedReader lerArq = new BufferedReader(arq);

          linha = lerArq.readLine(); 
          /*while (linha != null) {
            System.out.printf(linha);
            linha = lerArq.readLine(); // lê da segunda até a última linha
          }*/
          arq.close();

        } catch (IOException e) {
            System.err.printf("Erro na abertura do arquivo: %s.\n",
              e.getMessage());
        }
        //System.out.println(linha);
        return linha;
    }

    public List<TesteModel> lerJSON() {
        String str = lerArquivo();
        Type type = new TypeToken<List<TesteModel>>(){}.getType();

        Gson gson = new GsonBuilder().create();
        List<TesteModel> lista = gson.fromJson(str, type);

        for(TesteModel teste: lista){
            System.out.println(teste.getSelecionado());
            System.out.println(teste.getNome());
        }
        return lista;
    }

}

Class Model

public class TesteModel {
    private Boolean select;
    private String name;

    public Boolean getSelecionado() {
        return select;
    }

    public void setSelecionado(Boolean selecionado) {
        this.select = selecionado;
    }

    public String getNome() {
        return name;
    }

    public void setNome(String nome) {
        this.name = nome;
    }

}

students.json

[{"select": "false", "name": "Ana 01"}, {"select": "false", "name": "João"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"}, {"select": "false", "name": "José 02"}, {"select": "false", "name": "Maria"}, {"select": "false", "name": "Renato"}, {"select": "false", "name": "Paula"}, {"select": "false", "name": "Juliano"}, {"select": "false", "name": "Júlio 03"}, {"select": "false", "name": "Amanda"}, {"select": "false", "name": "André"}, {"select": "false", "name": "Tales"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "João 04"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "João 05"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "João 06"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Pedro"}]

students_1.json

[{"select": "false", "name": "Ana 01"}, {"select": "false", "name": "João"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"}, {"select": "false", "name": "José 02"}, {"select": "false", "name": "Maria"}, {"select": "false", "name": "Renato"}, {"select": "false", "name": "Paula"}, {"select": "false", "name": "Juliano"}, {"select": "false", "name": "Júlio 03"}, {"select": "false", "name": "Amanda"}, {"select": "false", "name": "André"}, {"select": "false", "name": "Tales"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "João 04"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "João 05"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "João 06"}, {"select": "false", "name": "Laura"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Pedro"}, {"select": "false", "name": "Bruno"}, {"select": "false", "name": "Carina"},{"select": "false", "name": "Joselino RESTO"}]

The Gson lib can be downloaded here.

    
asked by anonymous 28.10.2018 / 21:59

1 answer

1

This can be done by applying the approach of this SOEn response , where we only limit the amount of data to be displayed in the screen by removing the scroll bar and using the buttons to move it manually.

The secret here is to use the height of the rows of the table times the amount you want to display to move the scroll bar, so in the listener inside the buttons btnPrevious and btnNext I calculate the height of the next set of rows . In the adapted example of your code, the bar will move vertically exactly the height of 5 rows of the table at a time, until its end or its beginning.

For the buttons that move to the beginning and end of the table ( btnFirst and btnLast ), I just set the bar's minimum and maximum values, moving it to the beginning or end of the table.

The screen with the table and the buttons looks like this:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;

public class JTablePaginada extends JFrame {

    private JPanel contentPane, buttonPane;
    private JButton btnFirst, btnPrevious, btnNext, btnLast, btnClean;
    private JTable table;
    private TesteTableModel model;

    private static final int ITENS_POR_PAG = 5;


    public static void main(String[] args) {
        EventQueue.invokeLater(()-> new JTablePaginada().setVisible(true));
    }


    public JTablePaginada() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(500, 400));
        contentPane = new JPanel();

        model = new TesteTableModel(JSONUtils.JSONtoList());

        table = new JTable(model);

        JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_NEVER,
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        //o width é um pequeno "workaround pra tabela ficar certinha na tela
        //a altura é definida pela quantidade de itens que quer exibir 
        //mais a altura do cabeçalho
        scrollPane.setPreferredSize(new Dimension(getPreferredSize().width - 20, table.getRowHeight() * ITENS_POR_PAG + table.getTableHeader().getPreferredSize().height));

        contentPane.add(scrollPane);
        this.add(contentPane, BorderLayout.CENTER);

        btnClean = new JButton("Remover tudo");
        btnFirst = new JButton("<<");
        btnFirst.addActionListener(e -> {
            JScrollBar bar = scrollPane.getVerticalScrollBar();
            bar.setValue(0);
        });

        btnPrevious = new JButton("<");
        btnPrevious.addActionListener(e -> {
            int height = table.getRowHeight() * (ITENS_POR_PAG - 1);
            JScrollBar bar = scrollPane.getVerticalScrollBar();
            bar.setValue(bar.getValue() - height);
        });

        btnNext = new JButton(">");
        btnNext.addActionListener(e -> {
            int height = table.getRowHeight() * (ITENS_POR_PAG - 1);
            JScrollBar bar = scrollPane.getVerticalScrollBar();
            bar.setValue(bar.getValue() + height);
        });

        btnLast = new JButton(">>");
        btnLast.addActionListener(e -> {
            JScrollBar bar = scrollPane.getVerticalScrollBar();
            bar.setValue(bar.getMaximum());
        });

        buttonPane = new JPanel();
        buttonPane.add(btnFirst);
        buttonPane.add(btnPrevious);
        buttonPane.add(btnNext);
        buttonPane.add(btnLast);

        this.add(buttonPane, BorderLayout.SOUTH);       
        pack();
    }
}

Running with the file alunos.json :

Rememberingthatnoamountofdatamattershere,aswearejustmovingthescrollbaracrosstherowsofthetablewithoutdisplayingitonthescreen.

Furthercomments

I'vemadeothercodechangesthatareimportanttocommenton,althoughtheymayhaveeludedsomeoftheproblemthathasalreadybeenresolved,butmayaffectnewimplementations,includingtheactualpaging:

  • classTableModelshouldnotreadthejsonfileorevenconvertit,thishurtsthe principle of class cohesion , in addition to the concept of single responsibility, where the class should do just what it was designed for. So I moved the two methods of reading the file and converting json to List into a new JSONUtils class:
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Type;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;

public class JSONUtils {

    private static String strjson = null;


    //isso é pra evitar instanciacao da classe
    //ja que os métodos sao estaticos
    private JSONUtils() {

        if (strjson == null)
            strjson = lerArquivo();
    }

    public static List<TesteModel> JSONtoList() {
        String str = lerArquivo();
        Type type = new TypeToken<List<TesteModel>>() {
        }.getType();

        Gson gson = new GsonBuilder().create();
        List<TesteModel> lista = gson.fromJson(str, type);

        for (TesteModel teste : lista) {
            System.out.println(teste.getSelecionado());
            System.out.println(teste.getNome());
        }
        return lista;
    }

    private static String lerArquivo() {
        String linha = "";

        try {
            FileReader arq = new FileReader("C:\temp\alunos.json");
            BufferedReader lerArq = new BufferedReader(arq);

            linha = lerArq.readLine();
            /*
             * while (linha != null) { System.out.printf(linha); linha = lerArq.readLine();
             * // lê da segunda até a última linha }
             */
            arq.close();

        } catch (IOException e) {
            System.err.printf("Erro na abertura do arquivo: %s.\n", e.getMessage());
        }
        // System.out.println(linha);
        return linha;
    }
}
  • In the TesteTableModel class, the deletarLinhas() method can be simplified. You do not need to scan item by item from a list to delete everything, the List class already natively has a method to clear the list, which is clear . This is why it is important to ALWAYS read the documentation of the classes, this is how you learn how to work and avoid creating unnecessary code for tasks that java already has. Just use the method quoted and notify the table:
public void deletarLinhas() {
    this.dados.clear();
    this.fireTableDataChanged();
}
  • Still in the TesteTableModel class, I suggest creating a builder as below, considering what you said in chat regarding the reuse of the table for other json files. This way you can create a button or function that imports a new file and populate it in the table, just create a new TableModel :
//flexibilizando o tablemodel
public TesteTableModel(List<TesteModel> model) {
    this.dados = model;
}

Java-swing: Always try to understand the basics of how a component works , java-swing is not such an easy to handle API, although not as complex as it is it is essential that you try to understand how the component works, what its features, if not every code you find there and try to adapt it in yours, will only create a cascade of problems.

    
05.11.2018 / 01:25