/[gnats]/gnats/libiberty/hashtab.c
ViewVC logotype

Diff of /gnats/libiberty/hashtab.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by pdm, Mon Dec 10 23:03:26 2001 UTC revision 1.2 by chewie, Sat Nov 13 05:14:17 2004 UTC
# Line 1  Line 1 
1  /* An expandable hash tables datatype.    /* An expandable hash tables datatype.  
2     Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.     Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3     Contributed by Vladimir Makarov (vmakarov@cygnus.com).     Contributed by Vladimir Makarov (vmakarov@cygnus.com).
4    
5  This file is part of the libiberty library.  This file is part of the libiberty library.
# Line 45  Boston, MA 02111-1307, USA.  */ Line 45  Boston, MA 02111-1307, USA.  */
45  #include <string.h>  #include <string.h>
46  #endif  #endif
47    
48    #ifdef HAVE_MALLOC_H
49    #include <malloc.h>
50    #endif
51    
52  #include <stdio.h>  #include <stdio.h>
53    
54  #include "libiberty.h"  #include "libiberty.h"
# Line 80  higher_prime_number (n) Line 84  higher_prime_number (n)
84  {  {
85    /* These are primes that are near, but slightly smaller than, a    /* These are primes that are near, but slightly smaller than, a
86       power of two.  */       power of two.  */
87    static unsigned long primes[] = {    static const unsigned long primes[] = {
     (unsigned long) 2,  
88      (unsigned long) 7,      (unsigned long) 7,
89      (unsigned long) 13,      (unsigned long) 13,
90      (unsigned long) 31,      (unsigned long) 31,
# Line 115  higher_prime_number (n) Line 118  higher_prime_number (n)
118      ((unsigned long) 2147483647) + ((unsigned long) 2147483644),      ((unsigned long) 2147483647) + ((unsigned long) 2147483644),
119    };    };
120    
121    unsigned long* low = &primes[0];    const unsigned long *low = &primes[0];
122    unsigned long* high = &primes[sizeof(primes) / sizeof(primes[0])];    const unsigned long *high = &primes[sizeof(primes) / sizeof(primes[0])];
123    
124    while (low != high)    while (low != high)
125      {      {
126        unsigned long* mid = low + (high - low) / 2;        const unsigned long *mid = low + (high - low) / 2;
127        if (n > *mid)        if (n > *mid)
128          low = mid + 1;          low = mid + 1;
129        else        else
# Line 159  eq_pointer (p1, p2) Line 162  eq_pointer (p1, p2)
162  /* This function creates table with length slightly longer than given  /* This function creates table with length slightly longer than given
163     source length.  Created hash table is initiated as empty (all the     source length.  Created hash table is initiated as empty (all the
164     hash table entries are EMPTY_ENTRY).  The function returns the     hash table entries are EMPTY_ENTRY).  The function returns the
165     created hash table.  Memory allocation must not fail.  */     created hash table, or NULL if memory allocation fails.  */
166    
167  htab_t  htab_t
168  htab_create (size, hash_f, eq_f, del_f)  htab_create_alloc (size, hash_f, eq_f, del_f, alloc_f, free_f)
169       size_t size;       size_t size;
170       htab_hash hash_f;       htab_hash hash_f;
171       htab_eq eq_f;       htab_eq eq_f;
172       htab_del del_f;       htab_del del_f;
173         htab_alloc alloc_f;
174         htab_free free_f;
175  {  {
176    htab_t result;    htab_t result;
177    
178    size = higher_prime_number (size);    size = higher_prime_number (size);
179    result = (htab_t) xcalloc (1, sizeof (struct htab));    result = (htab_t) (*alloc_f) (1, sizeof (struct htab));
180    result->entries = (PTR *) xcalloc (size, sizeof (PTR));    if (result == NULL)
181        return NULL;
182      result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR));
183      if (result->entries == NULL)
184        {
185          if (free_f != NULL)
186            (*free_f) (result);
187          return NULL;
188        }
189    result->size = size;    result->size = size;
190    result->hash_f = hash_f;    result->hash_f = hash_f;
191    result->eq_f = eq_f;    result->eq_f = eq_f;
192    result->del_f = del_f;    result->del_f = del_f;
193    result->return_allocation_failure = 0;    result->alloc_f = alloc_f;
194      result->free_f = free_f;
195    return result;    return result;
196  }  }
197    
198  /* This function creates table with length slightly longer than given  /* As above, but use the variants of alloc_f and free_f which accept
199     source length.  The created hash table is initiated as empty (all the     an extra argument.  */
    hash table entries are EMPTY_ENTRY).  The function returns the created  
    hash table.  Memory allocation may fail; it may return NULL.  */  
200    
201  htab_t  htab_t
202  htab_try_create (size, hash_f, eq_f, del_f)  htab_create_alloc_ex (size, hash_f, eq_f, del_f, alloc_arg, alloc_f,
203                          free_f)
204       size_t size;       size_t size;
205       htab_hash hash_f;       htab_hash hash_f;
206       htab_eq eq_f;       htab_eq eq_f;
207       htab_del del_f;       htab_del del_f;
208         PTR alloc_arg;
209         htab_alloc_with_arg alloc_f;
210         htab_free_with_arg free_f;
211  {  {
212    htab_t result;    htab_t result;
213    
214    size = higher_prime_number (size);    size = higher_prime_number (size);
215    result = (htab_t) calloc (1, sizeof (struct htab));    result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab));
216    if (result == NULL)    if (result == NULL)
217      return NULL;      return NULL;
218      result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR));
   result->entries = (PTR *) calloc (size, sizeof (PTR));  
