]> git.pld-linux.org Git - packages/tig.git/commitdiff
- new auto/ac/tig-0_10_1-1 auto/th/tig-0_10_1-1
authorAdam Gołębiowski <adamg@pld-linux.org>
Fri, 21 Mar 2008 12:57:30 +0000 (12:57 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    tig-git.patch -> 1.1

tig-git.patch [new file with mode: 0644]

diff --git a/tig-git.patch b/tig-git.patch
new file mode 100644 (file)
index 0000000..63180bb
--- /dev/null
@@ -0,0 +1,601 @@
+diff --git a/TODO b/TODO
+index adf9129..464e122 100644
+--- a/TODO
++++ b/TODO
+@@ -24,10 +24,8 @@ Features that should be explored.
+  - Split sources of tig.c into multiple files.
+- - Rewrite revgraph handling to use --parents and --boundary. The former
+-   should help to cleanup this messy part of the code, while the latter
+-   is nice for general repository inspection when revision limiters are
+-   used.
++ - Rewrite revgraph handling to use --parents, which should help to
++   cleanup this messy part of the code.
+  - Color the revgraph to make it easier to follow branches. Idea by
+    Dominik Vogt
+diff --git a/VERSION b/VERSION
+index 5712157..91e2525 100644
+--- a/VERSION
++++ b/VERSION
+@@ -1 +1 @@
+-0.10.1
++0.11.git
+diff --git a/configure.ac b/configure.ac
+index 65b5af3..764190a 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -12,12 +12,14 @@ AC_SEARCH_LIBS([wclear], [ncursesw ncurses curses], [],
+ AM_ICONV
+ AC_PROG_CC
+-AC_CHECK_PROGS(GIT_CONFIG, [git-config git-repo-config])
+-if test "${ac_cv_prog_GIT_CONFIG}" = ""; then
+-  AC_CHECK_PROGS(GIT, [git])
+-  GIT_CONFIG="${ac_cv_prog_GIT} config"
+-fi
++
++AC_CHECK_PROG(GIT, [git], [git], [AC_ERROR([git not found])])
++AC_MSG_CHECKING([which config command git supports])
++GIT_CONFIG="git repo-config"
++git config --list >/dev/null && GIT_CONFIG="git config"
++AC_MSG_RESULT([$GIT_CONFIG])
+ AC_DEFINE_UNQUOTED(GIT_CONFIG,"$GIT_CONFIG",[git config program])
++
+ AC_CHECK_PROGS(ASCIIDOC, [asciidoc false])
+ AC_CHECK_PROGS(XMLTO, [xmlto false])
+ AC_CHECK_PROGS(DOCBOOK2PDF, [docbook2pdf false])
+diff --git a/manual.txt b/manual.txt
+index ca01561..fd466db 100644
+--- a/manual.txt
++++ b/manual.txt
+@@ -347,7 +347,10 @@ z Stop all background loading. This can be useful if you use \
+       the revision log.
+ v     Show version.
+ '.'   Toggle line numbers on/off.
++D     Toggle date display on/off.
++A     Toggle author display on/off.
+ g     Toggle revision graph visualization on/off.
++F     Toggle reference display on/off (tag and branch names).
+ ':'   Open prompt. This allows you to specify what git command \
+       to run. Example `:log -p`
+ u     Update status of file. In the status view, this allows you to add an \
+diff --git a/tig.c b/tig.c
+index 1eb028b..36f03c2 100644
+--- a/tig.c
++++ b/tig.c
+@@ -58,7 +58,7 @@ static void warn(const char *msg, ...);
+ static void report(const char *msg, ...);
+ static int read_properties(FILE *pipe, const char *separators, int (*read)(char *, size_t, char *, size_t));
+ static void set_nonblocking_input(bool loading);
+-static size_t utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed);
++static size_t utf8_length(const char *string, size_t max_width, int *trimmed, bool reserve);
+ #define ABS(x)                ((x) >= 0  ? (x) : -(x))
+ #define MIN(x, y)     ((x) < (y) ? (x) :  (y))
+@@ -140,6 +140,7 @@ struct ref {
+       char *name;             /* Ref name; tag or head names are shortened. */
+       char id[SIZEOF_REV];    /* Commit SHA1 ID */
+       unsigned int tag:1;     /* Is it a tag? */
++      unsigned int ltag:1;    /* If so, is the tag local? */
+       unsigned int remote:1;  /* Is it a remote ref? */
+       unsigned int next:1;    /* For ref lists: are there more refs? */
+ };
+@@ -354,7 +355,10 @@ sq_quote(char buf[SIZEOF_STR], size_t bufsize, const char *src)
+       REQ_(SHOW_VERSION,      "Show version information"), \
+       REQ_(STOP_LOADING,      "Stop all loading views"), \
+       REQ_(TOGGLE_LINENO,     "Toggle line numbers"), \
++      REQ_(TOGGLE_DATE,       "Toggle date display"), \
++      REQ_(TOGGLE_AUTHOR,     "Toggle author display"), \
+       REQ_(TOGGLE_REV_GRAPH,  "Toggle revision graph visualization"), \
++      REQ_(TOGGLE_REFS,       "Toggle reference display (tags/branches)"), \
+       REQ_(STATUS_UPDATE,     "Update file status"), \
+       REQ_(STATUS_MERGE,      "Merge file using external tool"), \
+       REQ_(TREE_PARENT,       "Switch to parent directory in tree view"), \
+@@ -422,8 +426,11 @@ static const char usage[] =
+ "  -h, --help      Show help message and exit\n";
+ /* Option and state variables. */
++static bool opt_date                  = TRUE;
++static bool opt_author                        = TRUE;
+ static bool opt_line_number           = FALSE;
+ static bool opt_rev_graph             = FALSE;
++static bool opt_show_refs             = TRUE;
+ static int opt_num_interval           = NUMBER_INTERVAL;
+ static int opt_tab_size                       = TABSIZE;
+ static enum request opt_request               = REQ_VIEW_MAIN;
+@@ -598,9 +605,6 @@ parse_options(int argc, char *argv[])
+               opt_cmd[buf_size] = 0;
+       }
+-      if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
+-              opt_utf8 = FALSE;
+-
+       return TRUE;
+ }
+@@ -648,6 +652,7 @@ LINE(MAIN_AUTHOR,  "",                     COLOR_GREEN,    COLOR_DEFAULT,  0), \
+ LINE(MAIN_COMMIT,  "",                        COLOR_DEFAULT,  COLOR_DEFAULT,  0), \
+ LINE(MAIN_DELIM,   "",                        COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
+ LINE(MAIN_TAG,     "",                        COLOR_MAGENTA,  COLOR_DEFAULT,  A_BOLD), \
++LINE(MAIN_LOCAL_TAG,"",                       COLOR_MAGENTA,  COLOR_DEFAULT,  A_BOLD), \
+ LINE(MAIN_REMOTE,  "",                        COLOR_YELLOW,   COLOR_DEFAULT,  A_BOLD), \
+ LINE(MAIN_REF,     "",                        COLOR_CYAN,     COLOR_DEFAULT,  A_BOLD), \
+ LINE(MAIN_REVGRAPH,"",                        COLOR_MAGENTA,  COLOR_DEFAULT,  0), \
+@@ -808,7 +813,10 @@ static struct keybinding default_keybindings[] = {
+       { 'v',          REQ_SHOW_VERSION },
+       { 'r',          REQ_SCREEN_REDRAW },
+       { '.',          REQ_TOGGLE_LINENO },
++      { 'D',          REQ_TOGGLE_DATE },
++      { 'A',          REQ_TOGGLE_AUTHOR },
+       { 'g',          REQ_TOGGLE_REV_GRAPH },
++      { 'F',          REQ_TOGGLE_REFS },
+       { ':',          REQ_PROMPT },
+       { 'u',          REQ_STATUS_UPDATE },
+       { 'M',          REQ_STATUS_MERGE },
+@@ -1115,6 +1123,12 @@ option_color_command(int argc, char *argv[])
+       return OK;
+ }
++static bool parse_bool(const char *s)
++{
++      return (!strcmp(s, "1") || !strcmp(s, "true") ||
++              !strcmp(s, "yes")) ? TRUE : FALSE;
++}
++
+ /* Wants: name = value */
+ static int
+ option_set_command(int argc, char *argv[])
+@@ -1129,10 +1143,28 @@ option_set_command(int argc, char *argv[])
+               return ERR;
+       }
++      if (!strcmp(argv[0], "show-author")) {
++              opt_author = parse_bool(argv[2]);
++              return OK;
++      }
++
++      if (!strcmp(argv[0], "show-date")) {
++              opt_date = parse_bool(argv[2]);
++              return OK;
++      }
++
+       if (!strcmp(argv[0], "show-rev-graph")) {
+-              opt_rev_graph = (!strcmp(argv[2], "1") ||
+-                               !strcmp(argv[2], "true") ||
+-                               !strcmp(argv[2], "yes"));
++              opt_rev_graph = parse_bool(argv[2]);
++              return OK;
++      }
++
++      if (!strcmp(argv[0], "show-refs")) {
++              opt_show_refs = parse_bool(argv[2]);
++              return OK;
++      }
++
++      if (!strcmp(argv[0], "show-line-numbers")) {
++              opt_line_number = parse_bool(argv[2]);
+               return OK;
+       }
+@@ -1394,9 +1426,10 @@ struct view {
+       struct view *parent;
+       /* Buffering */
+-      unsigned long lines;    /* Total number of lines */
++      size_t lines;           /* Total number of lines */
+       struct line *line;      /* Line index */
+-      unsigned long line_size;/* Total number of allocated lines */
++      size_t line_alloc;      /* Total number of allocated lines */
++      size_t line_size;       /* Total number of used lines */
+       unsigned int digits;    /* Number of digits in the lines member. */
+       /* Loading */
+@@ -1460,44 +1493,34 @@ static int
+ draw_text(struct view *view, const char *string, int max_len, int col,
+         bool use_tilde, int tilde_attr)
+ {
+-      int n;
+-
+-      n = 0;
+-      if (max_len > 0) {
+-              int len;
+-              int trimmed = FALSE;
++      int len = 0;
++      int trimmed = FALSE;
+-              if (opt_utf8) {
+-                      int pad = 0;
++      if (max_len <= 0)
++              return 0;
+-                      len = utf8_length(string, max_len, &pad, &trimmed);
+-                      if (trimmed && use_tilde) {
++      if (opt_utf8) {
++              len = utf8_length(string, max_len, &trimmed, use_tilde);
++      } else {
++              len = strlen(string);
++              if (len > max_len) {
++                      if (use_tilde) {
+                               max_len -= 1;
+-                              len = utf8_length(
+-                                      string, max_len, &pad, &trimmed);
+                       }
+-                      n = len;
+-              } else {
+-                      len = strlen(string);
+-                      if (len > max_len) {
+-                              if (use_tilde) {
+-                                      max_len -= 1;
+-                              }
+-                              len = max_len;
+-                              trimmed = TRUE;
+-                      }
+-                      n = len;
+-              }
+-              waddnstr(view->win, string, n);
+-              if (trimmed && use_tilde) {
+-                      if (tilde_attr != -1)
+-                              wattrset(view->win, tilde_attr);
+-                      waddch(view->win, '~');
+-                      n++;
++                      len = max_len;
++                      trimmed = TRUE;
+               }
+       }
+-      return n;
++      waddnstr(view->win, string, len);
++      if (trimmed && use_tilde) {
++              if (tilde_attr != -1)
++                      wattrset(view->win, tilde_attr);
++              waddch(view->win, '~');
++              len++;
++      }
++
++      return len;
+ }
+ static bool
+@@ -2076,15 +2099,33 @@ begin_update(struct view *view)
+       return TRUE;
+ }
++#define ITEM_CHUNK_SIZE 256
++static void *
++realloc_items(void *mem, size_t *size, size_t new_size, size_t item_size)
++{
++      size_t num_chunks = *size / ITEM_CHUNK_SIZE;
++      size_t num_chunks_new = (new_size + ITEM_CHUNK_SIZE - 1) / ITEM_CHUNK_SIZE;
++
++      if (mem == NULL || num_chunks != num_chunks_new) {
++              *size = num_chunks_new * ITEM_CHUNK_SIZE;
++              mem = realloc(mem, *size * item_size);
++      }
++
++      return mem;
++}
++
+ static struct line *
+ realloc_lines(struct view *view, size_t line_size)
+ {
+-      struct line *tmp = realloc(view->line, sizeof(*view->line) * line_size);
++      size_t alloc = view->line_alloc;
++      struct line *tmp = realloc_items(view->line, &alloc, line_size,
++                                       sizeof(*view->line));
+       if (!tmp)
+               return NULL;
+       view->line = tmp;
++      view->line_alloc = alloc;
+       view->line_size = line_size;
+       return view->line;
+ }
+@@ -2550,11 +2591,26 @@ view_driver(struct view *view, enum request request)
+               redraw_display();
+               break;
++      case REQ_TOGGLE_DATE:
++              opt_date = !opt_date;
++              redraw_display();
++              break;
++
++      case REQ_TOGGLE_AUTHOR:
++              opt_author = !opt_author;
++              redraw_display();
++              break;
++
+       case REQ_TOGGLE_REV_GRAPH:
+               opt_rev_graph = !opt_rev_graph;
+               redraw_display();
+               break;
++      case REQ_TOGGLE_REFS:
++              opt_show_refs = !opt_show_refs;
++              redraw_display();
++              break;
++
+       case REQ_PROMPT:
+               /* Always reload^Wrerun commands from the prompt. */
+               open_view(view, opt_request, OPEN_RELOAD);
+@@ -3366,7 +3422,7 @@ error_out:
+ /* Don't show unmerged entries in the staged section. */
+ #define STATUS_DIFF_INDEX_CMD "git diff-index -z --diff-filter=ACDMRTXB --cached -M HEAD"
+-#define STATUS_DIFF_FILES_CMD "git update-index -q --refresh && git diff-files -z"
++#define STATUS_DIFF_FILES_CMD "git diff-files -z"
+ #define STATUS_LIST_OTHER_CMD \
+       "git ls-files -z --others --exclude-per-directory=.gitignore"
+@@ -3391,7 +3447,7 @@ status_open(struct view *view)
+       for (i = 0; i < view->lines; i++)
+               free(view->line[i].data);
+       free(view->line);
+-      view->lines = view->line_size = view->lineno = 0;
++      view->lines = view->line_alloc = view->line_size = view->lineno = 0;
+       view->line = NULL;
+       if (!realloc_lines(view, view->line_size + 6))
+@@ -3410,6 +3466,8 @@ status_open(struct view *view)
+                       return FALSE;
+       }
++      system("git update-index -q --refresh");
++
+       if (!status_run(view, STATUS_DIFF_INDEX_CMD, TRUE, LINE_STAT_STAGED) ||
+           !status_run(view, STATUS_DIFF_FILES_CMD, TRUE, LINE_STAT_UNSTAGED) ||
+           !status_run(view, cmd, FALSE, LINE_STAT_UNTRACKED))
+@@ -4183,7 +4241,7 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select
+               tilde_attr = get_line_attr(LINE_MAIN_DELIM);
+       }
+-      {
++      if (opt_date) {
+               int n;
+               timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time);
+@@ -4201,7 +4259,7 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select
+       if (type != LINE_CURSOR)
+               wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR));
+-      {
++      if (opt_author) {
+               int max_len;
+               max_len = view->width - col;
+@@ -4238,12 +4296,14 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select
+       wmove(view->win, lineno, col);
+-      if (commit->refs) {
++      if (opt_show_refs && commit->refs) {
+               size_t i = 0;
+               do {
+                       if (type == LINE_CURSOR)
+                               ;
++                      else if (commit->refs[i]->ltag)
++                              wattrset(view->win, get_line_attr(LINE_MAIN_LOCAL_TAG));
+                       else if (commit->refs[i]->tag)
+                               wattrset(view->win, get_line_attr(LINE_MAIN_TAG));
+                       else if (commit->refs[i]->remote)
+@@ -4559,19 +4619,16 @@ utf8_to_unicode(const char *string, size_t length)
+ /* Calculates how much of string can be shown within the given maximum width
+  * and sets trimmed parameter to non-zero value if all of string could not be
+- * shown.
+- *
+- * Additionally, adds to coloffset how many many columns to move to align with
+- * the expected position. Takes into account how multi-byte and double-width
+- * characters will effect the cursor position.
++ * shown. If the reserve flag is TRUE, it will reserve at least one
++ * trailing character, which can be useful when drawing a delimiter.
+  *
+  * Returns the number of bytes to output from string to satisfy max_width. */
+ static size_t
+-utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed)
++utf8_length(const char *string, size_t max_width, int *trimmed, bool reserve)
+ {
+       const char *start = string;
+       const char *end = strchr(string, '\0');
+-      size_t mbwidth = 0;
++      unsigned char last_bytes = 0;
+       size_t width = 0;
+       *trimmed = 0;
+@@ -4597,27 +4654,16 @@ utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed)
+               width  += ucwidth;
+               if (width > max_width) {
+                       *trimmed = 1;
++                      if (reserve && width - ucwidth == max_width) {
++                              string -= last_bytes;
++                      }
+                       break;
+               }
+-              /* The column offset collects the differences between the
+-               * number of bytes encoding a character and the number of
+-               * columns will be used for rendering said character.
+-               *
+-               * So if some character A is encoded in 2 bytes, but will be
+-               * represented on the screen using only 1 byte this will and up
+-               * adding 1 to the multi-byte column offset.
+-               *
+-               * Assumes that no double-width character can be encoding in
+-               * less than two bytes. */
+-              if (bytes > ucwidth)
+-                      mbwidth += bytes - ucwidth;
+-
+               string  += bytes;
++              last_bytes = bytes;
+       }
+-      *coloffset += mbwidth;
+-
+       return string - start;
+ }
+@@ -4800,18 +4846,21 @@ read_prompt(const char *prompt)
+  * Repository references
+  */
+-static struct ref *refs;
+-static size_t refs_size;
++static struct ref *refs = NULL;
++static size_t refs_alloc = 0;
++static size_t refs_size = 0;
+ /* Id <-> ref store */
+-static struct ref ***id_refs;
+-static size_t id_refs_size;
++static struct ref ***id_refs = NULL;
++static size_t id_refs_alloc = 0;
++static size_t id_refs_size = 0;
+ static struct ref **
+ get_refs(char *id)
+ {
+       struct ref ***tmp_id_refs;
+       struct ref **ref_list = NULL;
++      size_t ref_list_alloc = 0;
+       size_t ref_list_size = 0;
+       size_t i;
+@@ -4819,7 +4868,8 @@ get_refs(char *id)
+               if (!strcmp(id, id_refs[i][0]->id))
+                       return id_refs[i];
+-      tmp_id_refs = realloc(id_refs, (id_refs_size + 1) * sizeof(*id_refs));
++      tmp_id_refs = realloc_items(id_refs, &id_refs_alloc, id_refs_size + 1,
++                                  sizeof(*id_refs));
+       if (!tmp_id_refs)
+               return NULL;
+@@ -4831,7 +4881,8 @@ get_refs(char *id)
+               if (strcmp(id, refs[i].id))
+                       continue;
+-              tmp = realloc(ref_list, (ref_list_size + 1) * sizeof(*ref_list));
++              tmp = realloc_items(ref_list, &ref_list_alloc,
++                                  ref_list_size + 1, sizeof(*ref_list));
+               if (!tmp) {
+                       if (ref_list)
+                               free(ref_list);
+@@ -4861,15 +4912,19 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
+ {
+       struct ref *ref;
+       bool tag = FALSE;
++      bool ltag = FALSE;
+       bool remote = FALSE;
++      bool check_replace = FALSE;
+       if (!strncmp(name, "refs/tags/", STRING_SIZE("refs/tags/"))) {
+-              /* Commits referenced by tags has "^{}" appended. */
+-              if (name[namelen - 1] != '}')
+-                      return OK;
+-
+-              while (namelen > 0 && name[namelen] != '^')
+-                      namelen--;
++              if (!strcmp(name + namelen - 3, "^{}")) {
++                      namelen -= 3;
++                      name[namelen] = 0;
++                      if (refs_size > 0 && refs[refs_size - 1].ltag == TRUE)
++                              check_replace = TRUE;
++              } else {
++                      ltag = TRUE;
++              }
+               tag = TRUE;
+               namelen -= STRING_SIZE("refs/tags/");
+@@ -4888,7 +4943,17 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
+               return OK;
+       }
+-      refs = realloc(refs, sizeof(*refs) * (refs_size + 1));
++      if (check_replace && !strcmp(name, refs[refs_size - 1].name)) {
++              /* it's an annotated tag, replace the previous sha1 with the
++               * resolved commit id; relies on the fact git-ls-remote lists
++               * the commit id of an annotated tag right beofre the commit id
++               * it points to. */
++              refs[refs_size - 1].ltag = ltag;
++              string_copy_rev(refs[refs_size - 1].id, id);
++
++              return OK;
++      }
++      refs = realloc_items(refs, &refs_alloc, refs_size + 1, sizeof(*refs));
+       if (!refs)
+               return ERR;
+@@ -4900,6 +4965,7 @@ read_ref(char *id, size_t idlen, char *name, size_t namelen)
+       strncpy(ref->name, name, namelen);
+       ref->name[namelen] = 0;
+       ref->tag = tag;
++      ref->ltag = ltag;
+       ref->remote = remote;
+       string_copy_rev(ref->id, id);
+@@ -5079,6 +5145,9 @@ main(int argc, char *argv[])
+       if (!opt_git_dir[0])
+               die("Not a git repository");
++      if (*opt_encoding && strcasecmp(opt_encoding, "UTF-8"))
++              opt_utf8 = FALSE;
++
+       if (*opt_codeset && strcmp(opt_codeset, opt_encoding)) {
+               opt_iconv = iconv_open(opt_codeset, opt_encoding);
+               if (opt_iconv == ICONV_NONE)
+diff --git a/tigrc.5.txt b/tigrc.5.txt
+index f7d7bed..bed3116 100644
+--- a/tigrc.5.txt
++++ b/tigrc.5.txt
+@@ -42,7 +42,11 @@ is:
+ Examples:
+ --------------------------------------------------------------------------
++set show-author = yes         # Show author?
++set show-date = yes           # Show commit date?
+ set show-rev-graph = yes      # Show revision graph?
++set show-refs = yes           # Show references?
++set show-line-numbers = no    # Show line numbers?
+ set line-number-interval = 5  # Interval between line numbers
+ set tab-size = 8              # Number of spaces per tab
+ set encoding = "UTF-8"                # Commit encoding
+@@ -68,10 +72,14 @@ Variables
+ The following variables can be set:
++'show-author' (bool)::
++'show-date' (bool)::
+ 'show-rev-graph' (bool)::
++'show-refs' (bool)::
+-      Show revision graph in the main view on start-up. Can be toggled with
+-      'g'.
++      Whether to show author, date, revision graph, and references
++      (branches, tags, and remotes) in the main view on start-up. Can all be
++      toggled.
+ 'line-number-interval' (int)::
+@@ -243,7 +251,10 @@ screen-resize             Resize the screen
+ show-version          Show version information
+ stop-loading          Stop all loading views
+ toggle-lineno         Toggle line numbers
++toggle-date           Toggle date display
++toggle-author         Toggle author display
+ toggle-rev-graph      Toggle revision graph visualization
++toggle-refs           Toggle reference display
+ status-update         Update file status
+ status-merge          Resolve unmerged file
+ tree-parent           Switch to parent directory in tree view
+@@ -336,7 +347,7 @@ Appearance of the various columns in the main view, including the '~' used for
+ delimiting long author names and labels for tag and branch references.
+ *main-date*, *main-author*, *main-commit*, *main-delim*, *main-tag*,
+-*main-ref*, *main-remote*, *main-revgraph*
++*main-local-tag*, *main-ref*, *main-remote*, *main-revgraph*
+ --
This page took 0.155213 seconds and 4 git commands to generate.