Changeset ea40556 for iknow-api/Data


Ignore:
Timestamp:
09/15/26 21:15:53 (8 days ago)
Author:
Stefan-Saveski <stefansaveski19@…>
Branches:
master
Children:
a12988e, c42181c
Parents:
10009b9
Message:
  • ready for presentation
Location:
iknow-api/Data
Files:
1 added
1 edited

Legend:

Unmodified
Added
Removed
  • iknow-api/Data/AppDbContext.cs

    r10009b9 rea40556  
    44namespace iknow_api.Data
    55{
     6    /// <summary>
     7    /// The schema is owned by sql/ddl.sql, not by EF migrations. Every entity
     8    /// below is mapped explicitly onto the table and column names in that
     9    /// script; nothing here may rely on EF naming conventions.
     10    /// </summary>
    611    public class AppDbContext : DbContext
    712    {
     13        /// <summary>
     14        /// The schema created by sql/schema_creation.sql. Every table and enum
     15        /// type is qualified with it, so nothing depends on search_path.
     16        /// </summary>
     17        public const string ProjectSchema = "project";
     18
    819        public AppDbContext(DbContextOptions<AppDbContext> options)
    920            : base(options) { }
     
    1223        public DbSet<ContactInfo> ContactInfo { get; set; }
    1324        public DbSet<HighSchool> HighSchool { get; set; }
    14         public DbSet<EnrollmentInfo> EnrollmentInfo { get; set; }
    1525        public DbSet<RefreshToken> RefreshToken { get; set; }
    1626        public DbSet<Subject> Subjects { get; set; }
     
    2737        public DbSet<ProfessorSubjects> ProfessorSubjects { get; set; }
    2838
    29 
    3039        protected override void OnModelCreating(ModelBuilder modelBuilder)
    3140        {
    3241            base.OnModelCreating(modelBuilder);
    3342
    34             modelBuilder.Entity<Major>().HasData(
    35                 new Major { Id = 1, Name = "PIT" },
    36                 new Major { Id = 2, Name = "SIIS" },
    37                 new Major { Id = 3, Name = "SEIS" },
    38                 new Major { Id = 4, Name = "KN" }
    39             );
    40 
    41 
    42             // -------------------------
    43             // DependencySubject (self-referencing many-to-many)
    44             // -------------------------
    45             modelBuilder.Entity<DependencySubject>()
    46                 .HasKey(ds => new { ds.SubjectId, ds.DependencyId });
    47 
    48             modelBuilder.Entity<DependencySubject>()
    49                 .HasOne(ds => ds.Subject)
    50                 .WithMany(s => s.Dependencies)
    51                 .HasForeignKey(ds => ds.SubjectId)
    52                 .OnDelete(DeleteBehavior.Restrict);
    53 
    54             modelBuilder.Entity<DependencySubject>()
    55                 .HasOne(ds => ds.Dependency)
    56                 .WithMany(s => s.Dependents)
    57                 .HasForeignKey(ds => ds.DependencyId)
    58                 .OnDelete(DeleteBehavior.Restrict);
    59 
    60             // -------------------------
    61             // MajorSubjects (many-to-many)
    62             // -------------------------
    63             modelBuilder.Entity<MajorSubjects>()
    64                 .HasKey(ab => new { ab.MajorId, ab.SubjectId });
    65 
    66             modelBuilder.Entity<MajorSubjects>()
    67                 .HasOne(ab => ab.Majors)
    68                 .WithMany(a => a.Subjects)
    69                 .HasForeignKey(ab => ab.MajorId)
    70                 .OnDelete(DeleteBehavior.Cascade);
    71 
    72             modelBuilder.Entity<MajorSubjects>()
    73                 .HasOne(ab => ab.Subjects)
    74                 .WithMany(b => b.Majors)
    75                 .HasForeignKey(ab => ab.SubjectId)
    76                 .OnDelete(DeleteBehavior.Cascade);
    77 
    78             // -------------------------
    79             // UserDocuments (many-to-many)
    80             // -------------------------
    81             modelBuilder.Entity<UserDocuments>()
    82                 .HasKey(ab => new { ab.UserId, ab.DocumentId });
    83 
    84             modelBuilder.Entity<UserDocuments>()
    85                 .HasOne(ab => ab.User)
    86                 .WithMany(a => a.Documents)
    87                 .HasForeignKey(ab => ab.UserId)
    88                 .OnDelete(DeleteBehavior.Cascade);
    89 
    90             modelBuilder.Entity<UserDocuments>()
    91                 .HasOne(ab => ab.Documents)
    92                 .WithMany(b => b.User)
    93                 .HasForeignKey(ab => ab.DocumentId)
    94                 .OnDelete(DeleteBehavior.Cascade);
    95 
    96             // -------------------------
    97             // Payment (user enrollment)
    98             // -------------------------
    99             modelBuilder.Entity<Payment>()
    100                 .HasKey(p => p.Id);
    101 
    102             modelBuilder.Entity<Payment>()
    103                 .HasOne(p => p.User)
    104                 .WithMany(u => u.EnrolledSemesters)
    105                 .HasForeignKey(p => p.UserId)
    106                 .OnDelete(DeleteBehavior.Cascade);
    107 
    108             modelBuilder.Entity<Payment>()
    109                 .HasOne(p => p.EnrolledSemesters)
    110                 .WithMany(es => es.Users)
    111                 .HasForeignKey(p => p.EnrollmentInfoId)
    112                 .OnDelete(DeleteBehavior.Cascade);
    113 
    114             // -------------------------
    115             // SemesterSubject (student enrollments and professor assignments)
    116             // -------------------------
    117             modelBuilder.Entity<SemesterSubject>()
    118                 .HasKey(ss => ss.Id); // or composite key if you prefer {UserId, EnrolledSemesterId, SubjectId}
    119 
    120             // Student enrollment
    121             modelBuilder.Entity<SemesterSubject>()
    122                 .HasOne(ss => ss.User)
    123                 .WithMany(u => u.EnrolledSemesterUserSubjects)
    124                 .HasForeignKey(ss => ss.UserId)
    125                 .OnDelete(DeleteBehavior.Restrict);
    126 
    127             // Professor teaching
    128             modelBuilder.Entity<SemesterSubject>()
    129                 .HasOne(ss => ss.Professor)
    130                 .WithMany(u => u.TeachingSubjects)
    131                 .HasForeignKey(ss => ss.ProfessorId)
    132                 .OnDelete(DeleteBehavior.Restrict);
    133 
    134             // Subject relation
    135             modelBuilder.Entity<SemesterSubject>()
    136                 .HasOne(ss => ss.Subject)
    137                 .WithMany(s => s.SemesterSubjects)
    138                 .HasForeignKey(ss => ss.SubjectId)
    139                 .OnDelete(DeleteBehavior.Restrict);
    140 
    141             // EnrolledSemester relation
    142             modelBuilder.Entity<SemesterSubject>()
    143                 .HasOne(ss => ss.EnrolledSemester)
    144                 .WithMany(es => es.SemesterSubjects)
    145                 .HasForeignKey(ss => ss.EnrolledSemesterId)
    146                 .OnDelete(DeleteBehavior.Restrict);
    147 
    148             // -------------------------
    149             // PassedSubject (one-to-one with SemesterSubject)
    150             // -------------------------
    151             modelBuilder.Entity<PassedSubject>()
    152                 .HasKey(ps => ps.Id);
    153 
    154             modelBuilder.Entity<PassedSubject>()
    155                 .HasOne(ps => ps.SemesterSubject)
    156                 .WithOne(ss => ss.PassedSubject)
    157                 .HasForeignKey<PassedSubject>(ps => ps.SemesterSubjectId)
    158                 .OnDelete(DeleteBehavior.Cascade);
    159 
    160             // -------------------------
    161             // ActiveSemesters to EnrolledSemesters (one-to-many)
    162             // -------------------------
    163             modelBuilder.Entity<EnrolledSemesters>()
    164                 .HasOne(es => es.Semester)
    165                 .WithMany(a => a.EnrolledSemesters)
    166                 .HasForeignKey(es => es.Id)
    167                 .OnDelete(DeleteBehavior.Restrict);
    168 
    169             // -------------------------
    170             // ProfessorSubjects (many-to-many: Professor -> Semester -> Subject)
    171             // -------------------------
    172             modelBuilder.Entity<ProfessorSubjects>()
    173                 .HasKey(ps => new { ps.ProfessorId, ps.SemesterId, ps.SubjectId });
    174 
    175             modelBuilder.Entity<ProfessorSubjects>()
    176                 .HasOne(ps => ps.Professor)
    177                 .WithMany()
    178                 .HasForeignKey(ps => ps.ProfessorId)
    179                 .OnDelete(DeleteBehavior.Cascade);
    180 
    181             modelBuilder.Entity<ProfessorSubjects>()
    182                 .HasOne(ps => ps.Semester)
    183                 .WithMany()
    184                 .HasForeignKey(ps => ps.SemesterId)
    185                 .OnDelete(DeleteBehavior.Cascade);
    186 
    187             modelBuilder.Entity<ProfessorSubjects>()
    188                 .HasOne(ps => ps.Subject)
    189                 .WithMany()
    190                 .HasForeignKey(ps => ps.SubjectId)
    191                 .OnDelete(DeleteBehavior.Cascade);
     43            // The enum types themselves are declared in ddl.sql; this tells EF
     44            // they exist so it does not try to treat the columns as text.
     45            modelBuilder.HasPostgresEnum<UserRole>(ProjectSchema, "user_role");
     46            modelBuilder.HasPostgresEnum<HighSchoolType>(ProjectSchema, "hs_type");
     47            modelBuilder.HasPostgresEnum<Quota>(ProjectSchema, "quota_type");
     48            modelBuilder.HasPostgresEnum<sType>(ProjectSchema, "semester_type");
     49            modelBuilder.HasPostgresEnum<Grade>(ProjectSchema, "grade_type");
     50
     51            // -------------------------
     52            // users
     53            // -------------------------
     54            modelBuilder.Entity<User>(e =>
     55            {
     56                e.ToTable("users", ProjectSchema);
     57                e.HasKey(u => u.Id);
     58                e.Property(u => u.Id).HasColumnName("id");
     59                e.Property(u => u.Name).HasColumnName("name");
     60                e.Property(u => u.EMBG).HasColumnName("embg");
     61                e.Property(u => u.Surname).HasColumnName("surname");
     62                e.Property(u => u.Index).HasColumnName("index");
     63                e.Property(u => u.Bday).HasColumnName("bday").HasColumnType("timestamp without time zone");
     64                e.Property(u => u.Email).HasColumnName("email");
     65                e.Property(u => u.PasswordHash).HasColumnName("password");
     66                e.Property(u => u.Role).HasColumnName("role");
     67                e.Property(u => u.Quota).HasColumnName("quota");
     68                e.Property(u => u.EnrollmentYear).HasColumnName("enrollment_year");
     69                e.Property(u => u.CreatedAt).HasColumnName("created_at").HasColumnType("timestamp without time zone");
     70                e.HasIndex(u => u.Email).IsUnique();
     71            });
     72
     73            // -------------------------
     74            // high_school
     75            // -------------------------
     76            modelBuilder.Entity<HighSchool>(e =>
     77            {
     78                e.ToTable("high_school", ProjectSchema);
     79                e.HasKey(h => h.Id);
     80                e.Property(h => h.Id).HasColumnName("id");
     81                e.Property(h => h.UserId).HasColumnName("user_id");
     82                e.Property(h => h.GPA).HasColumnName("gpa");
     83                e.Property(h => h.HighSchoolType).HasColumnName("type");
     84                e.HasOne(h => h.User)
     85                 .WithOne(u => u.HighSchool)
     86                 .HasForeignKey<HighSchool>(h => h.UserId)
     87                 .OnDelete(DeleteBehavior.Restrict);
     88            });
     89
     90            // -------------------------
     91            // contact
     92            // -------------------------
     93            modelBuilder.Entity<ContactInfo>(e =>
     94            {
     95                e.ToTable("contact", ProjectSchema);
     96                e.HasKey(c => c.Id);
     97                e.Property(c => c.Id).HasColumnName("id");
     98                e.Property(c => c.UserId).HasColumnName("user_id");
     99                e.Property(c => c.City).HasColumnName("city");
     100                e.Property(c => c.Municipality).HasColumnName("municipality");
     101                e.Property(c => c.Address).HasColumnName("address");
     102                e.Property(c => c.PhoneNumber).HasColumnName("number");
     103                e.Property(c => c.MicrosoftEmail).HasColumnName("microsoft_email");
     104                e.HasOne(c => c.User)
     105                 .WithOne(u => u.ContactInfo)
     106                 .HasForeignKey<ContactInfo>(c => c.UserId)
     107                 .OnDelete(DeleteBehavior.Restrict);
     108            });
     109
     110            // -------------------------
     111            // major
     112            // -------------------------
     113            modelBuilder.Entity<Major>(e =>
     114            {
     115                e.ToTable("major", ProjectSchema);
     116                e.HasKey(m => m.Id);
     117                e.Property(m => m.Id).HasColumnName("id");
     118                e.Property(m => m.Name).HasColumnName("name");
     119            });
     120
     121            // -------------------------
     122            // active_semesters
     123            // -------------------------
     124            modelBuilder.Entity<ActiveSemesters>(e =>
     125            {
     126                e.ToTable("active_semesters", ProjectSchema);
     127                e.HasKey(a => a.Id);
     128                e.Property(a => a.Id).HasColumnName("id");
     129                e.Property(a => a.Year).HasColumnName("year");
     130                e.Property(a => a.Type).HasColumnName("type");
     131            });
     132
     133            // -------------------------
     134            // subjects
     135            // -------------------------
     136            modelBuilder.Entity<Subject>(e =>
     137            {
     138                e.ToTable("subjects", ProjectSchema);
     139                e.HasKey(s => s.Id);
     140                e.Property(s => s.Id).HasColumnName("id");
     141                e.Property(s => s.Name).HasColumnName("name");
     142                e.Property(s => s.Code).HasColumnName("code");
     143                e.Property(s => s.AwardedCredits).HasColumnName("awarded_credits");
     144                e.Property(s => s.DependencyCredit).HasColumnName("dependency_credit");
     145            });
     146
     147            // -------------------------
     148            // enrolled_semesters
     149            // -------------------------
     150            modelBuilder.Entity<EnrolledSemesters>(e =>
     151            {
     152                e.ToTable("enrolled_semesters", ProjectSchema);
     153                e.HasKey(es => es.Id);
     154                e.Property(es => es.Id).HasColumnName("id");
     155                e.Property(es => es.UserId).HasColumnName("user_id");
     156                e.Property(es => es.QuotaType).HasColumnName("quota");
     157                e.Property(es => es.MajorId).HasColumnName("major_id");
     158                e.Property(es => es.Note).HasColumnName("note");
     159                e.Property(es => es.StudentComment).HasColumnName("student_comment");
     160                e.Property(es => es.CratedAt).HasColumnName("created_at").HasColumnType("timestamp without time zone");
     161                e.Property(es => es.LastChange).HasColumnName("last_change").HasColumnType("timestamp without time zone");
     162                e.Property(es => es.Verified).HasColumnName("completed").HasColumnType("timestamp without time zone");
     163                e.Property(es => es.SemesterId).HasColumnName("semester_id");
     164
     165                e.HasOne(es => es.User)
     166                 .WithMany(u => u.Enrolments)
     167                 .HasForeignKey(es => es.UserId)
     168                 .OnDelete(DeleteBehavior.Restrict);
     169
     170                // Note: this deliberately keys off SemesterId. An earlier version
     171                // pointed the foreign key at es.Id, which silently tied every
     172                // enrolment to the semester that happened to share its id.
     173                e.HasOne(es => es.Semester)
     174                 .WithMany(a => a.EnrolledSemesters)
     175                 .HasForeignKey(es => es.SemesterId)
     176                 .OnDelete(DeleteBehavior.Restrict);
     177
     178                e.HasOne(es => es.Major)
     179                 .WithMany()
     180                 .HasForeignKey(es => es.MajorId)
     181                 .OnDelete(DeleteBehavior.Restrict);
     182            });
     183
     184            // -------------------------
     185            // semesters_subjects
     186            // -------------------------
     187            modelBuilder.Entity<SemesterSubject>(e =>
     188            {
     189                e.ToTable("semesters_subjects", ProjectSchema);
     190                e.HasKey(ss => ss.Id);
     191                e.Property(ss => ss.Id).HasColumnName("id");
     192                e.Property(ss => ss.EnrolledSemesterId).HasColumnName("enrolled_semesters_id");
     193                e.Property(ss => ss.SubjectId).HasColumnName("subjects_id");
     194                e.Property(ss => ss.ProfessorId).HasColumnName("professor_id");
     195                e.Property(ss => ss.Signature).HasColumnName("signature");
     196
     197                e.HasOne(ss => ss.Professor)
     198                 .WithMany(u => u.TeachingSubjects)
     199                 .HasForeignKey(ss => ss.ProfessorId)
     200                 .OnDelete(DeleteBehavior.Restrict);
     201
     202                e.HasOne(ss => ss.Subject)
     203                 .WithMany(s => s.SemesterSubjects)
     204                 .HasForeignKey(ss => ss.SubjectId)
     205                 .OnDelete(DeleteBehavior.Restrict);
     206
     207                e.HasOne(ss => ss.EnrolledSemester)
     208                 .WithMany(es => es.SemesterSubjects)
     209                 .HasForeignKey(ss => ss.EnrolledSemesterId)
     210                 .OnDelete(DeleteBehavior.Restrict);
     211            });
     212
     213            // -------------------------
     214            // passed_subjects
     215            // -------------------------
     216            modelBuilder.Entity<PassedSubject>(e =>
     217            {
     218                e.ToTable("passed_subjects", ProjectSchema);
     219                e.HasKey(ps => ps.Id);
     220                e.Property(ps => ps.Id).HasColumnName("id");
     221                e.Property(ps => ps.SemesterSubjectId).HasColumnName("enrolled_id");
     222                e.Property(ps => ps.Grade).HasColumnName("grade");
     223                e.Property(ps => ps.DatePassed).HasColumnName("date_passed").HasColumnType("timestamp without time zone");
     224
     225                e.HasOne(ps => ps.SemesterSubject)
     226                 .WithOne(ss => ss.PassedSubject)
     227                 .HasForeignKey<PassedSubject>(ps => ps.SemesterSubjectId)
     228                 .OnDelete(DeleteBehavior.Cascade);
     229            });
     230
     231            // -------------------------
     232            // documents
     233            // -------------------------
     234            modelBuilder.Entity<Documents>(e =>
     235            {
     236                e.ToTable("documents", ProjectSchema);
     237                e.HasKey(d => d.Id);
     238                e.Property(d => d.Id).HasColumnName("id");
     239                e.Property(d => d.Name).HasColumnName("type");
     240                e.Property(d => d.Body).HasColumnName("body");
     241                e.Property(d => d.Cost).HasColumnName("cost");
     242            });
     243
     244            // -------------------------
     245            // user_documents
     246            // -------------------------
     247            modelBuilder.Entity<UserDocuments>(e =>
     248            {
     249                e.ToTable("user_documents", ProjectSchema);
     250                e.HasKey(ud => new { ud.UserId, ud.DocumentId });
     251                e.Property(ud => ud.UserId).HasColumnName("user_id");
     252                e.Property(ud => ud.DocumentId).HasColumnName("document_id");
     253
     254                e.HasOne(ud => ud.User)
     255                 .WithMany(u => u.Documents)
     256                 .HasForeignKey(ud => ud.UserId)
     257                 .OnDelete(DeleteBehavior.Cascade);
     258
     259                e.HasOne(ud => ud.Documents)
     260                 .WithMany(d => d.User)
     261                 .HasForeignKey(ud => ud.DocumentId)
     262                 .OnDelete(DeleteBehavior.Cascade);
     263            });
     264
     265            // -------------------------
     266            // token
     267            // -------------------------
     268            modelBuilder.Entity<RefreshToken>(e =>
     269            {
     270                e.ToTable("token", ProjectSchema);
     271                e.HasKey(t => t.Id);
     272                e.Property(t => t.Id).HasColumnName("id");
     273                e.Property(t => t.UserId).HasColumnName("user_id");
     274                e.Property(t => t.Token).HasColumnName("token");
     275                e.Property(t => t.ExpiresAt).HasColumnName("expires_at").HasColumnType("timestamp without time zone");
     276                e.Property(t => t.IsValid).HasColumnName("is_valid");
     277
     278                e.HasOne(t => t.User)
     279                 .WithMany()
     280                 .HasForeignKey(t => t.UserId)
     281                 .OnDelete(DeleteBehavior.Cascade);
     282            });
     283
     284            // -------------------------
     285            // payment
     286            // -------------------------
     287            modelBuilder.Entity<Payment>(e =>
     288            {
     289                e.ToTable("payment", ProjectSchema);
     290                e.HasKey(p => p.Id);
     291                e.Property(p => p.Id).HasColumnName("id");
     292                e.Property(p => p.UserId).HasColumnName("user_id");
     293                e.Property(p => p.EnrollmentInfoId).HasColumnName("enrollment_id");
     294                e.Property(p => p.Amount).HasColumnName("amount");
     295
     296                e.HasOne(p => p.User)
     297                 .WithMany(u => u.Payments)
     298                 .HasForeignKey(p => p.UserId)
     299                 .OnDelete(DeleteBehavior.Cascade);
     300
     301                e.HasOne(p => p.EnrolledSemesters)
     302                 .WithMany(es => es.Users)
     303                 .HasForeignKey(p => p.EnrollmentInfoId)
     304                 .OnDelete(DeleteBehavior.Cascade);
     305            });
     306
     307            // -------------------------
     308            // major_subjects
     309            // -------------------------
     310            modelBuilder.Entity<MajorSubjects>(e =>
     311            {
     312                e.ToTable("major_subjects", ProjectSchema);
     313                e.HasKey(ms => new { ms.MajorId, ms.SubjectId });
     314                e.Property(ms => ms.MajorId).HasColumnName("major_id");
     315                e.Property(ms => ms.SubjectId).HasColumnName("subject_id");
     316                e.Property(ms => ms.MandatorySemester).HasColumnName("mandatory_semester");
     317
     318                e.HasOne(ms => ms.Majors)
     319                 .WithMany(m => m.Subjects)
     320                 .HasForeignKey(ms => ms.MajorId)
     321                 .OnDelete(DeleteBehavior.Cascade);
     322
     323                e.HasOne(ms => ms.Subjects)
     324                 .WithMany(s => s.Majors)
     325                 .HasForeignKey(ms => ms.SubjectId)
     326                 .OnDelete(DeleteBehavior.Cascade);
     327            });
     328
     329            // -------------------------
     330            // dependency_subject
     331            // -------------------------
     332            modelBuilder.Entity<DependencySubject>(e =>
     333            {
     334                e.ToTable("dependency_subject", ProjectSchema);
     335                e.HasKey(ds => new { ds.SubjectId, ds.DependencyId });
     336                e.Property(ds => ds.SubjectId).HasColumnName("subject_id");
     337                e.Property(ds => ds.DependencyId).HasColumnName("dependency_id");
     338
     339                e.HasOne(ds => ds.Subject)
     340                 .WithMany(s => s.Dependencies)
     341                 .HasForeignKey(ds => ds.SubjectId)
     342                 .OnDelete(DeleteBehavior.Restrict);
     343
     344                e.HasOne(ds => ds.Dependency)
     345                 .WithMany(s => s.Dependents)
     346                 .HasForeignKey(ds => ds.DependencyId)
     347                 .OnDelete(DeleteBehavior.Restrict);
     348            });
     349
     350            // -------------------------
     351            // professour_subjects  (spelling matches the table in ddl.sql)
     352            // -------------------------
     353            modelBuilder.Entity<ProfessorSubjects>(e =>
     354            {
     355                e.ToTable("professour_subjects", ProjectSchema);
     356                e.HasKey(ps => new { ps.ProfessorId, ps.SemesterId, ps.SubjectId });
     357                e.Property(ps => ps.ProfessorId).HasColumnName("prof_id");
     358                e.Property(ps => ps.SemesterId).HasColumnName("active_semester_id");
     359                e.Property(ps => ps.SubjectId).HasColumnName("subject_id");
     360
     361                e.HasOne(ps => ps.Professor)
     362                 .WithMany()
     363                 .HasForeignKey(ps => ps.ProfessorId)
     364                 .OnDelete(DeleteBehavior.Cascade);
     365
     366                e.HasOne(ps => ps.Semester)
     367                 .WithMany()
     368                 .HasForeignKey(ps => ps.SemesterId)
     369                 .OnDelete(DeleteBehavior.Cascade);
     370
     371                e.HasOne(ps => ps.Subject)
     372                 .WithMany()
     373                 .HasForeignKey(ps => ps.SubjectId)
     374                 .OnDelete(DeleteBehavior.Cascade);
     375            });
    192376        }
    193 
    194377    }
    195378}
Note: See TracChangeset for help on using the changeset viewer.