Add the possibility to import a value from the environment into kconfig via the option syntax. Beside flexibility this has the advantage providing proper dependencies. Documented the options syntax.
Showing the changes to scripts (8 of 9 files). Show all
Unified · Split
| @@ -106,7 +106,8 @@ struct symbol { · 105 unmodified lines | ||
| 106 | 106 | #define SYMBOL_HASHMASK 0xff |
| 107 | 107 | |
| 108 | 108 | enum prop_type { |
| 109 | − P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE | |
| 109 | + P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, | |
| 110 | + P_SELECT, P_RANGE, P_ENV | |
| 110 | 111 | }; |
| 111 | 112 | |
| 112 | 113 | struct property { |
| @@ -44,6 +44,7 @@ extern "C" { · 43 unmodified lines | ||
| 44 | 44 | |
| 45 | 45 | #define T_OPT_MODULES 1 |
| 46 | 46 | #define T_OPT_DEFCONFIG_LIST 2 |
| 47 | +#define T_OPT_ENV 3 | |
| 47 | 48 | |
| 48 | 49 | struct kconf_id { |
| 49 | 50 | int name; |
| @@ -74,6 +75,7 @@ void kconfig_load(void); · 24 unmodified lines | ||
| 74 | 75 | |
| 75 | 76 | /* menu.c */ |
| 76 | 77 | void menu_init(void); |
| 78 | +void menu_warn(struct menu *menu, const char *fmt, ...); | |
| 77 | 79 | struct menu *menu_add_menu(void); |
| 78 | 80 | void menu_end_menu(void); |
| 79 | 81 | void menu_add_entry(struct symbol *sym); |
| @@ -103,6 +105,8 @@ void str_printf(struct gstr *gs, const char *fmt, ...); · 23 unmodified lines | ||
| 103 | 105 | const char *str_get(struct gstr *gs); |
| 104 | 106 | |
| 105 | 107 | /* symbol.c */ |
| 108 | +extern struct expr *sym_env_list; | |
| 109 | + | |
| 106 | 110 | void sym_init(void); |
| 107 | 111 | void sym_clear_all_valid(void); |
| 108 | 112 | void sym_set_all_changed(void); |
| @@ -110,6 +114,7 @@ void sym_set_changed(struct symbol *sym); · 1 unmodified line | ||
| 110 | 114 | struct symbol *sym_check_deps(struct symbol *sym); |
| 111 | 115 | struct property *prop_alloc(enum prop_type type, struct symbol *sym); |
| 112 | 116 | struct symbol *prop_get_symbol(struct property *prop); |
| 117 | +struct property *sym_get_env_prop(struct symbol *sym); | |
| 113 | 118 | |
| 114 | 119 | static inline tristate sym_get_tristate_value(struct symbol *sym) |
| 115 | 120 | { |
| @@ -15,7 +15,7 @@ static struct menu **last_entry_ptr; · 14 unmodified lines | ||
| 15 | 15 | struct file *file_list; |
| 16 | 16 | struct file *current_file; |
| 17 | 17 | |
| 18 | −static void menu_warn(struct menu *menu, const char *fmt, ...) | |
| 18 | +void menu_warn(struct menu *menu, const char *fmt, ...) | |
| 19 | 19 | { |
| 20 | 20 | va_list ap; |
| 21 | 21 | va_start(ap, fmt); |
| @@ -172,6 +172,9 @@ void menu_add_option(int token, char *arg) · 150 unmodified lines | ||
| 172 | 172 | else if (sym_defconfig_list != current_entry->sym) |
| 173 | 173 | zconf_error("trying to redefine defconfig symbol"); |
| 174 | 174 | break; |
| 175 | + case T_OPT_ENV: | |
| 176 | + prop_add_env(arg); | |
| 177 | + break; | |
| 175 | 178 | } |
| 176 | 179 | } |
| 177 | 180 | |
| @@ -1088,7 +1088,11 @@ QString ConfigInfoView::debug_info(struct symbol *sym) · 1087 unmodified lines | ||
| 1088 | 1088 | debug += "</a><br>"; |
| 1089 | 1089 | break; |
| 1090 | 1090 | case P_DEFAULT: |
| 1091 | − debug += "default: "; | |
| 1091 | + case P_SELECT: | |
| 1092 | + case P_RANGE: | |
| 1093 | + case P_ENV: | |
| 1094 | + debug += prop_get_type_name(prop->type); | |
| 1095 | + debug += ": "; | |
| 1092 | 1096 | expr_print(prop->expr, expr_print_help, &debug, E_NONE); |
| 1093 | 1097 | debug += "<br>"; |
| 1094 | 1098 | break; |
| @@ -1099,16 +1103,6 @@ QString ConfigInfoView::debug_info(struct symbol *sym) · 4 unmodified lines | ||
| 1099 | 1103 | debug += "<br>"; |
| 1100 | 1104 | } |
| 1101 | 1105 | break; |
| 1102 | − case P_SELECT: | |
| 1103 | − debug += "select: "; | |
| 1104 | − expr_print(prop->expr, expr_print_help, &debug, E_NONE); | |
| 1105 | − debug += "<br>"; | |
| 1106 | − break; | |
| 1107 | − case P_RANGE: | |
| 1108 | − debug += "range: "; | |
| 1109 | − expr_print(prop->expr, expr_print_help, &debug, E_NONE); | |
| 1110 | − debug += "<br>"; | |
| 1111 | − break; | |
| 1112 | 1106 | default: |
| 1113 | 1107 | debug += "unknown property: "; |
| 1114 | 1108 | debug += prop_get_type_name(prop->type); |
| @@ -34,6 +34,8 @@ struct symbol *sym_defconfig_list; · 33 unmodified lines | ||
| 34 | 34 | struct symbol *modules_sym; |
| 35 | 35 | tristate modules_val; |
| 36 | 36 | |
| 37 | +struct expr *sym_env_list; | |
| 38 | + | |
| 37 | 39 | void sym_add_default(struct symbol *sym, const char *def) |
| 38 | 40 | { |
| 39 | 41 | struct property *prop = prop_alloc(P_DEFAULT, sym); |
| @@ -117,6 +119,15 @@ struct property *sym_get_choice_prop(struct symbol *sym) · 77 unmodified lines | ||
| 117 | 119 | return NULL; |
| 118 | 120 | } |
| 119 | 121 | |
| 122 | +struct property *sym_get_env_prop(struct symbol *sym) | |
| 123 | +{ | |
| 124 | + struct property *prop; | |
| 125 | + | |
| 126 | + for_all_properties(sym, prop, P_ENV) | |
| 127 | + return prop; | |
| 128 | + return NULL; | |
| 129 | +} | |
| 130 | + | |
| 120 | 131 | struct property *sym_get_default_prop(struct symbol *sym) |
| 121 | 132 | { |
| 122 | 133 | struct property *prop; |
| @@ -346,6 +357,9 @@ void sym_calc_value(struct symbol *sym) · 223 unmodified lines | ||
| 346 | 357 | ; |
| 347 | 358 | } |
| 348 | 359 | |
| 360 | + if (sym->flags & SYMBOL_AUTO) | |
| 361 | + sym->flags &= ~SYMBOL_WRITE; | |
| 362 | + | |
| 349 | 363 | sym->curr = newval; |
| 350 | 364 | if (sym_is_choice(sym) && newval.tri == yes) |
| 351 | 365 | sym->curr.val = sym_calc_choice(sym); |
| @@ -860,6 +874,8 @@ const char *prop_get_type_name(enum prop_type type) · 508 unmodified lines | ||
| 860 | 874 | switch (type) { |
| 861 | 875 | case P_PROMPT: |
| 862 | 876 | return "prompt"; |
| 877 | + case P_ENV: | |
| 878 | + return "env"; | |
| 863 | 879 | case P_COMMENT: |
| 864 | 880 | return "comment"; |
| 865 | 881 | case P_MENU: |
| @@ -877,3 +893,32 @@ const char *prop_get_type_name(enum prop_type type) · 11 unmodified lines | ||
| 877 | 893 | } |
| 878 | 894 | return "unknown"; |
| 879 | 895 | } |
| 896 | + | |
| 897 | +void prop_add_env(const char *env) | |
| 898 | +{ | |
| 899 | + struct symbol *sym, *sym2; | |
| 900 | + struct property *prop; | |
| 901 | + char *p; | |
| 902 | + | |
| 903 | + sym = current_entry->sym; | |
| 904 | + sym->flags |= SYMBOL_AUTO; | |
| 905 | + for_all_properties(sym, prop, P_ENV) { | |
| 906 | + sym2 = prop_get_symbol(prop); | |
| 907 | + if (strcmp(sym2->name, env)) | |
| 908 | + menu_warn(current_entry, "redefining environment symbol from %s", | |
| 909 | + sym2->name); | |
| 910 | + return; | |
| 911 | + } | |
| 912 | + | |
| 913 | + prop = prop_alloc(P_ENV, sym); | |
| 914 | + prop->expr = expr_alloc_symbol(sym_lookup(env, 1)); | |
| 915 | + | |
| 916 | + sym_env_list = expr_alloc_one(E_LIST, sym_env_list); | |
| 917 | + sym_env_list->right.sym = sym; | |
| 918 | + | |
| 919 | + p = getenv(env); | |
| 920 | + if (p) | |
| 921 | + sym_add_default(sym, p); | |
| 922 | + else | |
| 923 | + menu_warn(current_entry, "environment variable %s undefined", env); | |
| 924 | +} | |
| @@ -29,6 +29,8 @@ struct file *file_lookup(const char *name) · 28 unmodified lines | ||
| 29 | 29 | /* write a dependency file as used by kbuild to track dependencies */ |
| 30 | 30 | int file_write_dep(const char *name) |
| 31 | 31 | { |
| 32 | + struct symbol *sym, *env_sym; | |
| 33 | + struct expr *e; | |
| 32 | 34 | struct file *file; |
| 33 | 35 | FILE *out; |
| 34 | 36 | |
| @@ -45,8 +47,25 @@ int file_write_dep(const char *name) · 10 unmodified lines | ||
| 45 | 47 | fprintf(out, "\t%s\n", file->name); |
| 46 | 48 | } |
| 47 | 49 | fprintf(out, "\ninclude/config/auto.conf: \\\n" |
| 48 | − "\t$(deps_config)\n\n" | |
| 49 | − "$(deps_config): ;\n"); | |
| 50 | + "\t$(deps_config)\n\n"); | |
| 51 | + | |
| 52 | + expr_list_for_each_sym(sym_env_list, e, sym) { | |
| 53 | + struct property *prop; | |
| 54 | + const char *value; | |
| 55 | + | |
| 56 | + prop = sym_get_env_prop(sym); | |
| 57 | + env_sym = prop_get_symbol(prop); | |
| 58 | + if (!env_sym) | |
| 59 | + continue; | |
| 60 | + value = getenv(env_sym->name); | |
| 61 | + if (!value) | |
| 62 | + value = ""; | |
| 63 | + fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); | |
| 64 | + fprintf(out, "include/config/auto.conf: FORCE\n"); | |
| 65 | + fprintf(out, "endif\n"); | |
| 66 | + } | |
| 67 | + | |
| 68 | + fprintf(out, "\n$(deps_config): ;\n"); | |
| 50 | 69 | fclose(out); |
| 51 | 70 | rename("..config.tmp", name); |
| 52 | 71 | return 0; |
| @@ -41,4 +41,5 @@ option, T_OPTION, TF_COMMAND · 40 unmodified lines | ||
| 41 | 41 | on, T_ON, TF_PARAM |
| 42 | 42 | modules, T_OPT_MODULES, TF_OPTION |
| 43 | 43 | defconfig_list, T_OPT_DEFCONFIG_LIST,TF_OPTION |
| 44 | +env, T_OPT_ENV, TF_OPTION | |
| 44 | 45 | %% |
| @@ -53,10 +53,10 @@ kconf_id_hash (register const char *str, register unsigned int len) · 52 unmodified lines | ||
| 53 | 53 | 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, |
| 54 | 54 | 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, |
| 55 | 55 | 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, |
| 56 | − 49, 49, 49, 49, 49, 49, 49, 18, 11, 5, | |
| 56 | + 49, 49, 49, 49, 49, 49, 49, 35, 35, 5, | |
| 57 | 57 | 0, 0, 5, 49, 5, 20, 49, 49, 5, 20, |
| 58 | − 5, 0, 30, 49, 0, 15, 0, 10, 49, 49, | |
| 59 | − 25, 49, 49, 49, 49, 49, 49, 49, 49, 49, | |
| 58 | + 5, 0, 30, 49, 0, 15, 0, 10, 0, 49, | |
| 59 | + 10, 49, 49, 49, 49, 49, 49, 49, 49, 49, | |
| 60 | 60 | 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, |
| 61 | 61 | 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, |
| 62 | 62 | 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, |
| @@ -89,6 +89,7 @@ kconf_id_hash (register const char *str, register unsigned int len) · 26 unmodified lines | ||
| 89 | 89 | struct kconf_id_strings_t |
| 90 | 90 | { |
| 91 | 91 | char kconf_id_strings_str2[sizeof("on")]; |
| 92 | + char kconf_id_strings_str3[sizeof("env")]; | |
| 92 | 93 | char kconf_id_strings_str5[sizeof("endif")]; |
| 93 | 94 | char kconf_id_strings_str6[sizeof("option")]; |
| 94 | 95 | char kconf_id_strings_str7[sizeof("endmenu")]; |
| @@ -99,30 +100,31 @@ struct kconf_id_strings_t · 4 unmodified lines | ||
| 99 | 100 | char kconf_id_strings_str12[sizeof("default")]; |
| 100 | 101 | char kconf_id_strings_str13[sizeof("def_bool")]; |
| 101 | 102 | char kconf_id_strings_str14[sizeof("help")]; |
| 102 | − char kconf_id_strings_str15[sizeof("bool")]; | |
| 103 | 103 | char kconf_id_strings_str16[sizeof("config")]; |
| 104 | 104 | char kconf_id_strings_str17[sizeof("def_tristate")]; |
| 105 | − char kconf_id_strings_str18[sizeof("boolean")]; | |
| 105 | + char kconf_id_strings_str18[sizeof("hex")]; | |
| 106 | 106 | char kconf_id_strings_str19[sizeof("defconfig_list")]; |
| 107 | 107 | char kconf_id_strings_str21[sizeof("string")]; |
| 108 | 108 | char kconf_id_strings_str22[sizeof("if")]; |
| 109 | 109 | char kconf_id_strings_str23[sizeof("int")]; |
| 110 | − char kconf_id_strings_str24[sizeof("enable")]; | |
| 111 | 110 | char kconf_id_strings_str26[sizeof("select")]; |
| 112 | 111 | char kconf_id_strings_str27[sizeof("modules")]; |
| 113 | 112 | char kconf_id_strings_str28[sizeof("tristate")]; |
| 114 | 113 | char kconf_id_strings_str29[sizeof("menu")]; |
| 115 | 114 | char kconf_id_strings_str31[sizeof("source")]; |
| 116 | 115 | char kconf_id_strings_str32[sizeof("comment")]; |
| 117 | − char kconf_id_strings_str33[sizeof("hex")]; | |
| 118 | 116 | char kconf_id_strings_str35[sizeof("menuconfig")]; |
| 119 | 117 | char kconf_id_strings_str36[sizeof("prompt")]; |
| 120 | 118 | char kconf_id_strings_str37[sizeof("depends")]; |
| 119 | + char kconf_id_strings_str39[sizeof("bool")]; | |
| 120 | + char kconf_id_strings_str41[sizeof("enable")]; | |
| 121 | + char kconf_id_strings_str42[sizeof("boolean")]; | |
| 121 | 122 | char kconf_id_strings_str48[sizeof("mainmenu")]; |
| 122 | 123 | }; |
| 123 | 124 | static struct kconf_id_strings_t kconf_id_strings_contents = |
| 124 | 125 | { |
| 125 | 126 | "on", |
| 127 | + "env", | |
| 126 | 128 | "endif", |
| 127 | 129 | "option", |
| 128 | 130 | "endmenu", |
| @@ -133,25 +135,25 @@ static struct kconf_id_strings_t kconf_id_strings_contents = · 4 unmodified lines | ||
| 133 | 135 | "default", |
| 134 | 136 | "def_bool", |
| 135 | 137 | "help", |
| 136 | − "bool", | |
| 137 | 138 | "config", |
| 138 | 139 | "def_tristate", |
| 139 | − "boolean", | |
| 140 | + "hex", | |
| 140 | 141 | "defconfig_list", |
| 141 | 142 | "string", |
| 142 | 143 | "if", |
| 143 | 144 | "int", |
| 144 | − "enable", | |
| 145 | 145 | "select", |
| 146 | 146 | "modules", |
| 147 | 147 | "tristate", |
| 148 | 148 | "menu", |
| 149 | 149 | "source", |
| 150 | 150 | "comment", |
| 151 | − "hex", | |
| 152 | 151 | "menuconfig", |
| 153 | 152 | "prompt", |
| 154 | 153 | "depends", |
| 154 | + "bool", | |
| 155 | + "enable", | |
| 156 | + "boolean", | |
| 155 | 157 | "mainmenu" |
| 156 | 158 | }; |
| 157 | 159 | #define kconf_id_strings ((const char *) &kconf_id_strings_contents) |
| @@ -163,7 +165,7 @@ kconf_id_lookup (register const char *str, register unsigned int len) · 5 unmodified lines | ||
| 163 | 165 | { |
| 164 | 166 | enum |
| 165 | 167 | { |
| 166 | − TOTAL_KEYWORDS = 31, | |
| 168 | + TOTAL_KEYWORDS = 32, | |
| 167 | 169 | MIN_WORD_LENGTH = 2, |
| 168 | 170 | MAX_WORD_LENGTH = 14, |
| 169 | 171 | MIN_HASH_VALUE = 2, |
| @@ -174,7 +176,8 @@ kconf_id_lookup (register const char *str, register unsigned int len) · 4 unmodified lines | ||
| 174 | 176 | { |
| 175 | 177 | {-1}, {-1}, |
| 176 | 178 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_ON, TF_PARAM}, |
| 177 | − {-1}, {-1}, | |
| 179 | + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_OPT_ENV, TF_OPTION}, | |
| 180 | + {-1}, | |
| 178 | 181 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, |
| 179 | 182 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str6, T_OPTION, TF_COMMAND}, |
| 180 | 183 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_ENDMENU, TF_COMMAND}, |
| @@ -185,17 +188,16 @@ kconf_id_lookup (register const char *str, register unsigned int len) · 4 unmodified lines | ||
| 185 | 188 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, |
| 186 | 189 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, |
| 187 | 190 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_HELP, TF_COMMAND}, |
| 188 | − {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str15, T_TYPE, TF_COMMAND, S_BOOLEAN}, | |
| 191 | + {-1}, | |
| 189 | 192 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str16, T_CONFIG, TF_COMMAND}, |
| 190 | 193 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_DEFAULT, TF_COMMAND, S_TRISTATE}, |
| 191 | − {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_BOOLEAN}, | |
| 194 | + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_TYPE, TF_COMMAND, S_HEX}, | |
| 192 | 195 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str19, T_OPT_DEFCONFIG_LIST,TF_OPTION}, |
| 193 | 196 | {-1}, |
| 194 | 197 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_TYPE, TF_COMMAND, S_STRING}, |
| 195 | 198 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_IF, TF_COMMAND|TF_PARAM}, |
| 196 | 199 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_TYPE, TF_COMMAND, S_INT}, |
| 197 | − {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str24, T_SELECT, TF_COMMAND}, | |
| 198 | − {-1}, | |
| 200 | + {-1}, {-1}, | |
| 199 | 201 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str26, T_SELECT, TF_COMMAND}, |
| 200 | 202 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, |
| 201 | 203 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_TYPE, TF_COMMAND, S_TRISTATE}, |
| @@ -203,13 +205,16 @@ kconf_id_lookup (register const char *str, register unsigned int len) · 1 unmodified line | ||
| 203 | 205 | {-1}, |
| 204 | 206 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SOURCE, TF_COMMAND}, |
| 205 | 207 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, |
| 206 | − {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_TYPE, TF_COMMAND, S_HEX}, | |
| 207 | − {-1}, | |
| 208 | + {-1}, {-1}, | |
| 208 | 209 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_MENUCONFIG, TF_COMMAND}, |
| 209 | 210 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_PROMPT, TF_COMMAND}, |
| 210 | 211 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str37, T_DEPENDS, TF_COMMAND}, |
| 211 | − {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, | |
| 212 | 212 | {-1}, |
| 213 | + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN}, | |
| 214 | + {-1}, | |
| 215 | + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SELECT, TF_COMMAND}, | |
| 216 | + {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_TYPE, TF_COMMAND, S_BOOLEAN}, | |
| 217 | + {-1}, {-1}, {-1}, {-1}, {-1}, | |
| 213 | 218 | {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str48, T_MAINMENU, TF_COMMAND} |
| 214 | 219 | }; |
| 215 | 220 | |