219    if (result->entries == NULL)    if (result->entries == NULL)
220      {      {
221        free (result);        if (free_f != NULL)
222            (*free_f) (alloc_arg, result);
223        return NULL;        return NULL;
224      }      }
   
225    result->size = size;    result->size = size;
226    result->hash_f = hash_f;    result->hash_f = hash_f;
227    result->eq_f = eq_f;    result->eq_f = eq_f;
228    result->del_f = del_f;    result->del_f = del_f;
229    result->return_allocation_failure = 1;    result->alloc_arg = alloc_arg;
230      result->alloc_with_arg_f = alloc_f;
231      result->free_with_arg_f = free_f;
232    return result;    return result;
233  }  }
234    
235    /* Update the function pointers and allocation parameter in the htab_t.  */
236    
237    void
238    htab_set_functions_ex (htab, hash_f, eq_f, del_f, alloc_arg, alloc_f, free_f)
239         htab_t htab;
240         htab_hash hash_f;
241         htab_eq eq_f;
242         htab_del del_f;
243         PTR alloc_arg;
244         htab_alloc_with_arg alloc_f;
245         htab_free_with_arg free_f;
246    {
247      htab->hash_f = hash_f;
248      htab->eq_f = eq_f;
249      htab->del_f = del_f;
250      htab->alloc_arg = alloc_arg;
251      htab->alloc_with_arg_f = alloc_f;
252      htab->free_with_arg_f = free_f;
253    }
254    
255    /* These functions exist solely for backward compatibility.  */
256    
257    #undef htab_create
258    htab_t
259    htab_create (size, hash_f, eq_f, del_f)
260         size_t size;
261         htab_hash hash_f;
262         htab_eq eq_f;
263         htab_del del_f;
264    {
265      return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free);
266    }
267    
268    htab_t
269    htab_try_create (size, hash_f, eq_f, del_f)
270         size_t size;
271         htab_hash hash_f;
272         htab_eq eq_f;
273         htab_del del_f;
274    {
275      return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free);
276    }
277    
278  /* This function frees all memory allocated for given hash table.  /* This function frees all memory allocated for given hash table.
279     Naturally the hash table must already exist. */     Naturally the hash table must already exist. */
280    
# Line 230  htab_delete (htab) Line 290  htab_delete (htab)
290            && htab->entries[i] != DELETED_ENTRY)            && htab->entries[i] != DELETED_ENTRY)
291          (*htab->del_f) (htab->entries[i]);          (*htab->del_f) (htab->entries[i]);
292    
293    free (htab->entries);    if (htab->free_f != NULL)
294    free (htab);      {
295          (*htab->free_f) (htab->entries);
296          (*htab->free_f) (htab);
297        }
298      else if (htab->free_with_arg_f != NULL)
299        {
300          (*htab->free_with_arg_f) (htab->alloc_arg, htab->entries);
301          (*htab->free_with_arg_f) (htab->alloc_arg, htab);
302        }
303  }  }
304    
305  /* This function clears all entries in the given hash table.  */  /* This function clears all entries in the given hash table.  */
# Line 264  find_empty_slot_for_expand (htab, hash) Line 332  find_empty_slot_for_expand (htab, hash)
332       hashval_t hash;       hashval_t hash;
333  {  {
334    size_t size = htab->size;    size_t size = htab->size;
   hashval_t hash2 = 1 + hash % (size - 2);  
335    unsigned int index = hash % size;    unsigned int index = hash % size;
336      PTR *slot = htab->entries + index;
337      hashval_t hash2;
338    
339      if (*slot == EMPTY_ENTRY)
340        return slot;
341      else if (*slot == DELETED_ENTRY)
342        abort ();
343    
344      hash2 = 1 + hash % (size - 2);
345    for (;;)    for (;;)
346      {      {
347        PTR *slot = htab->entries + index;        index += hash2;
348          if (index >= size)
349            index -= size;
350    
351          slot = htab->entries + index;
352        if (*slot == EMPTY_ENTRY)        if (*slot == EMPTY_ENTRY)
353          return slot;          return slot;
354        else if (*slot == DELETED_ENTRY)        else if (*slot == DELETED_ENTRY)
355          abort ();          abort ();
   
       index += hash2;  
       if (index >= size)  
         index -= size;  
356      }      }
357  }  }
358    
# Line 297  htab_expand (htab) Line 371  htab_expand (htab)
371    PTR *oentries;    PTR *oentries;
372    PTR *olimit;    PTR *olimit;
373    PTR *p;    PTR *p;
374      PTR *nentries;
375      size_t nsize;
376    
377    oentries = htab->entries;    oentries = htab->entries;
378    olimit = oentries + htab->size;    olimit = oentries + htab->size;
379    
380    htab->size = higher_prime_number (htab->size * 2);    /* Resize only when table after removal of unused elements is either
381         too full or too empty.  */
382      if ((htab->n_elements - htab->n_deleted) * 2 > htab->size
383          || ((htab->n_elements - htab->n_deleted) * 8 < htab->size
384              && htab->size > 32))
385        nsize = higher_prime_number ((htab->n_elements - htab->n_deleted) * 2);
386      else
387        nsize = htab->size;
388    
389    if (htab->return_allocation_failure)    if (htab->alloc_with_arg_f != NULL)
390      {      nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize,
391        PTR *nentries = (PTR *) calloc (htab->size, sizeof (PTR *));                                                    sizeof (PTR *));
       if (nentries == NULL)  
         return 0;  
       htab->entries = nentries;  
     }  
