6d618ef70e5abfc5e18656ba8064ead0c8974386
- Author
- Andrew Janke <andrew@apjanke.net>
- Committer
- Andrew Janke <andrew@apjanke.net>
- Date
Message
Diff
This diff is truncated to protect this page.
1diff --git a/plugins/emoji/README.md b/plugins/emoji/README.md
2new file mode 100644
3index 0000000000000000000000000000000000000000..889e567e6ce8e3689fa57a517fd74ab8bc8732e6
4--- /dev/null
5+++ b/plugins/emoji/README.md
6@@ -0,0 +1,135 @@
7+# emoji plugin
8+
9+Support for conveniently working with Unicode emoji in Zsh.
10+
11+## Features
12+
13diff --git a/plugins/emoji/emoji-char-definitions.zsh b/plugins/emoji/emoji-char-definitions.zsh
14new file mode 100644
15index 0000000000000000000000000000000000000000..7d110603ceb4d7b579acaf8f12f4cea3e2b05833
16--- /dev/null
17+++ b/plugins/emoji/emoji-char-definitions.zsh
18@@ -0,0 +1,1294 @@
19+
20+# emoji-char-definitions.zsh - Emoji character definitions for oh-my-zsh emoji plugin
21+#
22+# This file is auto-generated by update_emoji.pl. Do not edit it manually.
23+#
24+# This contains the definition for:
25+# $emoji - which maps character names to Unicode characters
26+# $emoji_flags - maps country names to Unicode flag characters using region indicators
27+
28+typeset -gAH emoji
29+typeset -gAH emoji_flags
30+
31+emoji[copyright_sign]=$'\U00A9'
32+emoji[registered_sign]=$'\U00AE'
33+emoji[double_exclamation_mark]=$'\U203C'
34+emoji[exclamation_question_mark]=$'\U2049'
35+emoji[trade_mark_sign]=$'\U2122'
36+emoji[information_source]=$'\U2139'
37+emoji[left_right_arrow]=$'\U2194'
38+emoji[up_down_arrow]=$'\U2195'
39+emoji[north_west_arrow]=$'\U2196'
40+emoji[north_east_arrow]=$'\U2197'
41+emoji[south_east_arrow]=$'\U2198'
42+emoji[south_west_arrow]=$'\U2199'
43+emoji[leftwards_arrow_with_hook]=$'\U21A9'
44+emoji[rightwards_arrow_with_hook]=$'\U21AA'
45+emoji[watch]=$'\U231A'
46+emoji[hourglass]=$'\U231B'
47+emoji[keyboard]=$'\U2328'
48+emoji[eject_symbol]=$'\U23CF'
49+emoji[black_right_pointing_double_triangle]=$'\U23E9'
50+emoji[black_left_pointing_double_triangle]=$'\U23EA'
51+emoji[black_up_pointing_double_triangle]=$'\U23EB'
52+emoji[black_down_pointing_double_triangle]=$'\U23EC'
53+emoji[black_right_pointing_double_triangle_with_vertical_bar]=$'\U23ED'
54+emoji[black_left_pointing_double_triangle_with_vertical_bar]=$'\U23EE'
55+emoji[black_right_pointing_triangle_with_double_vertical_bar]=$'\U23EF'
56+emoji[alarm_clock]=$'\U23F0'
57+emoji[stopwatch]=$'\U23F1'
58+emoji[timer_clock]=$'\U23F2'
59+emoji[hourglass_with_flowing_sand]=$'\U23F3'
60+emoji[double_vertical_bar]=$'\U23F8'
61+emoji[black_square_for_stop]=$'\U23F9'
62+emoji[black_circle_for_record]=$'\U23FA'
63+emoji[circled_latin_capital_letter_m]=$'\U24C2'
64+emoji[black_small_square]=$'\U25AA'
65+emoji[white_small_square]=$'\U25AB'
66+emoji[black_right_pointing_triangle]=$'\U25B6'
67+emoji[black_left_pointing_triangle]=$'\U25C0'
68+emoji[white_medium_square]=$'\U25FB'
69+emoji[black_medium_square]=$'\U25FC'
70+emoji[white_medium_small_square]=$'\U25FD'
71+emoji[black_medium_small_square]=$'\U25FE'
72+emoji[black_sun_with_rays]=$'\U2600'
73+emoji[cloud]=$'\U2601'
74+emoji[umbrella]=$'\U2602'
75+emoji[snowman]=$'\U2603'
76+emoji[comet]=$'\U2604'
77+emoji[black_telephone]=$'\U260E'
78+emoji[ballot_box_with_check]=$'\U2611'
79+emoji[umbrella_with_rain_drops]=$'\U2614'
80+emoji[hot_beverage]=$'\U2615'
81+emoji[shamrock]=$'\U2618'
82+emoji[white_up_pointing_index]=$'\U261D'
83+emoji[skull_and_crossbones]=$'\U2620'
84+emoji[radioactive_sign]=$'\U2622'
85+emoji[biohazard_sign]=$'\U2623'
86+emoji[orthodox_cross]=$'\U2626'
87+emoji[star_and_crescent]=$'\U262A'
88+emoji[peace_symbol]=$'\U262E'
89+emoji[yin_yang]=$'\U262F'
90+emoji[wheel_of_dharma]=$'\U2638'
91+emoji[white_frowning_face]=$'\U2639'
92+emoji[white_smiling_face]=$'\U263A'
93+emoji[aries]=$'\U2648'
94+emoji[taurus]=$'\U2649'
95+emoji[gemini]=$'\U264A'
96+emoji[cancer]=$'\U264B'
97+emoji[leo]=$'\U264C'
98+emoji[virgo]=$'\U264D'
99+emoji[libra]=$'\U264E'
100+emoji[scorpius]=$'\U264F'
101+emoji[sagittarius]=$'\U2650'
102+emoji[capricorn]=$'\U2651'
103+emoji[aquarius]=$'\U2652'
104+emoji[pisces]=$'\U2653'
105+emoji[black_spade_suit]=$'\U2660'
106+emoji[black_club_suit]=$'\U2663'
107+emoji[black_heart_suit]=$'\U2665'
108+emoji[black_diamond_suit]=$'\U2666'
109+emoji[hot_springs]=$'\U2668'
110+emoji[black_universal_recycling_symbol]=$'\U267B'
111+emoji[wheelchair_symbol]=$'\U267F'
112+emoji[hammer_and_pick]=$'\U2692'
113+emoji[anchor]=$'\U2693'
114+emoji[crossed_swords]=$'\U2694'
115+emoji[scales]=$'\U2696'
116+emoji[alembic]=$'\U2697'
117+emoji[gear]=$'\U2699'
118diff --git a/plugins/emoji/emoji-data.txt b/plugins/emoji/emoji-data.txt
119new file mode 100644
120index 0000000000000000000000000000000000000000..7b4c015f7afb8ccd82f9b027da43df8c7a8e1ba7
121--- /dev/null
122+++ b/plugins/emoji/emoji-data.txt
123@@ -0,0 +1,1308 @@
124+# DRAFT emoji-data.txt
125+# For details about the format and other information, see /../../../reports/tr51/index.html#Data_Files.
126+#
127+# Format: Code ; Default_Emoji_Style ; Emoji_Level ; Emoji_Modifier_Status ; Emoji_Sources # Comment
128+#
129+# Field 1 — Default_Emoji_Style:
130+# text: default text presentation
131+# emoji: default emoji presentation
132+# Field 2 — Emoji_Level:
133+# L1: level 1 emoji
134+# L2: level 2 emoji
135+# NA: not applicable
136+# Field 3 — Emoji_Modifier_Status:
137+# modifier: an emoji modifier
138+# primary: a primary emoji modifier base
139+# secondary: a secondary emoji modifier base
140+# none: not applicable
141+# Field 4 — Emoji_Sources:
142+# one or more values from {z, a, j, w, x}
143+# see the key in http://www.unicode.org/draft/reports/tr51/tr51.html#Major_Sources
144+# NA: not applicable
145+# Comment — currently contains the version where the character was first encoded,
146+# followed by:
147+# - a character name in uppercase (for a single character),
148+# - a keycap name,
149+# - an associated flag, where is associated with value unicode region code
150+#
151+00A9 ; text ; L1 ; none ; j # V1.1 (©) COPYRIGHT SIGN
152+00AE ; text ; L1 ; none ; j # V1.1 (®) REGISTERED SIGN
153+203C ; text ; L1 ; none ; a j # V1.1 (‼) DOUBLE EXCLAMATION MARK
154+2049 ; text ; L1 ; none ; a j # V3.0 (⁉) EXCLAMATION QUESTION MARK
155+2122 ; text ; L1 ; none ; j # V1.1 (™) TRADE MARK SIGN
156+2139 ; text ; L1 ; none ; j # V3.0 (ℹ) INFORMATION SOURCE
157+2194 ; text ; L1 ; none ; z j # V1.1 (↔) LEFT RIGHT ARROW
158+2195 ; text ; L1 ; none ; z j # V1.1 (↕) UP DOWN ARROW
159+2196 ; text ; L1 ; none ; j # V1.1 (↖) NORTH WEST ARROW
160+2197 ; text ; L1 ; none ; j # V1.1 (↗) NORTH EAST ARROW
161+2198 ; text ; L1 ; none ; j # V1.1 (↘) SOUTH EAST ARROW
162+2199 ; text ; L1 ; none ; j # V1.1 (↙) SOUTH WEST ARROW
163+21A9 ; text ; L1 ; none ; j # V1.1 (↩) LEFTWARDS ARROW WITH HOOK
164+21AA ; text ; L1 ; none ; j # V1.1 (↪) RIGHTWARDS ARROW WITH HOOK
165+231A ; emoji ; L1 ; none ; j # V1.1 (⌚) WATCH
166+231B ; emoji ; L1 ; none ; j # V1.1 (⌛) HOURGLASS
167+2328 ; text ; L2 ; none ; x # V1.1 (⌨) KEYBOARD
168+23CF ; text ; L2 ; none ; x # V4.0 (⏏) EJECT SYMBOL
169+23E9 ; emoji ; L1 ; none ; j w # V6.0 (⏩) BLACK RIGHT-POINTING DOUBLE TRIANGLE
170+23EA ; emoji ; L1 ; none ; j w # V6.0 (⏪) BLACK LEFT-POINTING DOUBLE TRIANGLE
171+23EB ; emoji ; L1 ; none ; j # V6.0 (⏫) BLACK UP-POINTING DOUBLE TRIANGLE
172+23EC ; emoji ; L1 ; none ; j # V6.0 (⏬) BLACK DOWN-POINTING DOUBLE TRIANGLE
173+23ED ; text ; L2 ; none ; w # V6.0 (⏭) BLACK RIGHT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
174+23EE ; text ; L2 ; none ; w # V6.0 (⏮) BLACK LEFT-POINTING DOUBLE TRIANGLE WITH VERTICAL BAR
175+23EF ; text ; L2 ; none ; x # V6.0 (⏯) BLACK RIGHT-POINTING TRIANGLE WITH DOUBLE VERTICAL BAR
176+23F0 ; emoji ; L1 ; none ; j # V6.0 (⏰) ALARM CLOCK
177+23F1 ; text ; L2 ; none ; x # V6.0 (⏱) STOPWATCH
178+23F2 ; text ; L2 ; none ; x # V6.0 (⏲) TIMER CLOCK
179+23F3 ; emoji ; L1 ; none ; j w # V6.0 (⏳) HOURGLASS WITH FLOWING SAND
180+23F8 ; text ; L2 ; none ; w # V7.0 (⏸) DOUBLE VERTICAL BAR
181+23F9 ; text ; L2 ; none ; w # V7.0 (⏹) BLACK SQUARE FOR STOP
182+23FA ; text ; L2 ; none ; w # V7.0 (⏺) BLACK CIRCLE FOR RECORD
183+24C2 ; text ; L1 ; none ; j # V1.1 (Ⓜ) CIRCLED LATIN CAPITAL LETTER M
184+25AA ; text ; L1 ; none ; j w # V1.1 (▪) BLACK SMALL SQUARE
185+25AB ; text ; L1 ; none ; j # V1.1 (▫) WHITE SMALL SQUARE
186+25B6 ; text ; L1 ; none ; a j w # V1.1 (▶) BLACK RIGHT-POINTING TRIANGLE
187+25C0 ; text ; L1 ; none ; a j w # V1.1 (◀) BLACK LEFT-POINTING TRIANGLE
188+25FB ; text ; L1 ; none ; j # V3.2 (◻) WHITE MEDIUM SQUARE
189+25FC ; text ; L1 ; none ; j w # V3.2 (◼) BLACK MEDIUM SQUARE
190+25FD ; emoji ; L1 ; none ; j # V3.2 (◽) WHITE MEDIUM SMALL SQUARE
191+25FE ; emoji ; L1 ; none ; j w # V3.2 (◾) BLACK MEDIUM SMALL SQUARE
192+2600 ; text ; L1 ; none ; a j # V1.1 (☀) BLACK SUN WITH RAYS
193+2601 ; text ; L1 ; none ; a j w # V1.1 (☁) CLOUD
194+2602 ; text ; L2 ; none ; a # V1.1 (☂) UMBRELLA
195+2603 ; text ; L2 ; none ; a # V1.1 (☃) SNOWMAN
196+2604 ; text ; L2 ; none ; x # V1.1 (☄) COMET
197+260E ; text ; L1 ; none ; z a j # V1.1 (☎) BLACK TELEPHONE
198+2611 ; text ; L1 ; none ; j w # V1.1 (☑) BALLOT BOX WITH CHECK
199+2614 ; emoji ; L1 ; none ; a j # V4.0 (☔) UMBRELLA WITH RAIN DROPS
200+2615 ; emoji ; L1 ; none ; j # V4.0 (☕) HOT BEVERAGE
201+2618 ; text ; L2 ; none ; x # V4.1 (☘) SHAMROCK
202+261D ; text ; L1 ; secondary ; j w # V1.1 (☝) WHITE UP POINTING INDEX
203+2620 ; text ; L2 ; none ; x # V1.1 (☠) SKULL AND CROSSBONES
204+2622 ; text ; L2 ; none ; x # V1.1 (☢) RADIOACTIVE SIGN
205+2623 ; text ; L2 ; none ; x # V1.1 (☣) BIOHAZARD SIGN
206+2626 ; text ; L2 ; none ; x # V1.1 (☦) ORTHODOX CROSS
207+262A ; text ; L2 ; none ; w # V1.1 (☪) STAR AND CRESCENT
208+262E ; text ; L2 ; none ; x # V1.1 (☮) PEACE SYMBOL
209+262F ; text ; L2 ; none ; w # V1.1 (☯) YIN YANG
210+2638 ; text ; L2 ; none ; w # V1.1 (☸) WHEEL OF DHARMA
211+2639 ; text ; L2 ; secondary ; w # V1.1 (☹) WHITE FROWNING FACE
212+263A ; text ; L1 ; secondary ; j w # V1.1 (☺) WHITE SMILING FACE
213+2648 ; emoji ; L1 ; none ; j w # V1.1 (♈) ARIES
214+2649 ; emoji ; L1 ; none ; j w # V1.1 (♉) TAURUS
215+264A ; emoji ; L1 ; none ; j w # V1.1 (♊) GEMINI
216+264B ; emoji ; L1 ; none ; j w # V1.1 (♋) CANCER
217+264C ; emoji ; L1 ; none ; j w # V1.1 (♌) LEO
218+264D ; emoji ; L1 ; none ; j w # V1.1 (♍) VIRGO
219+264E ; emoji ; L1 ; none ; j w # V1.1 (♎) LIBRA
220+264F ; emoji ; L1 ; none ; j w # V1.1 (♏) SCORPIUS
221+2650 ; emoji ; L1 ; none ; j w # V1.1 (♐) SAGITTARIUS
222+2651 ; emoji ; L1 ; none ; j w # V1.1 (♑) CAPRICORN
223diff --git a/plugins/emoji/emoji.plugin.zsh b/plugins/emoji/emoji.plugin.zsh
224index be761871e98a3b7336a63be2155d5529e33ad086..dbaf2bb9e2dd949f81ad55657bc70d946580802d 100644
225--- a/plugins/emoji/emoji.plugin.zsh
226+++ b/plugins/emoji/emoji.plugin.zsh
227@@ -1,876 +1,149 @@
228-# Make emoji available within the ZSH terminal
229+# emoji plugin
230+#
231+# Makes emoji support available within ZSH
232+#
233+# This plugin provides support for working with emoji characters in zsh using human-readable
234+# identifiers. It provides global variables which map emoji names to the actual
235+# characters, and some anmed groupings of emoji. It also provides associated functions
236+# for displaying them.
237+#
238+# Global variables:
239+# $emoji - Maps emoji names to characters
240+# $emoji2 - Auxiliary and combining characters
241+# $emoji_flags - Maps country names to flag characters (using region-indicators)
242+# $emoji_skintone - Skin tone modifiers (from Unicode 8.0)
243+# $emoji_groups - Named groups of emoji. Keys are group names; values are whitespace-separated
244+# lists of character names
245+#
246+# Functions:
247+# random_emoji - Prints a random emoji character
248+# display_emoji - Displays emoji, along with their names
249+#
250+# The emoji names and codes are sourced from Unicode Technical Report #51, which provides
251+# information on emoji support in Unicode. It can be found at http://www.unicode.org/reports/tr51/index.html.
252+#
253+# The group definitions are added by this OMZ plugin. They are not based on external definitions.
254+#
255+# The emoji in the main $emoji map are standalone character sequences which can all be output on their
256+# own, without worrying about combining effects. The values may actually be multi-code-point sequences,
257+# instead of a single code point, and may include combining characters in those sequences. But they're
258+# arranged so their effects do not extend beyond that sequence.
259+#
260+# Usage and Examples:
261 #
262 # To output a specific emoji, use:
263 # $> echo $emoji[<name>]
264-# ex: $> echo $emoji[mouse_face]
265+# E.g.:
266+# $> echo $emoji[mouse_face]
267 #
268 # To output a random emoji, use:
269 # $> random_emoji
270-# $> random_emoji_fruit
271-# $> random_emoji_animal
272-# $> random_emoji_vehicle
273-# $> random_emoji_face
274+# To output a random emoji from a particular group, use:
275+# $> random_emoji <group>
276+# E.g.:
277+# $> random_emoji fruits
278+# $> random_emoji animals
279+# $> random_emoji vehicles
280+# $> random_emoji faces
281+# The valid group names can be found with `echo ${(k)emoji_groups}`
282+#
283+# To list all available emoji with their names, use:
284+# $> display_emoji
285+# $> display_emoji fruits
286+# $> display_emoji animals
287+# $> display_emoji vehicles
288+# $> display_emoji faces
289 #
290-# To list all available emoji with names, use:
291-# $> display_all_emoji
292-# $> display_emoji_fruits
293-# $> display_emoji_animals
294-# $> display_emoji_vehicles
295-# $> display_emoji_faces
296+# To use emoji in a prompt:
297+# PROMPT="$emoji[penguin] > ""
298+# PROMPT='$(random_emoji fruits) > '
299+# surfer=$emoji[surfer]
300+# PROMPT="$surfer > "
301 #
302-# To use an emoji in a prompt:
303-# PROMPT='$(echo $emoji[penguin]) > '
304-# PROMPT='$(random_emoji_fruit) > '
305-# eval surfer=$(echo $emoji[surfer])
306-# PROMPT='$surfer > '
307 #
308-# emoji codes sourced from http://apps.timwhitlock.info/emoji/tables/unicode
309+# TODO: Move doco to a README
310+# TODO: Factor out parsing from generation in update_emoji.pl
311+# TODO: Incorporate CLDR data for ordering and groupings
312+# TODO: Short :bracket: style names (from gemoji)
313+# TODO: Country codes for flags
314+# TODO: ZWJ combining function?
315+
316+_omz_emoji_plugin_dir="${0:h}"
317+
318+() {
319+
320+local LC_ALL=en_US.UTF-8
321
322-typeset -A emoji
323-emoji[grinning_face_with_smiling_eyes]='\xF0\x9F\x98\x81'
324-emoji[face_with_tears_of_joy]='\xF0\x9F\x98\x82'
325-emoji[smiling_face_with_open_mouth]='\xF0\x9F\x98\x83'
326-emoji[smiling_face_with_open_mouth_and_smiling_eyes]='\xF0\x9F\x98\x84'
327diff --git a/plugins/emoji/update_emoji.pl b/plugins/emoji/update_emoji.pl
328new file mode 100644
329index 0000000000000000000000000000000000000000..d90c6e31622e362038880a64d26c41dc6f860580
330--- /dev/null
331+++ b/plugins/emoji/update_emoji.pl
332@@ -0,0 +1,113 @@
333+#!/usr/bin/perl -w
334+#
335+# update_emoji.pl
336+#
337+# This script generates the emoji.plugin.zsh emoji definitions from the Unicode
338+# character data for the emoji characters.
339+#
340+# The data file can be found at http://unicode.org/Public/emoji/latest/emoji-data.txt
341+# as referenced in Unicode TR51 (http://www.unicode.org/reports/tr51/index.html).
342+#
343+# This is known to work with the data file from version 1.0. It may not work with later
344+# versions if the format changes. In particular, this reads line comments to get the
345+# emoji character name and unicode version.
346+#
347+# Country names have punctuation and other non-letter characters removed from their name,
348+# to avoid possible complications with having to escape the strings when using them as
349+# array subscripts. The definition file seems to use some combining characters like accents
350+# that get stripped during this process.
351+
352+use strict;
353+use warnings;
354+use 5.010;
355+use autodie;
356+
357+use Path::Class;
358+use File::Copy;
359+
360+# Parse definitions out of the data file and convert
361+sub process_emoji_data_file {
362+ my ( $infile, $outfilename ) = @_;
363+ my $file = file($infile);
364+ my $outfile = file($outfilename);
365+ my $outfilebase = $outfile->basename();
366+ my $tempfilename = "$outfilename.tmp";
367+ my $tempfile = file($tempfilename);
368+ my $outfh = $tempfile->openw();
369+ $outfh->print("
370+# $outfilebase - Emoji character definitions for oh-my-zsh emoji plugin
371+#
372+# This file is auto-generated by update_emoji.pl. Do not edit it manually.
373+#
374+# This contains the definition for:
375+# \$emoji - which maps character names to Unicode characters
376+# \$emoji_flags - maps country names to Unicode flag characters using region indicators
377+
378+# Main emoji
379+typeset -gAH emoji
380+# National flags
381+typeset -gAH emoji_flags
382+# Combining modifiers
383+typeset -gAH emoji_mod
384+
385+");
386+
387+ my $fh = $file->openr();
388+ my $line_num = 0;
389+ while ( my $line = $fh->getline() ) {
390+ $line_num++;
391+ $_ = $line;
392+ # Skip all-comment lines (from the header) and blank lines
393+ # (But don't strip comments on normal lines; we need to parse those for
394+ # the emoji names.)
395+ next if /^\s*#/ or /^\s*$/;
396+
397+ if (/^(\S.*?\S)\s*;\s*(\w+)\s*;\s*(\w+)\s*;\s*(\w+)\s*;\s*(\w.*?)\s*#\s*V(\S+)\s\(.*?\)\s*(\w.*\S)\s*$/) {
398+ my ($code, $style, $level, $modifier_status, $sources, $version, $keycap_name)
399+ = ($1, $2, $3, $4, $5, $6, $7);
400+ #print "code=$code style=$style level=$level modifier_status=$modifier_status sources=$sources version=$version name=$keycap_name\n";
401+ my @code_points = split /\s+/, $code;
402+ my @sources = split /\s+/, $sources;
403+
404+ my $flag_country = "";
405+ if ( $keycap_name =~ /^flag for (\S.*?)\s*$/) {
406+ $flag_country = $1;
407+ }
408+
409+ my $zsh_code = join '', map { "\\U$_" } @code_points;
410+ # Convert keycap names to valid associative array names that do not require any
411+ # quoting. Works fine for most stuff, but is clumsy for flags.
412+ my $omz_name = lc($keycap_name);
413+ $omz_name =~ s/[^A-Za-z0-9]/_/g;
414+ my $zsh_flag_country = $flag_country;
415+ $zsh_flag_country =~ s/[^\p{Letter}]/_/g;
416+ if ($flag_country) {
417+ $outfh->print("emoji_flags[$zsh_flag_country]=\$'$zsh_code'\n");
418+ } else {
419+ $outfh->print("emoji[$omz_name]=\$'$zsh_code'\n");
420+ }
421+ # Modifiers are included in both the main set and their separate map,
422+ # because they have a standalone representation as a color swatch.
423+ if ( $modifier_status == "modifier" ) {
424+ $outfh->print("emoji_mod[$omz_name]=\$'$zsh_code'\n");
425+ }
426+ } else {
427+ die "Failed parsing line $line_num: '$_'";
428+ }
429+ }
430+ $fh->close();
431+ $outfh->print("\n");