source: src/ASM/Util.ma @ 1061

Last change on this file since 1061 was 1061, checked in by mulligan, 8 years ago

more work, bug found, ridiculous map3 function with dep. types added

File size: 17.0 KB
Line 
1include "basics/list.ma".
2include "basics/types.ma".
3include "arithmetics/nat.ma".
4
5(* let's implement a daemon not used by automation *)
6inductive DAEMONXXX: Type[0] ≝ K1DAEMONXXX: DAEMONXXX | K2DAEMONXXX: DAEMONXXX.
7axiom IMPOSSIBLE: K1DAEMONXXX = K2DAEMONXXX.
8example daemon: False. generalize in match IMPOSSIBLE; #IMPOSSIBLE destruct(IMPOSSIBLE) qed.
9example not_implemented: False. cases daemon qed.
10
11notation > "hvbox('let' 〈ident x,ident y〉 ≝ t 'in' s)"
12 with precedence 10
13for @{ match $t with [ pair ${ident x} ${ident y} ⇒ $s ] }.
14
15let rec nth_safe
16  (elt_type: Type[0]) (index: nat) (the_list: list elt_type)
17  (proof: index < | the_list |)
18    on index ≝
19  match index return λs. s < | the_list | → elt_type with
20  [ O ⇒
21    match the_list return λt. 0 < | t | → elt_type with
22    [ nil        ⇒ λnil_absurd. ?
23    | cons hd tl ⇒ λcons_proof. hd
24    ]
25  | S index' ⇒
26    match the_list return λt. S index' < | t | → elt_type with
27    [ nil ⇒ λnil_absurd. ?
28    | cons hd tl ⇒
29      λcons_proof. nth_safe elt_type index' tl ?
30    ]
31  ] proof.
32  [ normalize in nil_absurd;
33    cases (not_le_Sn_O 0)
34    #ABSURD
35    elim (ABSURD nil_absurd)
36  | normalize in nil_absurd;
37    cases (not_le_Sn_O (S index'))
38    #ABSURD
39    elim (ABSURD nil_absurd)
40  | normalize in cons_proof
41    @le_S_S_to_le
42    assumption
43  ]
44qed.
45
46definition last_safe ≝
47  λelt_type: Type[0].
48  λthe_list: list elt_type.
49  λproof   : 0 < | the_list |.
50    nth_safe elt_type (|the_list| - 1) the_list ?.
51  normalize /2/
52qed.
53
54let rec reduce
55  (A: Type[0]) (left: list A) (right: list A) on left ≝
56  match left with
57  [ nil ⇒ 〈〈[ ], [ ]〉, 〈[ ], right〉〉
58  | cons hd tl ⇒
59    match right with
60    [ nil ⇒ 〈〈[ ], left〉, 〈[ ], [ ]〉〉
61    | cons hd' tl' ⇒
62      let 〈cleft, cright〉 ≝ reduce A tl tl' in
63      let 〈commonl, restl〉 ≝ cleft in
64      let 〈commonr, restr〉 ≝ cright in
65        〈〈hd :: commonl, restl〉, 〈hd' :: commonr, restr〉〉
66    ]
67  ].
68
69axiom reduce_strong:
70  ∀A: Type[0].
71  ∀left: list A.
72  ∀right: list A.
73    Σret: ((list A) × (list A)) × ((list A) × (list A)). | \fst (\fst ret) | = | \fst (\snd ret) |.
74
75(*
76let rec reduce_strong
77  (A: Type[0]) (left: list A) (right: list A) (prf: | left | = | right |) on left ≝
78  match left return λx. |x| = |right| → Σret: ((list A) × (list A)) × ((list A) × (list A)). | \fst (\fst ret) | = | \fst (\snd ret) | with
79  [ nil ⇒
80    match right return λy. | [ ] | = | y | → Σret: ((list A) × (list A)) × ((list A) × (list A)). | \fst (\fst ret) | = | \fst (\snd ret) | with
81    [ nil ⇒ λnil_nil_prf. ?
82    | cons hd tl ⇒ λnil_cons_absrd_prf. ?
83    ]
84  | cons hd tl ⇒
85    match right return λy. | hd::tl | = | y | → Σret: ((list A) × (list A)) × ((list A) × (list A)). | \fst (\fst ret) | = | \fst (\snd ret) | with
86    [ nil ⇒ λcons_nil_absrd_prf. ?
87    | cons hd' tl' ⇒ λcons_cons_prf.
88      let tail_call ≝ reduce_strong A tl tl' ? in ?
89    ]
90  ] prf.
91  [ 5: normalize in cons_cons_prf;
92       destruct(cons_cons_prf)
93       assumption
94  | 2: normalize in nil_cons_absrd_prf;
95       destruct(nil_cons_absrd_prf)
96  | 3: normalize in cons_nil_absrd_prf;
97       destruct(cons_nil_absrd_prf)
98  ]
99qed.
100*)   
101 
102axiom reduce_length:
103  ∀A: Type[0].
104  ∀left, right: list A.
105  ∀prf: | left | = | right |.
106    \fst (\fst (reduce A left right)) = \fst (\snd (reduce A left right)).
107   
108let rec map2_opt
109  (A: Type[0]) (B: Type[0]) (C: Type[0]) (f: A → B → C)
110  (left: list A) (right: list B) on left ≝
111  match left with
112  [ nil ⇒
113    match right with
114    [ nil ⇒ Some ? (nil C)
115    | _ ⇒ None ?
116    ]
117  | cons hd tl ⇒
118    match right with
119    [ nil ⇒ None ?
120    | cons hd' tl' ⇒
121      match map2_opt A B C f tl tl' with
122      [ None ⇒ None ?
123      | Some tail ⇒ Some ? (f hd hd' :: tail)
124      ]
125    ]
126  ].
127
128let rec map2
129  (A: Type[0]) (B: Type[0]) (C: Type[0]) (f: A → B → C)
130  (left: list A) (right: list B) (proof: | left | = | right |) on left ≝
131  match left return λx. | x | = | right | → list C with
132  [ nil ⇒
133    match right return λy. | [] | = | y | → list C with
134    [ nil ⇒ λnil_prf. nil C
135    | _ ⇒ λcons_absrd. ?
136    ]
137  | cons hd tl ⇒
138    match right return λy. | hd::tl | = | y | → list C with
139    [ nil ⇒ λnil_absrd. ?
140    | cons hd' tl' ⇒ λcons_prf. (f hd hd') :: map2 A B C f tl tl' ?
141    ]
142  ] proof.
143  [1: normalize in cons_absrd;
144      destruct(cons_absrd)
145  |2: normalize in nil_absrd;
146      destruct(nil_absrd)
147  |3: normalize in cons_prf;
148      destruct(cons_prf)
149      assumption
150  ]
151qed.
152
153let rec map3
154  (A: Type[0]) (B: Type[0]) (C: Type[0]) (D: Type[0]) (f: A → B → C → D)
155  (left: list A) (centre: list B) (right: list C)
156  (prflc: |left| = |centre|) (prfcr: |centre| = |right|) on left ≝
157  match left return λx. |x| = |centre| → list D with
158  [ nil ⇒ λnil_prf.
159    match centre return λx. |x| = |right| → list D with
160    [ nil ⇒ λnil_nil_prf.
161      match right return λx. |nil ?| = |x| → list D with
162      [ nil        ⇒ λnil_nil_nil_prf. nil D
163      | cons hd tl ⇒ λcons_nil_nil_absrd. ?
164      ] nil_nil_prf
165    | cons hd tl ⇒ λnil_cons_absrd. ?
166    ] prfcr
167  | cons hd tl ⇒ λcons_prf.
168    match centre return λx. |x| = |right| → list D with
169    [ nil ⇒ λcons_nil_absrd. ?
170    | cons hd' tl' ⇒ λcons_cons_prf.
171      match right return λx. |right| = |x| → |cons ? hd' tl'| = |x| → list D with
172      [ nil ⇒ λrefl_prf. λcons_cons_nil_absrd. ?
173      | cons hd'' tl'' ⇒ λrefl_prf. λcons_cons_cons_prf.
174        (f hd hd' hd'') :: (map3 A B C D f tl tl' tl'' ? ?)
175      ] (refl ? (|right|)) cons_cons_prf
176    ] prfcr
177  ] prflc.
178  [ 1: normalize in cons_nil_nil_absrd;
179       destruct(cons_nil_nil_absrd)
180  | 2: generalize in match nil_cons_absrd;
181       <prfcr <nil_prf #HYP
182       normalize in HYP;
183       destruct(HYP)
184  | 3: generalize in match cons_nil_absrd;
185       <prfcr <cons_prf #HYP
186       normalize in HYP;
187       destruct(HYP)
188  | 4: normalize in cons_cons_nil_absrd;
189       destruct(cons_cons_nil_absrd)
190  | 5: normalize in cons_cons_cons_prf;
191       destruct(cons_cons_cons_prf)
192       assumption
193  | 6: generalize in match cons_cons_cons_prf;
194       <refl_prf <prfcr <cons_prf #HYP
195       normalize in HYP;
196       destruct(HYP)
197       @sym_eq assumption
198  ]
199qed.
200 
201lemma eq_rect_Type0_r :
202  ∀A: Type[0].
203  ∀a:A.
204  ∀P: ∀x:A. eq ? x a → Type[0]. P a (refl A a) → ∀x: A.∀p:eq ? x a. P x p.
205  #A #a #P #H #x #p
206  generalize in match H
207  generalize in match P
208  cases p
209  //
210qed.
211 
212let rec safe_nth (A: Type[0]) (n: nat) (l: list A) (p: n < length A l) on n: A ≝
213  match n return λo. o < length A l → A with
214  [ O ⇒
215    match l return λm. 0 < length A m → A with
216    [ nil ⇒ λabsd1. ?
217    | cons hd tl ⇒ λprf1. hd
218    ]
219  | S n' ⇒
220    match l return λm. S n' < length A m → A with
221    [ nil ⇒ λabsd2. ?
222    | cons hd tl ⇒ λprf2. safe_nth A n' tl ?
223    ]
224  ] ?.
225  [ 1:
226    @ p
227  | 4:
228    normalize in prf2
229    normalize
230    @ le_S_S_to_le
231    assumption
232  | 2:
233    normalize in absd1;
234    cases (not_le_Sn_O O)
235    # H
236    elim (H absd1)
237  | 3:
238    normalize in absd2;
239    cases (not_le_Sn_O (S n'))
240    # H
241    elim (H absd2)
242  ]
243qed.
244 
245let rec nub_by_internal (A: Type[0]) (f: A → A → bool) (l: list A) (n: nat) on n ≝
246  match n with
247  [ O ⇒
248    match l with
249    [ nil ⇒ [ ]
250    | cons hd tl ⇒ l
251    ]
252  | S n ⇒
253    match l with
254    [ nil ⇒ [ ]
255    | cons hd tl ⇒
256      hd :: nub_by_internal A f (filter ? (λy. notb (f y hd)) tl) n
257    ]
258  ].
259 
260definition nub_by ≝
261  λA: Type[0].
262  λf: A → A → bool.
263  λl: list A.
264    nub_by_internal A f l (length ? l).
265 
266let rec member (A: Type[0]) (eq: A → A → bool) (a: A) (l: list A) on l ≝
267  match l with
268  [ nil ⇒ false
269  | cons hd tl ⇒ orb (eq a hd) (member A eq a tl)
270  ].
271 
272let rec take (A: Type[0]) (n: nat) (l: list A) on n: list A ≝
273  match n with
274  [ O ⇒ [ ]
275  | S n ⇒
276    match l with
277    [ nil ⇒ [ ]
278    | cons hd tl ⇒ hd :: take A n tl
279    ]
280  ].
281 
282let rec drop (A: Type[0]) (n: nat) (l: list A) on n ≝
283  match n with
284  [ O ⇒ l
285  | S n ⇒
286    match l with
287    [ nil ⇒ [ ]
288    | cons hd tl ⇒ drop A n tl
289    ]
290  ].
291 
292definition list_split ≝
293  λA: Type[0].
294  λn: nat.
295  λl: list A.
296    〈take A n l, drop A n l〉.
297 
298let rec mapi_internal (A: Type[0]) (B: Type[0]) (n: nat) (f: nat → A → B)
299                      (l: list A) on l: list B ≝
300  match l with
301  [ nil ⇒ nil ?
302  | cons hd tl ⇒ (f n hd) :: (mapi_internal A B (n + 1) f tl)
303  ]. 
304
305definition mapi ≝
306  λA, B: Type[0].
307  λf: nat → A → B.
308  λl: list A.
309    mapi_internal A B 0 f l.
310
311let rec zip (A: Type[0]) (B: Type[0]) (l: list A) (r: list B) on l: option (list (A × B)) ≝
312  match l with
313  [ nil ⇒ Some ? (nil (A × B))
314  | cons hd tl ⇒
315    match r with
316    [ nil ⇒ None ?
317    | cons hd' tl' ⇒
318      match zip ? ? tl tl' with
319      [ None ⇒ None ?
320      | Some tail ⇒ Some ? (〈hd, hd'〉 :: tail)
321      ]
322    ]
323  ].
324
325let rec foldl (A: Type[0]) (B: Type[0]) (f: A → B → A) (a: A) (l: list B) on l ≝
326  match l with
327  [ nil ⇒ a
328  | cons hd tl ⇒ foldl A B f (f a hd) tl
329  ].
330
331lemma foldl_step:
332 ∀A:Type[0].
333  ∀B: Type[0].
334   ∀H: A → B → A.
335    ∀acc: A.
336     ∀pre: list B.
337      ∀hd:B.
338       foldl A B H acc (pre@[hd]) = (H (foldl A B H acc pre) hd).
339 #A #B #H #acc #pre generalize in match acc; -acc; elim pre
340  [ normalize; //
341  | #hd #tl #IH #acc #X normalize; @IH ]
342qed.
343
344lemma foldl_append:
345 ∀A:Type[0].
346  ∀B: Type[0].
347   ∀H: A → B → A.
348    ∀acc: A.
349     ∀suff,pre: list B.
350      foldl A B H acc (pre@suff) = (foldl A B H (foldl A B H acc pre) suff).
351 #A #B #H #acc #suff elim suff
352  [ #pre >append_nil %
353  | #hd #tl #IH #pre whd in ⊢ (???%) <(foldl_step … H ??) applyS (IH (pre@[hd])) ]
354qed.
355
356definition flatten ≝
357  λA: Type[0].
358  λl: list (list A).
359    foldr ? ? (append ?) [ ] l.
360
361let rec rev (A: Type[0]) (l: list A) on l ≝
362  match l with
363  [ nil ⇒ nil A
364  | cons hd tl ⇒ (rev A tl) @ [ hd ]
365  ].
366   
367notation > "'if' term 19 e 'then' term 19 t 'else' term 48 f" non associative with precedence 19
368 for @{ match $e in bool with [ true ⇒ $t | false ⇒ $f]  }.
369notation < "hvbox('if' \nbsp term 19 e \nbsp break 'then' \nbsp term 19 t \nbsp break 'else' \nbsp term 48 f \nbsp)" non associative with precedence 19
370 for @{ match $e with [ true ⇒ $t | false ⇒ $f]  }.
371
372let rec fold_left_i_aux (A: Type[0]) (B: Type[0])
373                        (f: nat → A → B → A) (x: A) (i: nat) (l: list B) on l ≝
374  match l with
375    [ nil ⇒ x
376    | cons hd tl ⇒ fold_left_i_aux A B f (f i x hd) (S i) tl
377    ].
378
379definition fold_left_i ≝ λA,B,f,x. fold_left_i_aux A B f x O.
380
381notation "hvbox(t⌈o ↦ h⌉)"
382  with precedence 45
383  for @{ match (? : $o=$h) with [ refl ⇒ $t ] }.
384
385definition function_apply ≝
386  λA, B: Type[0].
387  λf: A → B.
388  λa: A.
389    f a.
390   
391notation "f break $ x"
392  left associative with precedence 99
393  for @{ 'function_apply $f $x }.
394 
395interpretation "Function application" 'function_apply f x = (function_apply ? ? f x).
396
397let rec iterate (A: Type[0]) (f: A → A) (a: A) (n: nat) on n ≝
398  match n with
399    [ O ⇒ a
400    | S o ⇒ f (iterate A f a o)
401    ].
402
403(* Yeah, I probably ought to do something more general... *)
404notation "hvbox(\langle term 19 a, break term 19 b, break term 19 c\rangle)"
405with precedence 90 for @{ 'triple $a $b $c}.
406interpretation "Triple construction" 'triple x y z = (pair ? ? (pair ? ? x y) z).
407
408notation "hvbox(\langle term 19 a, break term 19 b, break term 19 c, break term 19 d\rangle)"
409with precedence 90 for @{ 'quadruple $a $b $c $d}.
410interpretation "Quadruple construction" 'quadruple w x y z = (pair ? ? (pair ? ? w x) (pair ? ? y z)).
411
412notation > "hvbox('let' 〈ident w,ident x,ident y,ident z〉 ≝ t 'in' s)"
413 with precedence 10
414for @{ match $t with [ pair ${fresh wx} ${fresh yz} ⇒ match ${fresh wx} with [ pair ${ident w} ${ident x} ⇒ match ${fresh yz} with [ pair ${ident y} ${ident z} ⇒ $s ] ] ] }.
415
416notation > "hvbox('let' 〈ident x,ident y,ident z〉 ≝ t 'in' s)"
417 with precedence 10
418for @{ match $t with [ pair ${fresh xy} ${ident z} ⇒ match ${fresh xy} with [ pair ${ident x} ${ident y} ⇒ $s ] ] }.
419
420notation < "hvbox('let' \nbsp hvbox(〈ident x,ident y〉\nbsp ≝ break t \nbsp 'in' \nbsp) break s)"
421 with precedence 10
422for @{ match $t with [ pair (${ident x}:$ignore) (${ident y}:$ignora) ⇒ $s ] }.
423
424axiom pair_elim':
425  ∀A,B,C: Type[0].
426  ∀T: A → B → C.
427  ∀p.
428  ∀P: A×B → C → Prop.
429    (∀lft, rgt. p = 〈lft,rgt〉 → P 〈lft,rgt〉 (T lft rgt)) →
430      P p (let 〈lft, rgt〉 ≝ p in T lft rgt).
431
432axiom pair_elim'':
433  ∀A,B,C,C': Type[0].
434  ∀T: A → B → C.
435  ∀T': A → B → C'.
436  ∀p.
437  ∀P: A×B → C → C' → Prop.
438    (∀lft, rgt. p = 〈lft,rgt〉 → P 〈lft,rgt〉 (T lft rgt) (T' lft rgt)) →
439      P p (let 〈lft, rgt〉 ≝ p in T lft rgt) (let 〈lft, rgt〉 ≝ p in T' lft rgt).
440
441lemma pair_destruct_1:
442 ∀A,B.∀a:A.∀b:B.∀c. 〈a,b〉 = c → a = \fst c.
443 #A #B #a #b *; /2/
444qed.
445
446lemma pair_destruct_2:
447 ∀A,B.∀a:A.∀b:B.∀c. 〈a,b〉 = c → b = \snd c.
448 #A #B #a #b *; /2/
449qed.
450
451
452notation "⊥" with precedence 90
453  for @{ match ? in False with [ ] }.
454
455let rec exclusive_disjunction (b: bool) (c: bool) on b ≝
456  match b with
457    [ true ⇒
458      match c with
459        [ false ⇒ true
460        | true ⇒ false
461        ]
462    | false ⇒
463      match c with
464        [ false ⇒ false
465        | true ⇒ true
466        ]
467    ].
468   
469definition ltb ≝
470  λm, n: nat.
471    leb (S m) n.
472   
473definition geb ≝
474  λm, n: nat.
475    ltb n m.
476
477definition gtb ≝
478  λm, n: nat.
479    leb n m.
480   
481(* dpm: unless I'm being stupid, this isn't defined in the stdlib? *)
482let rec eq_nat (n: nat) (m: nat) on n: bool ≝
483  match n with
484  [ O ⇒ match m with [ O ⇒ true | _ ⇒ false ]
485  | S n' ⇒ match m with [ S m' ⇒ eq_nat n' m' | _ ⇒ false ]
486  ].
487
488(* dpm: conflicts with library definitions
489interpretation "Nat less than" 'lt m n = (ltb m n).
490interpretation "Nat greater than" 'gt m n = (gtb m n).
491interpretation "Nat greater than eq" 'geq m n = (geb m n).
492*)
493
494let rec division_aux (m: nat) (n : nat) (p: nat) ≝
495  match ltb n (S p) with
496    [ true ⇒ O
497    | false ⇒
498      match m with
499        [ O ⇒ O
500        | (S q) ⇒ S (division_aux q (n - (S p)) p)
501        ]
502    ].
503   
504definition division ≝
505  λm, n: nat.
506    match n with
507      [ O ⇒ S m
508      | S o ⇒ division_aux m m o
509      ].
510     
511notation "hvbox(n break ÷ m)"
512  right associative with precedence 47
513  for @{ 'division $n $m }.
514 
515interpretation "Nat division" 'division n m = (division n m).
516
517let rec modulus_aux (m: nat) (n: nat) (p: nat) ≝
518  match leb n p with
519    [ true ⇒ n
520    | false ⇒
521      match m with
522        [ O ⇒ n
523        | S o ⇒ modulus_aux o (n - (S p)) p
524        ]
525    ].
526   
527definition modulus ≝
528  λm, n: nat.
529    match n with
530      [ O ⇒ m
531      | S o ⇒ modulus_aux m m o
532      ].
533   
534notation "hvbox(n break 'mod' m)"
535  right associative with precedence 47
536  for @{ 'modulus $n $m }.
537 
538interpretation "Nat modulus" 'modulus m n = (modulus m n).
539
540definition divide_with_remainder ≝
541  λm, n: nat.
542    pair ? ? (m ÷ n) (modulus m n).
543   
544let rec exponential (m: nat) (n: nat) on n ≝
545  match n with
546    [ O ⇒ S O
547    | S o ⇒ m * exponential m o
548    ].
549
550interpretation "Nat exponential" 'exp n m = (exponential n m).
551   
552notation "hvbox(a break ⊎ b)"
553 left associative with precedence 50
554for @{ 'disjoint_union $a $b }.
555interpretation "sum" 'disjoint_union A B = (Sum A B).
556
557theorem less_than_or_equal_monotone:
558  ∀m, n: nat.
559    m ≤ n → (S m) ≤ (S n).
560 #m #n #H
561 elim H
562 /2/
563qed.
564
565theorem less_than_or_equal_b_complete:
566  ∀m, n: nat.
567    leb m n = false → ¬(m ≤ n).
568 #m;
569 elim m;
570 normalize
571 [ #n #H
572   destruct
573 | #y #H1 #z
574   cases z
575   normalize
576   [ #H
577     /2/
578   | /3/
579   ]
580 ]
581qed.
582
583theorem less_than_or_equal_b_correct:
584  ∀m, n: nat.
585    leb m n = true → m ≤ n.
586 #m
587 elim m
588 //
589 #y #H1 #z
590 cases z
591 normalize
592 [ #H
593   destruct
594 | #n #H lapply (H1 … H) /2/
595 ]
596qed.
597
598definition less_than_or_equal_b_elim:
599 ∀m, n: nat.
600 ∀P: bool → Type[0].
601   (m ≤ n → P true) → (¬(m ≤ n) → P false) → P (leb m n).
602 #m #n #P #H1 #H2;
603 lapply (less_than_or_equal_b_correct m n)
604 lapply (less_than_or_equal_b_complete m n)
605 cases (leb m n)
606 /3/
607qed.
608
609lemma inclusive_disjunction_true:
610  ∀b, c: bool.
611    (orb b c) = true → b = true ∨ c = true.
612  # b
613  # c
614  elim b
615  [ normalize
616    # H
617    @ or_introl
618    %
619  | normalize
620    /2/
621  ]
622qed.
623
624lemma conjunction_true:
625  ∀b, c: bool.
626    andb b c = true → b = true ∧ c = true.
627  # b
628  # c
629  elim b
630  normalize
631  [ /2/
632  | # K
633    destruct
634  ]
635qed.
636
637lemma eq_true_false: false=true → False.
638 # K
639 destruct
640qed.
641
642lemma inclusive_disjunction_b_true: ∀b. orb b true = true.
643 # b
644 cases b
645 %
646qed.
647
648definition bool_to_Prop ≝
649 λb. match b with [ true ⇒ True | false ⇒ False ].
650
651coercion bool_to_Prop: ∀b:bool. Prop ≝ bool_to_Prop on _b:bool to Type[0].
652
653lemma eq_false_to_notb: ∀b. b = false → ¬ b.
654 *; /2/
655qed.
656
657lemma length_append:
658 ∀A.∀l1,l2:list A.
659  |l1 @ l2| = |l1| + |l2|.
660 #A #l1 elim l1
661  [ //
662  | #hd #tl #IH #l2 normalize <IH //]
663qed.
Note: See TracBrowser for help on using the repository browser.