392    else    else
393      htab->entries = (PTR *) xcalloc (htab->size, sizeof (PTR *));      nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *));
394      if (nentries == NULL)
395        return 0;
396      htab->entries = nentries;
397      htab->size = nsize;
398    
399    htab->n_elements -= htab->n_deleted;    htab->n_elements -= htab->n_deleted;
400    htab->n_deleted = 0;    htab->n_deleted = 0;
# Line 332  htab_expand (htab) Line 415  htab_expand (htab)
415      }      }
416    while (p < olimit);    while (p < olimit);
417    
418    free (oentries);    if (htab->free_f != NULL)
419        (*htab->free_f) (oentries);
420      else if (htab->free_with_arg_f != NULL)
421        (*htab->free_with_arg_f) (htab->alloc_arg, oentries);
422    return 1;    return 1;
423  }  }
424    
# Line 405  htab_find_slot_with_hash (htab, element, Line 491  htab_find_slot_with_hash (htab, element,
491    unsigned int index;    unsigned int index;
492    hashval_t hash2;    hashval_t hash2;
493    size_t size;    size_t size;
494      PTR entry;
495    
496    if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4    if (insert == INSERT && htab->size * 3 <= htab->n_elements * 4
497        && htab_expand (htab) == 0)        && htab_expand (htab) == 0)
498      return NULL;      return NULL;
499    
500    size = htab->size;    size = htab->size;
   hash2 = 1 + hash % (size - 2);  
