James Moger
2011-04-16 f602a2f552e1389ee465307723b492b1af378fd5
Working history feature.  Tweak to paging.
4 files added
10 files modified
300 ■■■■■ changed files
.classpath 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/utils/JGitUtils.java 11 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/GitBlitWebApp.java 2 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/GitBlitWebApp.properties 2 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/WicketUtils.java 7 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/CommitDiffPage.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/CommitPage.java 2 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/HistoryPage.html 28 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/HistoryPage.java 38 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/LogPage.java 13 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/TreePage.java 16 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/panels/HistoryPanel.html 35 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/panels/HistoryPanel.java 130 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/panels/LogPanel.java 10 ●●●●● patch | view | raw | blame | history
.classpath
@@ -3,8 +3,6 @@
    <classpathentry kind="src" path="src"/>
    <classpathentry kind="src" path="contrib"/>
    <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
    <classpathentry kind="lib" path="lib/jgit-0.11.3.jar" sourcepath="/org.eclipse.jgit"/>
    <classpathentry kind="lib" path="lib/jgit-http-0.11.3.jar" sourcepath="/org.eclipse.jgit.http.server"/>
    <classpathentry kind="lib" path="ext/log4j-1.2.16.jar"/>
    <classpathentry kind="lib" path="ext/servlet-api-2.5.jar"/>
    <classpathentry kind="lib" path="ext/slf4j-api-1.6.1.jar"/>
@@ -15,5 +13,7 @@
    <classpathentry kind="lib" path="ext/wicket-1.4.17.jar"/>
    <classpathentry kind="lib" path="ext/wicket-auth-roles-1.4.17.jar"/>
    <classpathentry kind="lib" path="ext/wicket-extensions-1.4.17.jar"/>
    <classpathentry kind="lib" path="lib/jgit-0.11.3.jar"/>
    <classpathentry kind="lib" path="lib/jgit-http-0.11.3.jar"/>
    <classpathentry kind="output" path="bin"/>
