From a59f20f8669c7bdd21166e918bd74493e46c0400 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Mon, 19 Jun 2017 14:42:33 -0700 Subject: 3928 --- html/edit/002-typing.mu.html | 539 +++++++++++++------------- html/edit/004-programming-environment.mu.html | 6 +- html/edit/005-sandbox.mu.html | 4 +- html/edit/011-errors.mu.html | 2 +- 4 files changed, 276 insertions(+), 275 deletions(-) (limited to 'html') diff --git a/html/edit/002-typing.mu.html b/html/edit/002-typing.mu.html index 4e6a5441..f619f5a3 100644 --- a/html/edit/002-typing.mu.html +++ b/html/edit/002-typing.mu.html @@ -334,7 +334,7 @@ if ('onhashchange' in window) { 271 row:num, column:num <- render screen, editor 272 clear-line-until screen, right 273 row <- add row, 1 - 274 draw-horizontal screen, row, left, right, 9480/horizontal-dotted + 274 draw-horizontal screen, row, left, right, 9480/horizontal-dotted 275 row <- add row, 1 276 clear-screen-from screen, row, left, left, right 277 assert-no-scroll screen, old-top-idx @@ -937,275 +937,276 @@ if ('onhashchange' in window) { 874 left:num <- get *editor, left:offset 875 right:num <- get *editor, right:offset 876 screen-height:num <- screen-height screen - 877 at-start-of-wrapped-line?:bool <- at-start-of-wrapped-line? editor - 878 # insert newline - 879 insert 10/newline, before-cursor - 880 before-cursor <- next before-cursor - 881 *editor <- put *editor, before-cursor:offset, before-cursor - 882 { - 883 ¦ break-if at-start-of-wrapped-line? - 884 ¦ cursor-row <- add cursor-row, 1 - 885 ¦ *editor <- put *editor, cursor-row:offset, cursor-row - 886 } - 887 cursor-column <- copy left - 888 *editor <- put *editor, cursor-column:offset, cursor-column - 889 # maybe scroll - 890 { - 891 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height # must be equal, never greater - 892 ¦ break-unless below-screen? - 893 ¦ <scroll-down> - 894 ¦ cursor-row <- subtract cursor-row, 1 # bring back into screen range - 895 ¦ *editor <- put *editor, cursor-row:offset, cursor-row - 896 } - 897 # indent if necessary - 898 indent?:bool <- get *editor, indent?:offset - 899 return-unless indent? - 900 d:&:duplex-list:char <- get *editor, data:offset - 901 end-of-previous-line:&:duplex-list:char <- prev before-cursor - 902 indent:num <- line-indent end-of-previous-line, d - 903 i:num <- copy 0 - 904 { - 905 ¦ indent-done?:bool <- greater-or-equal i, indent - 906 ¦ break-if indent-done? - 907 ¦ insert-at-cursor editor, 32/space, screen - 908 ¦ i <- add i, 1 - 909 ¦ loop - 910 } - 911 ] - 912 - 913 def at-start-of-wrapped-line? editor:&:editor -> result:bool [ - 914 local-scope - 915 load-ingredients - 916 left:num <- get *editor, left:offset - 917 cursor-column:num <- get *editor, cursor-column:offset - 918 cursor-at-left?:bool <- equal cursor-column, left - 919 return-unless cursor-at-left?, 0/false - 920 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset - 921 before-before-cursor:&:duplex-list:char <- prev before-cursor - 922 return-unless before-before-cursor, 0/false # cursor is at start of editor - 923 char-before-cursor:char <- get *before-cursor, value:offset - 924 cursor-after-newline?:bool <- equal char-before-cursor, 10/newline - 925 return-if cursor-after-newline?, 0/false - 926 # if cursor is at left margin and not at start, but previous character is not a newline, - 927 # then we're at start of a wrapped line - 928 return 1/true - 929 ] - 930 - 931 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts - 932 # the number of spaces at the start of the line containing 'curr'. - 933 def line-indent curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [ - 934 local-scope - 935 load-ingredients - 936 result:num <- copy 0 - 937 return-unless curr - 938 at-start?:bool <- equal curr, start - 939 return-if at-start? - 940 { - 941 ¦ curr <- prev curr - 942 ¦ break-unless curr - 943 ¦ at-start?:bool <- equal curr, start - 944 ¦ break-if at-start? - 945 ¦ c:char <- get *curr, value:offset - 946 ¦ at-newline?:bool <- equal c, 10/newline - 947 ¦ break-if at-newline? - 948 ¦ # if c is a space, increment result - 949 ¦ is-space?:bool <- equal c, 32/space - 950 ¦ { - 951 ¦ ¦ break-unless is-space? - 952 ¦ ¦ result <- add result, 1 - 953 ¦ } - 954 ¦ # if c is not a space, reset result - 955 ¦ { - 956 ¦ ¦ break-if is-space? - 957 ¦ ¦ result <- copy 0 - 958 ¦ } - 959 ¦ loop - 960 } - 961 ] - 962 - 963 scenario editor-moves-cursor-down-after-inserting-newline-2 [ - 964 local-scope - 965 assume-screen 10/width, 5/height - 966 e:&:editor <- new-editor [abc], 1/left, 10/right - 967 assume-console [ - 968 ¦ type [0 - 969 1] - 970 ] - 971 run [ - 972 ¦ editor-event-loop screen, console, e - 973 ] - 974 screen-should-contain [ - 975 ¦ . . - 976 ¦ . 0 . - 977 ¦ . 1abc . - 978 ¦ . ╌╌╌╌╌╌╌╌╌. - 979 ¦ . . - 980 ] - 981 ] - 982 - 983 scenario editor-clears-previous-line-completely-after-inserting-newline [ - 984 local-scope - 985 assume-screen 10/width, 5/height - 986 e:&:editor <- new-editor [abcde], 0/left, 5/right - 987 editor-render screen, e - 988 screen-should-contain [ - 989 ¦ . . - 990 ¦ .abcd↩ . - 991 ¦ .e . - 992 ¦ .╌╌╌╌╌ . - 993 ¦ . . - 994 ] - 995 assume-console [ - 996 ¦ press enter - 997 ] - 998 run [ - 999 ¦ editor-event-loop screen, console, e -1000 ] -1001 # line should be fully cleared -1002 screen-should-contain [ -1003 ¦ . . + 877 # update cursor coordinates + 878 at-start-of-wrapped-line?:bool <- at-start-of-wrapped-line? editor + 879 { + 880 ¦ break-if at-start-of-wrapped-line? + 881 ¦ cursor-row <- add cursor-row, 1 + 882 ¦ *editor <- put *editor, cursor-row:offset, cursor-row + 883 } + 884 cursor-column <- copy left + 885 *editor <- put *editor, cursor-column:offset, cursor-column + 886 # maybe scroll + 887 { + 888 ¦ below-screen?:bool <- greater-or-equal cursor-row, screen-height # must be equal, never greater + 889 ¦ break-unless below-screen? + 890 ¦ <scroll-down> + 891 ¦ cursor-row <- subtract cursor-row, 1 # bring back into screen range + 892 ¦ *editor <- put *editor, cursor-row:offset, cursor-row + 893 } + 894 # insert newline + 895 insert 10/newline, before-cursor + 896 before-cursor <- next before-cursor + 897 *editor <- put *editor, before-cursor:offset, before-cursor + 898 # indent if necessary + 899 indent?:bool <- get *editor, indent?:offset + 900 return-unless indent? + 901 d:&:duplex-list:char <- get *editor, data:offset + 902 end-of-previous-line:&:duplex-list:char <- prev before-cursor + 903 indent:num <- line-indent end-of-previous-line, d + 904 i:num <- copy 0 + 905 { + 906 ¦ indent-done?:bool <- greater-or-equal i, indent + 907 ¦ break-if indent-done? + 908 ¦ insert-at-cursor editor, 32/space, screen + 909 ¦ i <- add i, 1 + 910 ¦ loop + 911 } + 912 ] + 913 + 914 def at-start-of-wrapped-line? editor:&:editor -> result:bool [ + 915 local-scope + 916 load-ingredients + 917 left:num <- get *editor, left:offset + 918 cursor-column:num <- get *editor, cursor-column:offset + 919 cursor-at-left?:bool <- equal cursor-column, left + 920 return-unless cursor-at-left?, 0/false + 921 before-cursor:&:duplex-list:char <- get *editor, before-cursor:offset + 922 before-before-cursor:&:duplex-list:char <- prev before-cursor + 923 return-unless before-before-cursor, 0/false # cursor is at start of editor + 924 char-before-cursor:char <- get *before-cursor, value:offset + 925 cursor-after-newline?:bool <- equal char-before-cursor, 10/newline + 926 return-if cursor-after-newline?, 0/false + 927 # if cursor is at left margin and not at start, but previous character is not a newline, + 928 # then we're at start of a wrapped line + 929 return 1/true + 930 ] + 931 + 932 # takes a pointer 'curr' into the doubly-linked list and its sentinel, counts + 933 # the number of spaces at the start of the line containing 'curr'. + 934 def line-indent curr:&:duplex-list:char, start:&:duplex-list:char -> result:num [ + 935 local-scope + 936 load-ingredients + 937 result:num <- copy 0 + 938 return-unless curr + 939 at-start?:bool <- equal curr, start + 940 return-if at-start? + 941 { + 942 ¦ curr <- prev curr + 943 ¦ break-unless curr + 944 ¦ at-start?:bool <- equal curr, start + 945 ¦ break-if at-start? + 946 ¦ c:char <- get *curr, value:offset + 947 ¦ at-newline?:bool <- equal c, 10/newline + 948 ¦ break-if at-newline? + 949 ¦ # if c is a space, increment result + 950 ¦ is-space?:bool <- equal c, 32/space + 951 ¦ { + 952 ¦ ¦ break-unless is-space? + 953 ¦ ¦ result <- add result, 1 + 954 ¦ } + 955 ¦ # if c is not a space, reset result + 956 ¦ { + 957 ¦ ¦ break-if is-space? + 958 ¦ ¦ result <- copy 0 + 959 ¦ } + 960 ¦ loop + 961 } + 962 ] + 963 + 964 scenario editor-moves-cursor-down-after-inserting-newline-2 [ + 965 local-scope + 966 assume-screen 10/width, 5/height + 967 e:&:editor <- new-editor [abc], 1/left, 10/right + 968 assume-console [ + 969 ¦ type [0 + 970 1] + 971 ] + 972 run [ + 973 ¦ editor-event-loop screen, console, e + 974 ] + 975 screen-should-contain [ + 976 ¦ . . + 977 ¦ . 0 . + 978 ¦ . 1abc . + 979 ¦ . ╌╌╌╌╌╌╌╌╌. + 980 ¦ . . + 981 ] + 982 ] + 983 + 984 scenario editor-clears-previous-line-completely-after-inserting-newline [ + 985 local-scope + 986 assume-screen 10/width, 5/height + 987 e:&:editor <- new-editor [abcde], 0/left, 5/right + 988 editor-render screen, e + 989 screen-should-contain [ + 990 ¦ . . + 991 ¦ .abcd↩ . + 992 ¦ .e . + 993 ¦ .╌╌╌╌╌ . + 994 ¦ . . + 995 ] + 996 assume-console [ + 997 ¦ press enter + 998 ] + 999 run [ +1000 ¦ editor-event-loop screen, console, e +1001 ] +1002 # line should be fully cleared +1003 screen-should-contain [ 1004 ¦ . . -1005 ¦ .abcd↩ . -1006 ¦ .e . -1007 ¦ .╌╌╌╌╌ . -1008 ] -1009 ] -1010 -1011 scenario editor-splits-wrapped-line-after-inserting-newline [ -1012 local-scope -1013 assume-screen 10/width, 5/height -1014 e:&:editor <- new-editor [abcdef], 0/left, 5/right -1015 editor-render screen, e -1016 screen-should-contain [ -1017 ¦ . . -1018 ¦ .abcd↩ . -1019 ¦ .ef . -1020 ¦ .╌╌╌╌╌ . -1021 ¦ . . -1022 ] -1023 assume-console [ -1024 ¦ left-click 2, 0 -1025 ¦ press enter -1026 ] -1027 run [ -1028 ¦ editor-event-loop screen, console, e -1029 ¦ 10:num/raw <- get *e, cursor-row:offset -1030 ¦ 11:num/raw <- get *e, cursor-column:offset -1031 ] -1032 screen-should-contain [ -1033 ¦ . . -1034 ¦ .abcd . -1035 ¦ .ef . -1036 ¦ .╌╌╌╌╌ . -1037 ] -1038 memory-should-contain [ -1039 ¦ 10 <- 2 # cursor-row -1040 ¦ 11 <- 0 # cursor-column -1041 ] -1042 ] -1043 -1044 scenario editor-inserts-indent-after-newline [ -1045 local-scope -1046 assume-screen 10/width, 10/height -1047 s:text <- new [ab -1048 cd -1049 ef] -1050 e:&:editor <- new-editor s, 0/left, 10/right -1051 # position cursor after 'cd' and hit 'newline' -1052 assume-console [ -1053 ¦ left-click 2, 8 -1054 ¦ type [ -1055 ] -1056 ] -1057 run [ -1058 ¦ editor-event-loop screen, console, e -1059 ¦ 3:num/raw <- get *e, cursor-row:offset -1060 ¦ 4:num/raw <- get *e, cursor-column:offset -1061 ] -1062 # cursor should be below start of previous line -1063 memory-should-contain [ -1064 ¦ 3 <- 3 # cursor row -1065 ¦ 4 <- 2 # cursor column (indented) -1066 ] -1067 ] -1068 -1069 scenario editor-skips-indent-around-paste [ -1070 local-scope -1071 assume-screen 10/width, 10/height -1072 s:text <- new [ab -1073 cd -1074 ef] -1075 e:&:editor <- new-editor s, 0/left, 10/right -1076 # position cursor after 'cd' and hit 'newline' surrounded by paste markers -1077 assume-console [ -1078 ¦ left-click 2, 8 -1079 ¦ press 65507 # start paste -1080 ¦ press enter -1081 ¦ press 65506 # end paste -1082 ] -1083 run [ -1084 ¦ editor-event-loop screen, console, e -1085 ¦ 3:num/raw <- get *e, cursor-row:offset -1086 ¦ 4:num/raw <- get *e, cursor-column:offset -1087 ] -1088 # cursor should be below start of previous line -1089 memory-should-contain [ -1090 ¦ 3 <- 3 # cursor row -1091 ¦ 4 <- 0 # cursor column (not indented) -1092 ] -1093 ] -1094 -1095 after <handle-special-key> [ -1096 { -1097 ¦ paste-start?:bool <- equal k, 65507/paste-start -1098 ¦ break-unless paste-start? -1099 ¦ *editor <- put *editor, indent?:offset, 0/false -1100 ¦ return 1/go-render -1101 } -1102 ] -1103 -1104 after <handle-special-key> [ -1105 { -1106 ¦ paste-end?:bool <- equal k, 65506/paste-end -1107 ¦ break-unless paste-end? -1108 ¦ *editor <- put *editor, indent?:offset, 1/true -1109 ¦ return 1/go-render -1110 } -1111 ] -1112 -1113 ## helpers -1114 -1115 def draw-horizontal screen:&:screen, row:num, x:num, right:num -> screen:&:screen [ -1116 local-scope -1117 load-ingredients -1118 height:num <- screen-height screen -1119 past-bottom?:bool <- greater-or-equal row, height -1120 return-if past-bottom? -1121 style:char, style-found?:bool <- next-ingredient -1122 { -1123 ¦ break-if style-found? -1124 ¦ style <- copy 9472/horizontal -1125 } -1126 color:num, color-found?:bool <- next-ingredient -1127 { -1128 ¦ # default color to white -1129 ¦ break-if color-found? -1130 ¦ color <- copy 245/grey -1131 } -1132 bg-color:num, bg-color-found?:bool <- next-ingredient -1133 { -1134 ¦ break-if bg-color-found? -1135 ¦ bg-color <- copy 0/black -1136 } -1137 screen <- move-cursor screen, row, x -1138 { -1139 ¦ continue?:bool <- lesser-or-equal x, right # right is inclusive, to match editor semantics -1140 ¦ break-unless continue? -1141 ¦ print screen, style, color, bg-color -1142 ¦ x <- add x, 1 -1143 ¦ loop -1144 } -1145 ] +1005 ¦ . . +1006 ¦ .abcd↩ . +1007 ¦ .e . +1008 ¦ .╌╌╌╌╌ . +1009 ] +1010 ] +1011 +1012 scenario editor-splits-wrapped-line-after-inserting-newline [ +1013 local-scope +1014 assume-screen 10/width, 5/height +1015 e:&:editor <- new-editor [abcdef], 0/left, 5/right +1016 editor-render screen, e +1017 screen-should-contain [ +1018 ¦ . . +1019 ¦ .abcd↩ . +1020 ¦ .ef . +1021 ¦ .╌╌╌╌╌ . +1022 ¦ . . +1023 ] +1024 assume-console [ +1025 ¦ left-click 2, 0 +1026 ¦ press enter +1027 ] +1028 run [ +1029 ¦ editor-event-loop screen, console, e +1030 ¦ 10:num/raw <- get *e, cursor-row:offset +1031 ¦ 11:num/raw <- get *e, cursor-column:offset +1032 ] +1033 screen-should-contain [ +1034 ¦ . . +1035 ¦ .abcd . +1036 ¦ .ef . +1037 ¦ .╌╌╌╌╌ . +1038 ] +1039 memory-should-contain [ +1040 ¦ 10 <- 2 # cursor-row +1041 ¦ 11 <- 0 # cursor-column +1042 ] +1043 ] +1044 +1045 scenario editor-inserts-indent-after-newline [ +1046 local-scope +1047 assume-screen 10/width, 10/height +1048 s:text <- new [ab +1049 cd +1050 ef] +1051 e:&:editor <- new-editor s, 0/left, 10/right +1052 # position cursor after 'cd' and hit 'newline' +1053 assume-console [ +1054 ¦ left-click 2, 8 +1055 ¦ type [ +1056 ] +1057 ] +1058 run [ +1059 ¦ editor-event-loop screen, console, e +1060 ¦ 3:num/raw <- get *e, cursor-row:offset +1061 ¦ 4:num/raw <- get *e, cursor-column:offset +1062 ] +1063 # cursor should be below start of previous line +1064 memory-should-contain [ +1065 ¦ 3 <- 3 # cursor row +1066 ¦ 4 <- 2 # cursor column (indented) +1067 ] +1068 ] +1069 +1070 scenario editor-skips-indent-around-paste [ +1071 local-scope +1072 assume-screen 10/width, 10/height +1073 s:text <- new [ab +1074 cd +1075 ef] +1076 e:&:editor <- new-editor s, 0/left, 10/right +1077 # position cursor after 'cd' and hit 'newline' surrounded by paste markers +1078 assume-console [ +1079 ¦ left-click 2, 8 +1080 ¦ press 65507 # start paste +1081 ¦ press enter +1082 ¦ press 65506 # end paste +1083 ] +1084 run [ +1085 ¦ editor-event-loop screen, console, e +1086 ¦ 3:num/raw <- get *e, cursor-row:offset +1087 ¦ 4:num/raw <- get *e, cursor-column:offset +1088 ] +1089 # cursor should be below start of previous line +1090 memory-should-contain [ +1091 ¦ 3 <- 3 # cursor row +1092 ¦ 4 <- 0 # cursor column (not indented) +1093 ] +1094 ] +1095 +1096 after <handle-special-key> [ +1097 { +1098 ¦ paste-start?:bool <- equal k, 65507/paste-start +1099 ¦ break-unless paste-start? +1100 ¦ *editor <- put *editor, indent?:offset, 0/false +1101 ¦ return 1/go-render +1102 } +1103 ] +1104 +1105 after <handle-special-key> [ +1106 { +1107 ¦ paste-end?:bool <- equal k, 65506/paste-end +1108 ¦ break-unless paste-end? +1109 ¦ *editor <- put *editor, indent?:offset, 1/true +1110 ¦ return 1/go-render +1111 } +1112 ] +1113 +1114 ## helpers +1115 +1116 def draw-horizontal screen:&:screen, row:num, x:num, right:num -> screen:&:screen [ +1117 local-scope +1118 load-ingredients +1119 height:num <- screen-height screen +1120 past-bottom?:bool <- greater-or-equal row, height +1121 return-if past-bottom? +1122 style:char, style-found?:bool <- next-ingredient +1123 { +1124 ¦ break-if style-found? +1125 ¦ style <- copy 9472/horizontal +1126 } +1127 color:num, color-found?:bool <- next-ingredient +1128 { +1129 ¦ # default color to white +1130 ¦ break-if color-found? +1131 ¦ color <- copy 245/grey +1132 } +1133 bg-color:num, bg-color-found?:bool <- next-ingredient +1134 { +1135 ¦ break-if bg-color-found? +1136 ¦ bg-color <- copy 0/black +1137 } +1138 screen <- move-cursor screen, row, x +1139 { +1140 ¦ continue?:bool <- lesser-or-equal x, right # right is inclusive, to match editor semantics +1141 ¦ break-unless continue? +1142 ¦ print screen, style, color, bg-color +1143 ¦ x <- add x, 1 +1144 ¦ loop +1145 } +1146 ] diff --git a/html/edit/004-programming-environment.mu.html b/html/edit/004-programming-environment.mu.html index 647bc264..bc510375 100644 --- a/html/edit/004-programming-environment.mu.html +++ b/html/edit/004-programming-environment.mu.html @@ -470,7 +470,7 @@ if ('onhashchange' in window) { 407 # top menu 408 trace 11, [app], [render top menu] 409 width:num <- screen-width screen -410 draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey +410 draw-horizontal screen, 0, 0/left, width, 32/space, 0/black, 238/grey 411 button-start:num <- subtract width, 20 412 button-on-screen?:bool <- greater-or-equal button-start, 0 413 assert button-on-screen?, [screen too narrow for menu] @@ -507,7 +507,7 @@ if ('onhashchange' in window) { 444 row <- add row, 1 445 <render-recipe-components-end> 446 # draw dotted line after recipes -447 draw-horizontal screen, row, left, right, 9480/horizontal-dotted +447 draw-horizontal screen, row, left, right, 9480/horizontal-dotted 448 row <- add row, 1 449 clear-screen-from screen, row, left, left, right 450 ] @@ -524,7 +524,7 @@ if ('onhashchange' in window) { 461 clear-line-until screen, right 462 row <- add row, 1 463 # draw solid line after code (you'll see why in later layers) -464 draw-horizontal screen, row, left, right +464 draw-horizontal screen, row, left, right 465 row <- add row, 1 466 clear-screen-from screen, row, left, left, right 467 ] diff --git a/html/edit/005-sandbox.mu.html b/html/edit/005-sandbox.mu.html index 8e6eed32..69953a33 100644 --- a/html/edit/005-sandbox.mu.html +++ b/html/edit/005-sandbox.mu.html @@ -324,7 +324,7 @@ if ('onhashchange' in window) { 261 ¦ row <- add row, 1 262 } 263 # render sandboxes - 264 draw-horizontal screen, row, left, right + 264 draw-horizontal screen, row, left, right 265 sandbox:&:sandbox <- get *env, sandbox:offset 266 row, screen <- render-sandboxes screen, sandbox, left, right, row, render-from 267 clear-rest-of-screen screen, row, left, right @@ -370,7 +370,7 @@ if ('onhashchange' in window) { 307 ¦ at-bottom?:bool <- greater-or-equal row, screen-height 308 ¦ return-if at-bottom? 309 ¦ # draw solid line after sandbox - 310 ¦ draw-horizontal screen, row, left, right + 310 ¦ draw-horizontal screen, row, left, right 311 } 312 # if hidden, reset row attributes 313 { diff --git a/html/edit/011-errors.mu.html b/html/edit/011-errors.mu.html index 82ed22d1..45781d13 100644 --- a/html/edit/011-errors.mu.html +++ b/html/edit/011-errors.mu.html @@ -96,7 +96,7 @@ if ('onhashchange' in window) { 33 ¦ row:num <- get *env, recipe-bottom:offset 34 ¦ row, screen <- render-text screen, recipe-errors, left, right, 1/red, row 35 ¦ # draw dotted line after recipes - 36 ¦ draw-horizontal screen, row, left, right, 9480/horizontal-dotted + 36 ¦ draw-horizontal screen, row, left, right, 9480/horizontal-dotted 37 ¦ row <- add row, 1 38 ¦ clear-screen-from screen, row, left, left, right 39 } -- cgit 1.4.1-2-gfad0