501    index = hash % size;    index = hash % size;
502    
503    htab->searches++;    htab->searches++;
504    first_deleted_slot = NULL;    first_deleted_slot = NULL;
505    
506      entry = htab->entries[index];
507      if (entry == EMPTY_ENTRY)
508        goto empty_entry;
509      else if (entry == DELETED_ENTRY)
510        first_deleted_slot = &htab->entries[index];
511      else if ((*htab->eq_f) (entry, element))
512        return &htab->entries[index];
513          
514      hash2 = 1 + hash % (size - 2);
515    for (;;)    for (;;)
516      {      {
517        PTR entry = htab->entries[index];        htab->collisions++;
518          index += hash2;
519          if (index >= size)
520            index -= size;
521          
522          entry = htab->entries[index];
523        if (entry == EMPTY_ENTRY)        if (entry == EMPTY_ENTRY)
524          {          goto empty_entry;
525            if (insert == NO_INSERT)        else if (entry == DELETED_ENTRY)
             return NULL;  
   
           htab->n_elements++;  
   
           if (first_deleted_slot)  
             {  
               *first_deleted_slot = EMPTY_ENTRY;  
               return first_deleted_slot;  
             }  
   
           return &htab->entries[index];  
         }  
   
       if (entry == DELETED_ENTRY)  
526          {          {
527            if (!first_deleted_slot)            if (!first_deleted_slot)
528              first_deleted_slot = &htab->entries[index];              first_deleted_slot = &htab->entries[index];
529          }          }
530        else  if ((*htab->eq_f) (entry, element))        else if ((*htab->eq_f) (entry, element))
531          return &htab->entries[index];          return &htab->entries[index];
         
       htab->collisions++;  
       index += hash2;  
       if (index >= size)  
         index -= size;  
532      }      }
533    
534     empty_entry:
535      if (insert == NO_INSERT)
536        return NULL;
537    
538      if (first_deleted_slot)
539        {
540          htab->n_deleted--;
541          *first_deleted_slot = EMPTY_ENTRY;
542          return first_deleted_slot;
543        }
544    
545      htab->n_elements++;
546      return &htab->entries[index];
547  }  }
548    
549  /* Like htab_find_slot_with_hash, but compute the hash value from the  /* Like htab_find_slot_with_hash, but compute the hash value from the
# Line 512  htab_clear_slot (htab, slot) Line 607  htab_clear_slot (htab, slot)
607     argument.  */     argument.  */
608    
609  void  void
610  htab_traverse (htab, callback, info)  htab_traverse_noresize (htab, callback, info)
611       htab_t htab;       htab_t htab;
612       htab_trav callback;       htab_trav callback;
613       PTR info;       PTR info;
614  {  {
615    PTR *slot = htab->entries;    PTR *slot;
616    PTR *limit = slot + htab->size;    PTR *limit;
617    
618      slot = htab->entries;
619      limit = slot + htab->size;
620    
621    do    do
622      {      {
# Line 531  htab_traverse (htab, callback, info) Line 629  htab_traverse (htab, callback, info)
629    while (++slot < limit);    while (++slot < limit);
630  }  }
631    
632    /* Like htab_traverse_noresize, but does resize the table when it is
633       too empty to improve effectivity of subsequent calls.  */
634    
635    void
636    htab_traverse (htab, callback, info)
637         htab_t htab;
638         htab_trav callback;
639         PTR info;
640    {
641      if ((htab->n_elements - htab->n_deleted) * 8 < htab->size)
642        htab_expand (htab);
643    
644      htab_traverse_noresize (htab, callback, info);
645    }
646    
647  /* Return the current size of given hash table. */  /* Return the current size of given hash table. */
648    
649  size_t  size_t
# Line 561  htab_collisions (htab) Line 674  htab_collisions (htab)
674    
675    return (double) htab->collisions / (double) htab->searches;    return (double) htab->collisions / (double) htab->searches;
676  }  }
677    
678    /* Hash P as a null-terminated string.
679    
680       Copied from gcc/hashtable.c.  Zack had the following to say with respect
681       to applicability, though note that unlike hashtable.c, this hash table
682       implementation re-hashes rather than chain buckets.
683    
684       http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01021.html
685       From: Zack Weinberg <zackw@panix.com>
686       Date: Fri, 17 Aug 2001 02:15:56 -0400
687    
688       I got it by extracting all the identifiers from all the source code
689       I had lying around in mid-1999, and testing many recurrences of
690       the form "H_n = H_{n-1} * K + c_n * L + M" where K, L, M were either
691       prime numbers or the appropriate identity.  This was the best one.
692       I don't remember exactly what constituted "best", except I was
693       looking at bucket-length distributions mostly.
694      
695       So it should be very good at hashing identifiers, but might not be
696       as good at arbitrary strings.
697      
698       I'll add that it thoroughly trounces the hash functions recommended
699       for this use at http://burtleburtle.net/bob/hash/index.html, both
700       on speed and bucket distribution.  I haven't tried it against the
701       function they just started using for Perl's hashes.  */
702    
703    hashval_t
704    htab_hash_string (p)
705         const PTR p;
706    {
707      const unsigned char *str = (const unsigned char *) p;
708      hashval_t r = 0;
709      unsigned char c;
710    
711      while ((c = *str++) != 0)
712        r = r * 67 + c - 113;
713    
714      return r;
715    }
716    
717    /* DERIVED FROM:
718    --------------------------------------------------------------------
719    lookup2.c, by Bob Jenkins, December 1996, Public Domain.
720    hash(), hash2(), hash3, and mix() are externally useful functions.
721    Routines to test the hash are included if SELF_TEST is defined.
722    You can use this free for any purpose.  It has no warranty.
723    --------------------------------------------------------------------
724    */
725    
726    /*
727    --------------------------------------------------------------------
728    mix -- mix 3 32-bit values reversibly.
729    For every delta with one or two bit set, and the deltas of all three
730      high bits or all three low bits, whether the original value of a,b,c
731      is almost all zero or is uniformly distributed,
732    * If mix() is run forward or backward, at least 32 bits in a,b,c
733      have at least 1/4 probability of changing.
734    * If mix() is run forward, every bit of c will change between 1/3 and
735      2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
736    mix() was built out of 36 single-cycle latency instructions in a
737      structure that could supported 2x parallelism, like so:
738          a -= b;
739          a -= c; x = (c>>13);
740          b -= c; a ^= x;
741          b -= a; x = (a<<8);
742          c -= a; b ^= x;
743          c -= b; x = (b>>13);
744          ...
745      Unfortunately, superscalar Pentiums and Sparcs can't take advantage
746      of that parallelism.  They've also turned some of those single-cycle
747      latency instructions into multi-cycle latency instructions.  Still,
748      this is the fastest good hash I could find.  There were about 2^^68
749      to choose from.  I only looked at a billion or so.
750    --------------------------------------------------------------------
751    */
752    /* same, but slower, works on systems that might have 8 byte hashval_t's */
753    #define mix(a,b,c) \
754    { \
755      a -= b; a -= c; a ^= (c>>13); \
756      b -= c; b -= a; b ^= (a<< 8); \
757      c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \
758      a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \
759      b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \
760      c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \
761      a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \
762      b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \
763      c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \
764    }
765    
766    /*
767    --------------------------------------------------------------------
768    hash() -- hash a variable-length key into a 32-bit value
769      k     : the key (the unaligned variable-length array of bytes)
770      len   : the length of the key, counting by bytes
771      level : can be any 4-byte value
772    Returns a 32-bit value.  Every bit of the key affects every bit of
773    the return value.  Every 1-bit and 2-bit delta achieves avalanche.
774    About 36+6len instructions.
775    
776    The best hash table sizes are powers of 2.  There is no need to do
777    mod a prime (mod is sooo slow!).  If you need less than 32 bits,
778    use a bitmask.  For example, if you need only 10 bits, do
779      h = (h & hashmask(10));
780    In which case, the hash table should have hashsize(10) elements.
781    
782    If you are hashing n strings (ub1 **)k, do it like this:
783      for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
784    
785    By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
786    code any way you wish, private, educational, or commercial.  It's free.
787    
788    See http://burtleburtle.net/bob/hash/evahash.html
789    Use for hash table lookup, or anything where one collision in 2^32 is
790    acceptable.  Do NOT use for cryptographic purposes.
791    --------------------------------------------------------------------
792    */
793    
794    hashval_t iterative_hash (k_in, length, initval)
795         const PTR k_in;               /* the key */
796         register size_t  length;      /* the length of the key */
797         register hashval_t  initval;  /* the previous hash, or an arbitrary value */
798    {
799      register const unsigned char *k = (const unsigned char *)k_in;
800      register hashval_t a,b,c,len;
801    
802      /* Set up the internal state */
803      len = length;
804      a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
805      c = initval;           /* the previous hash value */
806    
807      /*---------------------------------------- handle most of the key */
808    #ifndef WORDS_BIGENDIAN
809      /* On a little-endian machine, if the data is 4-byte aligned we can hash
810         by word for better speed.  This gives nondeterministic results on
811         big-endian machines.  */
812      if (sizeof (hashval_t) == 4 && (((size_t)k)&3) == 0)
813        while (len >= 12)    /* aligned */
814          {
815            a += *(hashval_t *)(k+0);
816            b += *(hashval_t *)(k+4);
817            c += *(hashval_t *)(k+8);
818            mix(a,b,c);
819            k += 12; len -= 12;
820          }
821      else /* unaligned */
822    #endif
823        while (len >= 12)
824          {
825            a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24));
826            b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24));
827            c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24));
828            mix(a,b,c);
829            k += 12; len -= 12;
830          }
831    
832      /*------------------------------------- handle the last 11 bytes */
833      c += length;
834      switch(len)              /* all the case statements fall through */
835        {
836        case 11: c+=((hashval_t)k[10]<<24);
837        case 10: c+=((hashval_t)k[9]<<16);
838        case 9 : c+=((hashval_t)k[8]<<8);
839          /* the first byte of c is reserved for the length */
840        case 8 : b+=((hashval_t)k[7]<<24);
841        case 7 : b+=((hashval_t)k[6]<<16);
842        case 6 : b+=((hashval_t)k[5]<<8);
843        case 5 : b+=k[4];
844        case 4 : a+=((hashval_t)k[3]<<24);
845        case 3 : a+=((hashval_t)k[2]<<16);
846        case 2 : a+=((hashval_t)k[1]<<8);
847        case 1 : a+=k[0];
848          /* case 0: nothing left to add */
849        }
850      mix(a,b,c);
851      /*-------------------------------------------- report the result */
852      return c;
853    }

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.2

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26