</classpath>
src/com/gitblit/utils/JGitUtils.java
@@ -35,6 +35,7 @@
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
import org.eclipse.jgit.treewalk.filter.PathFilter;
import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
@@ -436,6 +437,10 @@
    }
    public static List<RevCommit> getRevLog(Repository r, String objectId, int offset, int maxCount) {
        return getRevLog(r, objectId, null, offset, maxCount);
    }
    public static List<RevCommit> getRevLog(Repository r, String objectId, String path, int offset, int maxCount) {
        List<RevCommit> list = new ArrayList<RevCommit>();
        try {
            if (objectId == null || objectId.trim().length() == 0) {
@@ -444,6 +449,12 @@
            RevWalk walk = new RevWalk(r);
            ObjectId object = r.resolve(objectId);
            walk.markStart(walk.parseCommit(object));
            if (!StringUtils.isEmpty(path)) {
                TreeFilter filter = AndTreeFilter.create(PathFilterGroup
                        .createFromStrings(Collections.singleton(path)),
                        TreeFilter.ANY_DIFF);
                walk.setTreeFilter(filter);
            }
            Iterable<RevCommit> revlog = walk;
            if (offset > 0) {
                int count = 0;
src/com/gitblit/wicket/GitBlitWebApp.java
@@ -17,6 +17,7 @@
import com.gitblit.wicket.pages.BranchesPage;
import com.gitblit.wicket.pages.CommitDiffPage;
import com.gitblit.wicket.pages.CommitPage;
import com.gitblit.wicket.pages.HistoryPage;
import com.gitblit.wicket.pages.LogPage;
import com.gitblit.wicket.pages.PatchPage;
import com.gitblit.wicket.pages.RawPage;
@@ -60,6 +61,7 @@
        mount(new MixedParamUrlCodingStrategy("/blobdiff", BlobDiffPage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/commitdiff", CommitDiffPage.class, new String[] { "r", "h" }));
        mount(new MixedParamUrlCodingStrategy("/patch", PatchPage.class, new String[] { "r", "h", "f" }));
        mount(new MixedParamUrlCodingStrategy("/history", HistoryPage.class, new String[] { "r", "h", "f" }));
        // setup ticgit urls
        mount(new MixedParamUrlCodingStrategy("/ticgit", TicGitPage.class, new String[] { "r" }));
src/com/gitblit/wicket/GitBlitWebApp.properties
@@ -46,3 +46,5 @@
gb.username = Username
gb.password = Password
gb.tagger = tagger
gb.moreHistory = more history...
gb.difftocurrent = diff to current
src/com/gitblit/wicket/WicketUtils.java
@@ -80,6 +80,13 @@
        }
        return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",page=" + pageNumber);
    }
    public static PageParameters newHistoryPageParameter(String repositoryName, String objectId, String path, int pageNumber) {
        if (pageNumber <= 1) {
            return newObjectParameter(repositoryName, objectId);
        }
        return new PageParameters("r=" + repositoryName + ",h=" + objectId + ",f=" + path + ",page=" + pageNumber);
    }
    public static String getRepositoryName(PageParameters params) {
        return params.getString("r", "");
src/com/gitblit/wicket/pages/CommitDiffPage.java
@@ -63,7 +63,7 @@
                item.add(new BookmarkablePageLink<Void>("patch", PatchPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("blame", BlobPage.class).setEnabled(false));
                item.add(new BookmarkablePageLink<Void>("history", BlobPage.class).setEnabled(false));
                item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, newPathParameter(entry.path)));
                WicketUtils.setAlternatingBackground(item, counter);
                counter++;
src/com/gitblit/wicket/pages/CommitPage.java
@@ -92,7 +92,7 @@
                item.add(new BookmarkablePageLink<Void>("diff", BlobDiffPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("view", BlobPage.class, newPathParameter(entry.path)));
                item.add(new BookmarkablePageLink<Void>("blame", BlobPage.class).setEnabled(false));
                item.add(new BookmarkablePageLink<Void>("history", BlobPage.class).setEnabled(false));
                item.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, newPathParameter(entry.path)));
                WicketUtils.setAlternatingBackground(item, counter);
                counter++;
src/com/gitblit/wicket/pages/HistoryPage.html
New file
@@ -0,0 +1,28 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
      xml:lang="en"
      lang="en">
<body>
<wicket:extend>
    <!-- page nav links -->
    <div wicket:id="pageLinks">[page links]</div>
    <!-- pager links -->
    <div style="padding-top:5px;padding-bottom:5px;">
        <a wicket:id="firstPageTop"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageTop"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageTop"><wicket:message key="gb.pageNext"></wicket:message></a>
    </div>
    <!-- history -->
    <div style="margin-top:5px;" wicket:id="historyPanel">[history panel]</div>
    <!-- pager links -->
    <div style="padding-bottom:5px;">
        <a wicket:id="firstPageBottom"><wicket:message key="gb.pageFirst"></wicket:message></a> | <a wicket:id="prevPageBottom"><wicket:message key="gb.pagePrevious"></wicket:message></a> | <a wicket:id="nextPageBottom"><wicket:message key="gb.pageNext"></wicket:message></a>
    </div>
</wicket:extend>
</body>
</html>
src/com/gitblit/wicket/pages/HistoryPage.java
New file
@@ -0,0 +1,38 @@
package com.gitblit.wicket.pages;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import com.gitblit.wicket.RepositoryPage;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.panels.HistoryPanel;
public class HistoryPage extends RepositoryPage {
    public HistoryPage(PageParameters params) {
        super(params);
        String path = WicketUtils.getPath(params);
        int pageNumber = WicketUtils.getPage(params);
        int prevPage = Math.max(0, pageNumber - 1);
        int nextPage = pageNumber + 1;
        HistoryPanel history = new HistoryPanel("historyPanel", repositoryName, objectId, path, getRepository(), -1, pageNumber - 1);
        boolean hasMore = history.hasMore();
        add(history);
        add(new BookmarkablePageLink<Void>("firstPageTop", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, objectId, path)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("prevPageTop", HistoryPage.class, WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, prevPage)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("nextPageTop", HistoryPage.class, WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, nextPage)).setEnabled(hasMore));
        add(new BookmarkablePageLink<Void>("firstPageBottom", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, objectId, path)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("prevPageBottom", HistoryPage.class, WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, prevPage)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("nextPageBottom", HistoryPage.class, WicketUtils.newHistoryPageParameter(repositoryName, objectId, path, nextPage)).setEnabled(hasMore));
    }
    @Override
    protected String getPageName() {
        return getString("gb.history");
    }
}
src/com/gitblit/wicket/pages/LogPage.java
@@ -15,16 +15,17 @@
        int pageNumber = WicketUtils.getPage(params);
        int prevPage = Math.max(0, pageNumber - 1);
        int nextPage = pageNumber + 1;
        LogPanel logPanel = new LogPanel("logPanel", repositoryName, objectId, getRepository(), -1, pageNumber - 1);
        boolean hasMore = logPanel.hasMore();
        add(logPanel);
        add(new BookmarkablePageLink<Void>("firstPageTop", LogPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        add(new BookmarkablePageLink<Void>("firstPageTop", LogPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("prevPageTop", LogPage.class, WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("nextPageTop", LogPage.class, WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage)));
        add(new BookmarkablePageLink<Void>("nextPageTop", LogPage.class, WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage)).setEnabled(hasMore));
        add(new LogPanel("logPanel", repositoryName, objectId, getRepository(), -1, pageNumber - 1));
        add(new BookmarkablePageLink<Void>("firstPageBottom", LogPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)));
        add(new BookmarkablePageLink<Void>("firstPageBottom", LogPage.class, WicketUtils.newObjectParameter(repositoryName, objectId)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("prevPageBottom", LogPage.class, WicketUtils.newLogPageParameter(repositoryName, objectId, prevPage)).setEnabled(pageNumber > 1));
        add(new BookmarkablePageLink<Void>("nextPageBottom", LogPage.class, WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage)));
        add(new BookmarkablePageLink<Void>("nextPageBottom", LogPage.class, WicketUtils.newLogPageParameter(repositoryName, objectId, nextPage)).setEnabled(hasMore));
    }
    @Override
src/com/gitblit/wicket/pages/TreePage.java
@@ -26,22 +26,22 @@
    public TreePage(PageParameters params) {
        super(params);
        final String basePath = WicketUtils.getPath(params);
        final String path = WicketUtils.getPath(params);
        Repository r = getRepository();
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        List<PathModel> paths = JGitUtils.getFilesInPath(r, basePath, commit);
        List<PathModel> paths = JGitUtils.getFilesInPath(r, path, commit);
        // tree page links
        add(new Label("historyLink", getString("gb.history")));
        add(new BookmarkablePageLink<Void>("headLink", TreePage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, basePath)));
        add(new BookmarkablePageLink<Void>("headLink", TreePage.class, WicketUtils.newPathParameter(repositoryName, Constants.HEAD, path)));
        add(new LinkPanel("shortlog", "title", commit.getShortMessage(), CommitPage.class, newCommitParameter()));
        // breadcrumbs
        add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, basePath, objectId));
        if (basePath != null && basePath.trim().length() > 0) {
            paths.add(0, PathModel.getParentPath(basePath, objectId));
        add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, path, objectId));
        if (path != null && path.trim().length() > 0) {
            paths.add(0, PathModel.getParentPath(path, objectId));
        }
        final ByteFormat byteFormat = new ByteFormat();
