| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package DBIx::Class::Schema::PopulateMore; | 
| 2 |  |  |  |  |  |  |  | 
| 3 | 3 |  |  | 3 |  | 1571 | use warnings; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 82 |  | 
| 4 | 3 |  |  | 3 |  | 11 | use strict; | 
|  | 3 |  |  |  |  | 3 |  | 
|  | 3 |  |  |  |  | 67 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 3 |  |  | 3 |  | 71 | use 5.008005; | 
|  | 3 |  |  |  |  | 10 |  | 
|  | 3 |  |  |  |  | 75 |  | 
| 7 | 3 |  |  | 3 |  | 1285 | use DBIx::Class::Schema::PopulateMore::Command; | 
|  | 3 |  |  |  |  | 9 |  | 
|  | 3 |  |  |  |  | 47 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 |  |  |  |  |  |  | =head1 NAME | 
| 10 |  |  |  |  |  |  |  | 
| 11 |  |  |  |  |  |  | DBIx::Class::Schema::PopulateMore - An enhanced populate method | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | =head1 VERSION | 
| 14 |  |  |  |  |  |  |  | 
| 15 |  |  |  |  |  |  | Version 0.19 | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | =cut | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  | our $VERSION = '0.19'; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | =head1 SYNOPSIS | 
| 22 |  |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | The following is example usage for this component. | 
| 24 |  |  |  |  |  |  |  | 
| 25 |  |  |  |  |  |  | package Myapp::Schema; | 
| 26 |  |  |  |  |  |  | use base qw/DBIx::Class::Schema/; | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  | __PACKAGE__->load_components(qw/Schema::PopulateMore/); | 
| 29 |  |  |  |  |  |  | __PACKAGE__->load_namespaces(); | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | ## All the rest of your setup | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  | Then assuming you have ResultSources of Gender, Person and FriendList: | 
| 34 |  |  |  |  |  |  |  | 
| 35 |  |  |  |  |  |  | my $setup_rows = [ | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | {Gender => { | 
| 38 |  |  |  |  |  |  | fields => 'label', | 
| 39 |  |  |  |  |  |  | data => { | 
| 40 |  |  |  |  |  |  | male => 'male', | 
| 41 |  |  |  |  |  |  | female => 'female', | 
| 42 |  |  |  |  |  |  | }}}, | 
| 43 |  |  |  |  |  |  |  | 
| 44 |  |  |  |  |  |  | {Person	=> { | 
| 45 |  |  |  |  |  |  | fields => ['name', 'age', 'gender'], | 
| 46 |  |  |  |  |  |  | data => { | 
| 47 |  |  |  |  |  |  | john => ['john', 38, "!Index:Gender.male"], | 
| 48 |  |  |  |  |  |  | jane => ['jane', 40, '!Index:Gender.female'], | 
| 49 |  |  |  |  |  |  | }}}, | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | {FriendList => { | 
| 52 |  |  |  |  |  |  | fields => ['person', 'friend', 'created_date'], | 
| 53 |  |  |  |  |  |  | data => { | 
| 54 |  |  |  |  |  |  | john_jane => [ | 
| 55 |  |  |  |  |  |  | '!Index:Person.john', | 
| 56 |  |  |  |  |  |  | '!Index:Person.jane' | 
| 57 |  |  |  |  |  |  | '!Date: March 30, 1996', | 
| 58 |  |  |  |  |  |  | ], | 
| 59 |  |  |  |  |  |  | }}}, | 
| 60 |  |  |  |  |  |  | ]; | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | $schema->populate_more($setup_rows); | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | Please see the test cases for more detailed examples. | 
| 65 |  |  |  |  |  |  |  | 
| 66 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 67 |  |  |  |  |  |  |  | 
| 68 |  |  |  |  |  |  | This is a L<DBIx::Class::Schema> component that provides an enhanced version | 
| 69 |  |  |  |  |  |  | of the builtin method L<DBIx::Class::Schema/populate>.  What it does is make it | 
| 70 |  |  |  |  |  |  | easier when you are doing a first time setup and need to insert a bunch of | 
| 71 |  |  |  |  |  |  | rows, like the first time you deploy a new database, or after you update it. | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | It's not as full featured as L<DBIx::Class::Fixtures> but is targeted more | 
| 74 |  |  |  |  |  |  | directly at making it easier to just take a prewritten perl structure --or one | 
| 75 |  |  |  |  |  |  | loaded from a configuration file-- and setup your database. | 
| 76 |  |  |  |  |  |  |  | 
| 77 |  |  |  |  |  |  | Most of us using L<DBIx::CLass> have written a version of this at one time or | 
| 78 |  |  |  |  |  |  | another.  What is special to this component is the fact that unlike the normal | 
| 79 |  |  |  |  |  |  | populate method you can insert to multiple result_sources in one go.  While | 
| 80 |  |  |  |  |  |  | doing this, we index the created rows so as to make it easy to reference them | 
| 81 |  |  |  |  |  |  | in relationships. I did this because I think it's very ugly to have to type in | 
| 82 |  |  |  |  |  |  | all the primary keys by hand, particularly if your PK is multi column, or is | 
| 83 |  |  |  |  |  |  | using some lengthy format such as uuid.  Also, we can embed expansion commands | 
| 84 |  |  |  |  |  |  | in the row values to do inflation for us.  For example, any value starting with | 
| 85 |  |  |  |  |  |  | "!Index:" will substitute it's value for that of the relating fields in the | 
| 86 |  |  |  |  |  |  | named row. | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | This distribution supplies three expansion commands: | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | =over 4 | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | =item Index | 
| 93 |  |  |  |  |  |  |  | 
| 94 |  |  |  |  |  |  | Use for creating relationships.  This is a string in the form of "Source.Label" | 
| 95 |  |  |  |  |  |  | where the Source is the name of the result source that you are creating rows in | 
| 96 |  |  |  |  |  |  | and Label is a key name from the key part of the data hash. | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | =item Env | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | Get's it's value from %ENV.  Typically this will be setup in your shell or at | 
| 101 |  |  |  |  |  |  | application runtime.  This is a string in the form of "!Env:MY_ENV_VAR" | 
| 102 |  |  |  |  |  |  |  | 
| 103 |  |  |  |  |  |  | =item Date | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  | converts it's value to a L<DateTime> object.  Will use a various methods to try | 
| 106 |  |  |  |  |  |  | and coerce a string, like "today", or "January 6, 1974".  Makes it easier to | 
| 107 |  |  |  |  |  |  | insert dates into your database without knowing or caring about the expected | 
| 108 |  |  |  |  |  |  | format.  For this to work correctly, you need to use the class component | 
| 109 |  |  |  |  |  |  | L<DBIx::Class::InflateColumn::DateTime> and mark your column data type as | 
| 110 |  |  |  |  |  |  | 'datetime' or similar. | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | =item Find | 
| 113 |  |  |  |  |  |  |  | 
| 114 |  |  |  |  |  |  | Used for when you want the value of something that you expect already exists | 
| 115 |  |  |  |  |  |  | in the database (but for which you didn't just populatemore for, use 'Index' | 
| 116 |  |  |  |  |  |  | for that case.) Use cases for this include lookup style tables, like 'Status' | 
| 117 |  |  |  |  |  |  | or 'Gender', 'State', etc. which you may already have installed. This is a | 
| 118 |  |  |  |  |  |  | string in the form of '!Find:Source.[key1=val1,key2=val2,...'. | 
| 119 |  |  |  |  |  |  |  | 
| 120 |  |  |  |  |  |  | If your find doesn't return a single result, expect an error. | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | It's trivial to write more; please feel free to post me your contributions. | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | =back | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | Please note the when inserting rows, we are actually calling "create_or_update" | 
| 127 |  |  |  |  |  |  | on each data item, so this will not be as fast as using $schema->bulk_insert. | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | =head1 METHODS | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | This module defines the following methods. | 
| 133 |  |  |  |  |  |  |  | 
| 134 |  |  |  |  |  |  | =head2 populate_more ($ArrayRef||@Array) | 
| 135 |  |  |  |  |  |  |  | 
| 136 |  |  |  |  |  |  | Given an arrayref formatted as in the L</SYNOPSIS> example, populate a rows in | 
| 137 |  |  |  |  |  |  | a database.  Confesses on errors. | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | We allow a few different inputs to make it less verbose to use under different | 
| 140 |  |  |  |  |  |  | situations, as well as format nicely using your configuration format of choice. | 
| 141 |  |  |  |  |  |  |  | 
| 142 |  |  |  |  |  |  | The $ArrayRef contains one or more elements in the following pattern; | 
| 143 |  |  |  |  |  |  |  | 
| 144 |  |  |  |  |  |  | $schema->populate_more([ | 
| 145 |  |  |  |  |  |  | {Source1 => { | 
| 146 |  |  |  |  |  |  | fields => [qw/ column belongs_to has_many/], | 
| 147 |  |  |  |  |  |  | data => { | 
| 148 |  |  |  |  |  |  | key_1 => ['value', $row, \@rows ], | 
| 149 |  |  |  |  |  |  | }}}, | 
| 150 |  |  |  |  |  |  | {Source2 => { | 
| 151 |  |  |  |  |  |  | fields => [qw/ column belongs_to has_many/], | 
| 152 |  |  |  |  |  |  | data => { | 
| 153 |  |  |  |  |  |  | key_1 => ['value', $row, \@rows ], | 
| 154 |  |  |  |  |  |  | }}}, | 
| 155 |  |  |  |  |  |  | ]); | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  | The @Array version can be one of the following: | 
| 158 |  |  |  |  |  |  |  | 
| 159 |  |  |  |  |  |  | ## Option One | 
| 160 |  |  |  |  |  |  | $schema->populate_more( | 
| 161 |  |  |  |  |  |  | {Source1 => { | 
| 162 |  |  |  |  |  |  | fields => [qw/ column belongs_to has_many/], | 
| 163 |  |  |  |  |  |  | data => { | 
| 164 |  |  |  |  |  |  | key_1 => ['value', $row, \@rows ], | 
| 165 |  |  |  |  |  |  | }}}, | 
| 166 |  |  |  |  |  |  | {Source2 => { | 
| 167 |  |  |  |  |  |  | fields => [qw/ column belongs_to has_many/], | 
| 168 |  |  |  |  |  |  | data => { | 
| 169 |  |  |  |  |  |  | key_1 => ['value', $row, \@rows ], | 
| 170 |  |  |  |  |  |  | }}}, | 
| 171 |  |  |  |  |  |  | ); | 
| 172 |  |  |  |  |  |  |  | 
| 173 |  |  |  |  |  |  | ## Option Two | 
| 174 |  |  |  |  |  |  | $schema->populate_more( | 
| 175 |  |  |  |  |  |  | Source1 => { | 
| 176 |  |  |  |  |  |  | fields => [qw/ column belongs_to has_many/], | 
| 177 |  |  |  |  |  |  | data => { | 
| 178 |  |  |  |  |  |  | key_1 => ['value', $row, \@rows ], | 
| 179 |  |  |  |  |  |  | } | 
| 180 |  |  |  |  |  |  | }, | 
| 181 |  |  |  |  |  |  | Source2 => { | 
| 182 |  |  |  |  |  |  | fields => [qw/ column belongs_to has_many/], | 
| 183 |  |  |  |  |  |  | data => { | 
| 184 |  |  |  |  |  |  | key_1 => ['value', $row, \@rows ], | 
| 185 |  |  |  |  |  |  | } | 
| 186 |  |  |  |  |  |  | }, | 
| 187 |  |  |  |  |  |  | ); | 
| 188 |  |  |  |  |  |  |  | 
| 189 |  |  |  |  |  |  | The last option is probably your choice if you are building a Perl structure | 
| 190 |  |  |  |  |  |  | directly, since it's the least verbose. | 
| 191 |  |  |  |  |  |  |  | 
| 192 |  |  |  |  |  |  | 'SourceX' is the name of a DBIC source (as in $schema->resultset($Source)->...) | 
| 193 |  |  |  |  |  |  | while fields is an arrayref of either columns or named relationships and data | 
| 194 |  |  |  |  |  |  | is a hashref of rows that you will insert into the Source. | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | See L</SYNOPSIS> for more. | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | =cut | 
| 199 |  |  |  |  |  |  |  | 
| 200 |  |  |  |  |  |  | sub populate_more { | 
| 201 | 5 |  |  | 5 | 1 | 86809 | my ($self, $arg, @rest) = @_; | 
| 202 |  |  |  |  |  |  |  | 
| 203 | 5 | 50 |  |  |  | 23 | $self->throw_exception("Argument is required.") | 
| 204 |  |  |  |  |  |  | unless $arg; | 
| 205 |  |  |  |  |  |  |  | 
| 206 | 5 | 100 | 66 |  |  | 53 | my @args = (ref $arg && ref $arg eq 'ARRAY') ? @$arg : ($arg, @rest); | 
| 207 |  |  |  |  |  |  |  | 
| 208 | 5 |  |  |  |  | 8 | my @definitions; | 
| 209 | 5 |  |  |  |  | 18 | while(@args) { | 
| 210 | 16 |  |  |  |  | 17 | my $next = shift(@args); | 
| 211 | 16 | 100 | 66 |  |  | 65 | if( (ref $next) && (ref $next eq 'HASH') ) { | 
| 212 | 14 |  |  |  |  | 30 | push @definitions, $next; | 
| 213 |  |  |  |  |  |  | } else { | 
| 214 | 2 |  |  |  |  | 4 | my $value = shift(@args); | 
| 215 | 2 |  |  |  |  | 10 | push @definitions, {$next => $value}; | 
| 216 |  |  |  |  |  |  | } | 
| 217 |  |  |  |  |  |  | } | 
| 218 |  |  |  |  |  |  |  | 
| 219 | 5 |  |  |  |  | 11 | my $command; | 
| 220 | 5 |  |  |  |  | 8 | eval { | 
| 221 |  |  |  |  |  |  | $command = DBIx::Class::Schema::PopulateMore::Command->new( | 
| 222 |  |  |  |  |  |  | definitions=>[@definitions], | 
| 223 |  |  |  |  |  |  | schema=>$self, | 
| 224 |  |  |  |  |  |  | exception_cb=>sub { | 
| 225 | 0 |  |  | 0 |  | 0 | $self->throw_exception(@_); | 
| 226 |  |  |  |  |  |  | }, | 
| 227 | 5 |  |  |  |  | 160 | ); | 
| 228 |  |  |  |  |  |  | }; | 
| 229 |  |  |  |  |  |  |  | 
| 230 | 5 | 50 |  |  |  | 252 | if($@) { | 
| 231 | 0 |  |  |  |  | 0 | $self->throw_exception("Can't create Command: $@"); | 
| 232 |  |  |  |  |  |  | } else { | 
| 233 | 5 |  |  |  |  | 26 | $command->execute; | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  | } | 
| 236 |  |  |  |  |  |  |  | 
| 237 |  |  |  |  |  |  |  | 
| 238 |  |  |  |  |  |  | =head1 ARGUMENT NOTES | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | The perl structure used in L</populate_more> was designed to be reasonable | 
| 241 |  |  |  |  |  |  | friendly to type in most of the popular configuration formats.  For example, | 
| 242 |  |  |  |  |  |  | the above serialized to YAML would look like: | 
| 243 |  |  |  |  |  |  |  | 
| 244 |  |  |  |  |  |  | - Gender: | 
| 245 |  |  |  |  |  |  | fields: label | 
| 246 |  |  |  |  |  |  | data: | 
| 247 |  |  |  |  |  |  | female: female | 
| 248 |  |  |  |  |  |  | male: male | 
| 249 |  |  |  |  |  |  | - Person: | 
| 250 |  |  |  |  |  |  | fields: | 
| 251 |  |  |  |  |  |  | - name | 
| 252 |  |  |  |  |  |  | - age | 
| 253 |  |  |  |  |  |  | - gender | 
| 254 |  |  |  |  |  |  | data: | 
| 255 |  |  |  |  |  |  | jane: | 
| 256 |  |  |  |  |  |  | - jane | 
| 257 |  |  |  |  |  |  | - 40 | 
| 258 |  |  |  |  |  |  | - '!Index:Gender.female' | 
| 259 |  |  |  |  |  |  | john: | 
| 260 |  |  |  |  |  |  | - john | 
| 261 |  |  |  |  |  |  | - 38 | 
| 262 |  |  |  |  |  |  | - !Index:Gender.male' | 
| 263 |  |  |  |  |  |  | - FriendList: | 
| 264 |  |  |  |  |  |  | fields: | 
| 265 |  |  |  |  |  |  | - person | 
| 266 |  |  |  |  |  |  | - friend | 
| 267 |  |  |  |  |  |  | - created_date | 
| 268 |  |  |  |  |  |  | data: | 
| 269 |  |  |  |  |  |  | john_jane: | 
| 270 |  |  |  |  |  |  | - '!Index:Person.john' | 
| 271 |  |  |  |  |  |  | - '!Index:Person.jane' | 
| 272 |  |  |  |  |  |  | - '!Date: March 30, 1996' | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | Since the argument is an arrayref or an array, the same base result source can | 
| 275 |  |  |  |  |  |  | appear as many times as you like.  This could be useful when a second insert | 
| 276 |  |  |  |  |  |  | to a given source requires completion of other inserts.  The insert order | 
| 277 |  |  |  |  |  |  | follows the index of the arrayref you create. | 
| 278 |  |  |  |  |  |  |  | 
| 279 |  |  |  |  |  |  | =head1 AUTHOR | 
| 280 |  |  |  |  |  |  |  | 
| 281 |  |  |  |  |  |  | John Napiorkowski, C<< <jjnapiork@cpan.org> >> | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | =head1 BUGS | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | Please report any bugs or feature requests to: | 
| 286 |  |  |  |  |  |  |  | 
| 287 |  |  |  |  |  |  | C<bug-DBIx-Class-Schema-PopulateMore at rt.cpan.org> | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | or through the web interface at: | 
| 290 |  |  |  |  |  |  |  | 
| 291 |  |  |  |  |  |  | L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBIx-Class-Schema-PopulateMore> | 
| 292 |  |  |  |  |  |  |  | 
| 293 |  |  |  |  |  |  | I will be notified, and then you'll automatically be notified of progress on | 
| 294 |  |  |  |  |  |  | your bug as I make changes. | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | =head1 SUPPORT | 
| 297 |  |  |  |  |  |  |  | 
| 298 |  |  |  |  |  |  | You can find documentation for this module with the perldoc command. | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | perldoc DBIx::Class::Schema::PopulateMore | 
| 301 |  |  |  |  |  |  |  | 
| 302 |  |  |  |  |  |  | You can also look for information at: | 
| 303 |  |  |  |  |  |  |  | 
| 304 |  |  |  |  |  |  | =over 4 | 
| 305 |  |  |  |  |  |  |  | 
| 306 |  |  |  |  |  |  | =item * RT: CPAN's request tracker | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=DBIx-Class-Schema-PopulateMore> | 
| 309 |  |  |  |  |  |  |  | 
| 310 |  |  |  |  |  |  | =item * AnnoCPAN: Annotated CPAN documentation | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | L<http://annocpan.org/dist/DBIx-Class-Schema-PopulateMore> | 
| 313 |  |  |  |  |  |  |  | 
| 314 |  |  |  |  |  |  | =item * CPAN Ratings | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | L<http://cpanratings.perl.org/d/DBIx-Class-Schema-PopulateMore> | 
| 317 |  |  |  |  |  |  |  | 
| 318 |  |  |  |  |  |  | =item * Search CPAN | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | L<http://search.cpan.org/dist/DBIx-Class-Schema-PopulateMore> | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | =back | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | =head1 ACKNOWLEDGEMENTS | 
| 325 |  |  |  |  |  |  |  | 
| 326 |  |  |  |  |  |  | Thanks to the entire L<DBIx::Class> team for providing such a useful and | 
| 327 |  |  |  |  |  |  | extensible ORM.  Also thanks to the L<Moose> developers for making it fun and | 
| 328 |  |  |  |  |  |  | easy to write beautiful Perl. | 
| 329 |  |  |  |  |  |  |  | 
| 330 |  |  |  |  |  |  | =head1 COPYRIGHT & LICENSE | 
| 331 |  |  |  |  |  |  |  | 
| 332 |  |  |  |  |  |  | Copyright 2011, John Napiorkowski | 
| 333 |  |  |  |  |  |  |  | 
| 334 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it under | 
| 335 |  |  |  |  |  |  | the same terms as Perl itself. | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | =cut | 
| 338 |  |  |  |  |  |  |  | 
| 339 |  |  |  |  |  |  | 1; |