@@ -69,7 +69,7 @@
                        // links
                        Fragment links = new Fragment("pathLinks", "treeLinks", this);
                        links.add(new BookmarkablePageLink<Void>("tree", TreePage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        links.add(new BookmarkablePageLink<Void>("history", TreePage.class).setEnabled(false));
                        links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        item.add(links);
                    } else {
                        // blob link
@@ -81,7 +81,7 @@
                        links.add(new BookmarkablePageLink<Void>("view", BlobPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        links.add(new BookmarkablePageLink<Void>("raw", RawPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        links.add(new BookmarkablePageLink<Void>("blame", BlobPage.class).setEnabled(false));
                        links.add(new BookmarkablePageLink<Void>("history", BlobPage.class).setEnabled(false));
                        links.add(new BookmarkablePageLink<Void>("history", HistoryPage.class, WicketUtils.newPathParameter(repositoryName, entry.commitId, entry.path)));
                        item.add(links);
                    }
                }
src/com/gitblit/wicket/panels/HistoryPanel.html
New file
@@ -0,0 +1,35 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.3-strict.dtd"
      xml:lang="en"
      lang="en">
<body>
<wicket:panel>
    <!-- header -->
    <div class="header" wicket:id="header">[history header]</div>
    <!-- breadcrumbs -->
    <div wicket:id="breadcrumbs">[breadcrumbs]</div>
    <table style="width:100%" class="pretty">
        <tbody>
               <tr wicket:id="commit">
                 <td class="date"><span wicket:id="commitDate">[commit date]</span></td>
                 <td class="author"><span wicket:id="commitAuthor">[commit author]</span></td>
                 <td><div wicket:id="commitShortMessage">[commit short message]</div></td>
                 <td class="rightAlign"><div wicket:id="commitRefs">[commit refs]</div></td>
                 <td class="rightAlign">
                     <span class="link">
                        <a wicket:id="view"><wicket:message key="gb.view"></wicket:message></a> | <a wicket:id="commitdiff"><wicket:message key="gb.commitdiff"></wicket:message></a> | <a wicket:id="difftocurrent"><wicket:message key="gb.difftocurrent"></wicket:message></a>
                    </span>
                </td>
               </tr>
        </tbody>
    </table>
    <div wicket:id="moreHistory">[more...]</div>
</wicket:panel>
</body>
</html>
src/com/gitblit/wicket/panels/HistoryPanel.java
New file
@@ -0,0 +1,130 @@
package com.gitblit.wicket.panels;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import org.apache.wicket.model.StringResourceModel;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.utils.JGitUtils;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.LinkPanel;
import com.gitblit.wicket.WicketUtils;
import com.gitblit.wicket.pages.BlobDiffPage;
import com.gitblit.wicket.pages.CommitDiffPage;
import com.gitblit.wicket.pages.CommitPage;
import com.gitblit.wicket.pages.HistoryPage;
import com.gitblit.wicket.pages.LogPage;
public class HistoryPanel extends BasePanel {
    private static final long serialVersionUID = 1L;
    private boolean hasMore = false;
    public HistoryPanel(String wicketId, final String repositoryName, String objectId, final String path, Repository r, int limit, int pageOffset) {
        super(wicketId);
        boolean pageResults = limit <= 0;
        int itemsPerPage = GitBlit.self().settings().getInteger(Keys.web.logPageCommitCount, 50);
        if (itemsPerPage <= 1) {
            itemsPerPage = 50;
        }
        RevCommit commit = JGitUtils.getCommit(r, objectId);
        final Map<ObjectId, List<String>> allRefs = JGitUtils.getAllRefs(r);
        List<RevCommit> commits;
        if (pageResults) {
            // Paging result set
            commits = JGitUtils.getRevLog(r, objectId, path, pageOffset * itemsPerPage, itemsPerPage);
        } else {
            // Fixed size result set
            commits = JGitUtils.getRevLog(r, objectId, path, 0, limit);
        }
        // inaccurate way to determine if there are more commits.
        // works unless commits.size() represents the exact end.
        hasMore = commits.size() >= itemsPerPage;
        // header
        if (pageResults) {
            // history page
            // show commit page link
            add(new LinkPanel("header", "title", commit.getShortMessage(), CommitPage.class, WicketUtils.newObjectParameter(repositoryName, commit.getName())));
        } else {
            // summary page
            // show history page link
            add(new LinkPanel("header", "title", new StringResourceModel("gb.history", this, null), LogPage.class, WicketUtils.newRepositoryParameter(repositoryName)));
        }
        // breadcrumbs
        add(new PathBreadcrumbsPanel("breadcrumbs", repositoryName, path, objectId));
        ListDataProvider<RevCommit> dp = new ListDataProvider<RevCommit>(commits);
        DataView<RevCommit> logView = new DataView<RevCommit>("commit", dp) {
            private static final long serialVersionUID = 1L;
            int counter = 0;
            public void populateItem(final Item<RevCommit> item) {
                final RevCommit entry = item.getModelObject();
                final Date date = JGitUtils.getCommitDate(entry);
                item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone()));
                String author = entry.getAuthorIdent().getName();
                item.add(WicketUtils.createAuthorLabel("commitAuthor", author));
                String shortMessage = entry.getShortMessage();
                String trimmedMessage = StringUtils.trimShortLog(shortMessage);
                LinkPanel shortlog = new LinkPanel("commitShortMessage", "list subject", trimmedMessage, CommitPage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName()));
                if (!shortMessage.equals(trimmedMessage)) {
                    WicketUtils.setHtmlTitle(shortlog, shortMessage);
                }
                item.add(shortlog);
                item.add(new RefsPanel("commitRefs", repositoryName, entry, allRefs));
                item.add(new BookmarkablePageLink<Void>("view", CommitPage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName())));
                item.add(new BookmarkablePageLink<Void>("commitdiff", CommitDiffPage.class, WicketUtils.newObjectParameter(repositoryName, entry.getName())));
                item.add(new BookmarkablePageLink<Void>("difftocurrent", BlobDiffPage.class, WicketUtils.newPathParameter(repositoryName, entry.getName(), path)).setEnabled(counter > 0));
                WicketUtils.setAlternatingBackground(item, counter);
                counter++;
            }
        };
        add(logView);
        // determine to show pager, more, or neither
        if (limit <= 0) {
            // no display limit
            add(new Label("moreHistory", "").setVisible(false));
        } else {
            if (pageResults) {
                // paging
                add(new Label("moreHistory", "").setVisible(false));
            } else {
                // more
                if (commits.size() == limit) {
                    // show more
                    add(new LinkPanel("moreHistory", "link", new StringResourceModel("gb.moreHistory", this, null), HistoryPage.class, WicketUtils.newPathParameter(repositoryName, objectId, path)));
                } else {
                    // no more
                    add(new Label("moreHistory", "").setVisible(false));
                }
            }
        }
    }
    public boolean hasMore() {
        return hasMore;
    }
}
src/com/gitblit/wicket/panels/LogPanel.java
@@ -30,6 +30,8 @@
    private static final long serialVersionUID = 1L;
    private boolean hasMore = false;
    public LogPanel(String wicketId, final String repositoryName, String objectId, Repository r, int limit, int pageOffset) {
        super(wicketId);
        boolean pageResults = limit <= 0;
@@ -47,6 +49,10 @@
            // Fixed size result set
            commits = JGitUtils.getRevLog(r, objectId, 0, limit);
        }
        // inaccurate way to determine if there are more commits.
        // works unless commits.size() represents the exact end.
        hasMore = commits.size() >= itemsPerPage;
        // header
        if (pageResults) {
@@ -113,4 +119,8 @@
            }
        }
    }
    public boolean hasMore() {
        return hasMore;
    }
}