| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # This is the code for Config::Apple::Profile::Payload::Common. | 
| 2 |  |  |  |  |  |  | # For Copyright, please see the bottom of the file. | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | package Config::Apple::Profile::Payload::Common; | 
| 5 |  |  |  |  |  |  |  | 
| 6 | 7 |  |  | 7 |  | 53690 | use 5.14.4; | 
|  | 7 |  |  |  |  | 25 |  | 
|  | 7 |  |  |  |  | 263 |  | 
| 7 | 7 |  |  | 7 |  | 39 | use strict; | 
|  | 7 |  |  |  |  | 12 |  | 
|  | 7 |  |  |  |  | 231 |  | 
| 8 | 7 |  |  | 7 |  | 35 | use warnings FATAL => 'all'; | 
|  | 7 |  |  |  |  | 13 |  | 
|  | 7 |  |  |  |  | 404 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | our $VERSION = '0.55'; | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 7 |  |  | 7 |  | 5240 | use Data::GUID; | 
|  | 7 |  |  |  |  | 148678 |  | 
|  | 7 |  |  |  |  | 56 |  | 
| 13 | 7 |  |  | 7 |  | 9315 | use Encode; | 
|  | 7 |  |  |  |  | 89173 |  | 
|  | 7 |  |  |  |  | 803 |  | 
| 14 | 7 |  |  | 7 |  | 7162 | use Mac::PropertyList; | 
|  | 7 |  |  |  |  | 310417 |  | 
|  | 7 |  |  |  |  | 479 |  | 
| 15 | 7 |  |  | 7 |  | 940 | use Readonly; | 
|  | 7 |  |  |  |  | 3190 |  | 
|  | 7 |  |  |  |  | 411 |  | 
| 16 | 7 |  |  | 7 |  | 46 | use Scalar::Util; | 
|  | 7 |  |  |  |  | 15 |  | 
|  | 7 |  |  |  |  | 277 |  | 
| 17 | 7 |  |  | 7 |  | 7388 | use Tie::Hash; # Also gives us Tie::StdHash | 
|  | 7 |  |  |  |  | 6648 |  | 
|  | 7 |  |  |  |  | 207 |  | 
| 18 | 7 |  |  | 7 |  | 6153 | use Try::Tiny; | 
|  | 7 |  |  |  |  | 28189 |  | 
|  | 7 |  |  |  |  | 555 |  | 
| 19 | 7 |  |  | 7 |  | 6324 | use version 0.77; | 
|  | 7 |  |  |  |  | 15911 |  | 
|  | 7 |  |  |  |  | 47 |  | 
| 20 | 7 |  |  | 7 |  | 5758 | use Config::Apple::Profile::Payload::Tie::Root; | 
|  | 7 |  |  |  |  | 29 |  | 
|  | 7 |  |  |  |  | 288 |  | 
| 21 | 7 |  |  | 7 |  | 49 | use Config::Apple::Profile::Payload::Types qw(:all); | 
|  | 7 |  |  |  |  | 15 |  | 
|  | 7 |  |  |  |  | 1461 |  | 
| 22 | 7 |  |  | 7 |  | 5498 | use Config::Apple::Profile::Payload::Types::Serialize qw(serialize); | 
|  | 7 |  |  |  |  | 21 |  | 
|  | 7 |  |  |  |  | 493 |  | 
| 23 | 7 |  |  | 7 |  | 46 | use Config::Apple::Profile::Payload::Types::Validation; | 
|  | 7 |  |  |  |  | 13 |  | 
|  | 7 |  |  |  |  | 304 |  | 
| 24 | 7 |  |  | 7 |  | 4481 | use Config::Apple::Profile::Targets qw(:all); | 
|  | 7 |  |  |  |  | 24 |  | 
|  | 7 |  |  |  |  | 1266 |  | 
| 25 |  |  |  |  |  |  |  | 
| 26 |  |  |  |  |  |  |  | 
| 27 |  |  |  |  |  |  | =encoding utf8 | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | =head1 NAME | 
| 30 |  |  |  |  |  |  |  | 
| 31 |  |  |  |  |  |  | Config::Apple::Profile::Payload::Common - Base class for almost all payload | 
| 32 |  |  |  |  |  |  | types, with common payload keys. | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | This module serves two purposes. | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | First, this module contains code to store payload data, to validate | 
| 39 |  |  |  |  |  |  | client-provided data, and to export payload data as a plist. | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | Second, this module defines the payload keys that are common to almost all | 
| 42 |  |  |  |  |  |  | payload types.  Specific payload types (classes) will include these common | 
| 43 |  |  |  |  |  |  | payload types in their own payload type-specific list. | 
| 44 |  |  |  |  |  |  |  | 
| 45 |  |  |  |  |  |  | Ideally, each payload type will be implemented as a class that subclasses this | 
| 46 |  |  |  |  |  |  | one, using this class to do all of the work, leaving the subclass to | 
| 47 |  |  |  |  |  |  | define the payload keys specific to that subclass. | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | =head1 CLASS METHODS | 
| 50 |  |  |  |  |  |  |  | 
| 51 |  |  |  |  |  |  | =head2 new() | 
| 52 |  |  |  |  |  |  |  | 
| 53 |  |  |  |  |  |  | Returns a new object. | 
| 54 |  |  |  |  |  |  |  | 
| 55 |  |  |  |  |  |  | =cut | 
| 56 |  |  |  |  |  |  |  | 
| 57 |  |  |  |  |  |  | sub new { | 
| 58 | 222 |  |  | 222 | 1 | 253202 | my ($self) = @_; | 
| 59 | 222 |  | 33 |  |  | 1301 | my $class = ref($self) || $self; | 
| 60 |  |  |  |  |  |  |  | 
| 61 |  |  |  |  |  |  | # The list of payload keys is defined in the class.  Let's make it easy | 
| 62 |  |  |  |  |  |  | # to reference for the instance. | 
| 63 |  |  |  |  |  |  | ## no critic (ProhibitNoStrict) | 
| 64 | 7 |  |  | 7 |  | 49 | no strict 'refs'; | 
|  | 7 |  |  |  |  | 16 |  | 
|  | 7 |  |  |  |  | 375 |  | 
| 65 |  |  |  |  |  |  | ## use critic | 
| 66 | 222 |  |  |  |  | 337 | my $keys = \%{"${class}::payloadKeys"}; | 
|  | 222 |  |  |  |  | 988 |  | 
| 67 | 7 |  |  | 7 |  | 43 | use strict 'refs'; | 
|  | 7 |  |  |  |  | 16 |  | 
|  | 7 |  |  |  |  | 10816 |  | 
| 68 |  |  |  |  |  |  |  | 
| 69 |  |  |  |  |  |  | # We're going to leverage Perl's hash-handling code to make payload keys | 
| 70 |  |  |  |  |  |  | # easy for the Perl programmer to access. | 
| 71 | 222 |  |  |  |  | 445 | my %payload; | 
| 72 |  |  |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | # Prepare out object | 
| 74 | 222 |  |  |  |  | 1026 | my $object = bless { | 
| 75 |  |  |  |  |  |  | 'keys' => $keys, | 
| 76 |  |  |  |  |  |  | 'payload' => \%payload, | 
| 77 |  |  |  |  |  |  | }, $class; | 
| 78 |  |  |  |  |  |  |  | 
| 79 |  |  |  |  |  |  | # Now that have the object, we can tie up the hash.  YES, this will create | 
| 80 |  |  |  |  |  |  | # a circular reference, which TIEHASH will deal with. | 
| 81 | 222 |  |  |  |  | 1603 | tie %payload, 'Config::Apple::Profile::Payload::Tie::Root', $object; | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | # Return the prepared object! | 
| 84 | 222 |  |  |  |  | 784 | return $object; | 
| 85 |  |  |  |  |  |  | } | 
| 86 |  |  |  |  |  |  |  | 
| 87 |  |  |  |  |  |  |  | 
| 88 |  |  |  |  |  |  | =head1 INSTANCE METHODS | 
| 89 |  |  |  |  |  |  |  | 
| 90 |  |  |  |  |  |  | =head2 keys() | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | Returns a hashref that contains the list of payload keys recognized by this | 
| 93 |  |  |  |  |  |  | instance. | 
| 94 |  |  |  |  |  |  |  | 
| 95 |  |  |  |  |  |  | B  The hashref points to a hash that is read-only.  Any attempts to | 
| 96 |  |  |  |  |  |  | modify will cause your code to die.  You probably want to look at C. | 
| 97 |  |  |  |  |  |  |  | 
| 98 |  |  |  |  |  |  | =cut | 
| 99 |  |  |  |  |  |  |  | 
| 100 |  |  |  |  |  |  | sub keys { | 
| 101 | 1350 |  |  | 1350 | 1 | 1921 | my ($self) = @_; | 
| 102 | 1350 |  |  |  |  | 9189 | return $self->{keys}; | 
| 103 |  |  |  |  |  |  | } | 
| 104 |  |  |  |  |  |  |  | 
| 105 |  |  |  |  |  |  |  | 
| 106 |  |  |  |  |  |  | =head2 payload() | 
| 107 |  |  |  |  |  |  |  | 
| 108 |  |  |  |  |  |  | Returns a hashref that can be used to access the contents of the payload.  This | 
| 109 |  |  |  |  |  |  | is a reference to a tied hash, so you can not use it as liberally as a normal | 
| 110 |  |  |  |  |  |  | hash.  The only keys that will be accepted are those listed under | 
| 111 |  |  |  |  |  |  | L. | 
| 112 |  |  |  |  |  |  |  | 
| 113 |  |  |  |  |  |  | The following exception may be thrown when accessing a hash key: | 
| 114 |  |  |  |  |  |  |  | 
| 115 |  |  |  |  |  |  | =over 4 | 
| 116 |  |  |  |  |  |  |  | 
| 117 |  |  |  |  |  |  | =item Config::Apple::Profile::Payload::Common::KeyInvalid | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | Thrown when attempting to access a payload key that is not valid for this | 
| 120 |  |  |  |  |  |  | payload. | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | =back | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | If a payload key is valid, but has not been set, then C is returned. | 
| 125 |  |  |  |  |  |  |  | 
| 126 |  |  |  |  |  |  | The following exceptions may be thrown when setting a hash key: | 
| 127 |  |  |  |  |  |  |  | 
| 128 |  |  |  |  |  |  | =over 4 | 
| 129 |  |  |  |  |  |  |  | 
| 130 |  |  |  |  |  |  | =item Config::Apple::Profile::Payload::Common::KeyInvalid | 
| 131 |  |  |  |  |  |  |  | 
| 132 |  |  |  |  |  |  | Thrown when attempting to access a payload key that is not valid for this | 
| 133 |  |  |  |  |  |  | payload. | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | =item Config::Apple::Profile::Payload::Common::ValueInvalid | 
| 136 |  |  |  |  |  |  |  | 
| 137 |  |  |  |  |  |  | Thrown when attempting to set an invalid value for this payload key. | 
| 138 |  |  |  |  |  |  |  | 
| 139 |  |  |  |  |  |  | =back | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | You can use C to test if a particular key is valid for this payload, and | 
| 142 |  |  |  |  |  |  | you can use C to test if a particular key actually has a value defined. | 
| 143 |  |  |  |  |  |  | Take note that calling C with an invalid key name will always return | 
| 144 |  |  |  |  |  |  | false. | 
| 145 |  |  |  |  |  |  |  | 
| 146 |  |  |  |  |  |  | You can use C to delete a key. | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  | =cut | 
| 149 |  |  |  |  |  |  |  | 
| 150 |  |  |  |  |  |  | sub payload { | 
| 151 | 312 |  |  | 312 | 1 | 1594 | my ($self) = @_; | 
| 152 | 312 |  |  |  |  | 2862 | return $self->{payload}; | 
| 153 |  |  |  |  |  |  | } | 
| 154 |  |  |  |  |  |  |  | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  | =head2 plist([C => C, ...]) | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | Return a copy of this payload, represented as a L object. | 
| 159 |  |  |  |  |  |  | All strings will be in UTF-8, and all Data entries will be Base64-encoded. | 
| 160 |  |  |  |  |  |  | This method is used when assembling payloads into a profile. | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | There are two ways to get string output from the plist object: | 
| 163 |  |  |  |  |  |  |  | 
| 164 |  |  |  |  |  |  | # First, get your plist object from the payload | 
| 165 |  |  |  |  |  |  | my $plist = $payload->plist(); | 
| 166 |  |  |  |  |  |  |  | 
| 167 |  |  |  |  |  |  | # If you just want the  XML element and its contents, do this... | 
| 168 |  |  |  |  |  |  | my $dict_element = $plist->write; | 
| 169 |  |  |  |  |  |  |  | 
| 170 |  |  |  |  |  |  | # If you want the complete XML plist, with headers, do this... | 
| 171 |  |  |  |  |  |  | use Mac::PropertyList; | 
| 172 |  |  |  |  |  |  | my $complete_plist = Mac::PropertyList::plist_as_string($plist); | 
| 173 |  |  |  |  |  |  |  | 
| 174 |  |  |  |  |  |  | Several parameters can be provided, which will influence how this method runs. | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | =over 4 | 
| 177 |  |  |  |  |  |  |  | 
| 178 |  |  |  |  |  |  | =item target | 
| 179 |  |  |  |  |  |  |  | 
| 180 |  |  |  |  |  |  | If C (a value from L) is provided, | 
| 181 |  |  |  |  |  |  | then this will be taken into account when exporting.  Only payload keys that | 
| 182 |  |  |  |  |  |  | are used on the specified target will be included in the output. | 
| 183 |  |  |  |  |  |  |  | 
| 184 |  |  |  |  |  |  | The C option controls what happens if keys are excluded. | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | =item version | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | If C (a version string) is provided, then only payload keys that work | 
| 189 |  |  |  |  |  |  | on the specified version will be included in the output. | 
| 190 |  |  |  |  |  |  |  | 
| 191 |  |  |  |  |  |  | If C is provided, then C must also be set, but C can | 
| 192 |  |  |  |  |  |  | be set without setting C. | 
| 193 |  |  |  |  |  |  |  | 
| 194 |  |  |  |  |  |  | The C option controls what happens if keys are excluded. | 
| 195 |  |  |  |  |  |  |  | 
| 196 |  |  |  |  |  |  | =item completeness | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | If C is set to a true value, and keys are excluded because of | 
| 199 |  |  |  |  |  |  | C or C, then C will throw an exception.  If set to a | 
| 200 |  |  |  |  |  |  | false value, or if not set at all, then no exceptions will be thrown, and a | 
| 201 |  |  |  |  |  |  | less-than-complete (but still valid) plist will be returned. | 
| 202 |  |  |  |  |  |  |  | 
| 203 |  |  |  |  |  |  | =back | 
| 204 |  |  |  |  |  |  |  | 
| 205 |  |  |  |  |  |  | The following exceptions may be thrown: | 
| 206 |  |  |  |  |  |  |  | 
| 207 |  |  |  |  |  |  | =over 4 | 
| 208 |  |  |  |  |  |  |  | 
| 209 |  |  |  |  |  |  | =item Config::Apple::Profile::Exception::KeyRequired | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | Thrown if a required key has not been set. | 
| 212 |  |  |  |  |  |  |  | 
| 213 |  |  |  |  |  |  | =item Config::Apple::Profile::Exception::Incomplete | 
| 214 |  |  |  |  |  |  |  | 
| 215 |  |  |  |  |  |  | Thrown if payload keys are being excluded from the output because of C | 
| 216 |  |  |  |  |  |  | or C. | 
| 217 |  |  |  |  |  |  |  | 
| 218 |  |  |  |  |  |  | =back | 
| 219 |  |  |  |  |  |  |  | 
| 220 |  |  |  |  |  |  | =cut | 
| 221 |  |  |  |  |  |  |  | 
| 222 |  |  |  |  |  |  | sub plist { | 
| 223 | 90 |  |  | 90 | 1 | 16068 | my $self = $_[0]; | 
| 224 |  |  |  |  |  |  |  | 
| 225 |  |  |  |  |  |  | # Process parameters | 
| 226 | 90 |  |  |  |  | 159 | my %params; | 
| 227 | 90 |  |  |  |  | 410 | for (my $i = 1; $i < scalar(@_); $i += 2) { | 
| 228 | 0 |  |  |  |  | 0 | my ($name, $value) = @_[$i,$i+1]; | 
| 229 |  |  |  |  |  |  |  | 
| 230 |  |  |  |  |  |  | # We have three parameters possible.  Process each one | 
| 231 | 0 | 0 |  |  |  | 0 | if ($name eq 'target') { | 
|  |  | 0 |  |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 232 | 0 | 0 | 0 |  |  | 0 | unless (   ($value == $TargetIOS) | 
| 233 |  |  |  |  |  |  | || ($value == $TargetMACOSX) | 
| 234 |  |  |  |  |  |  | ) { | 
| 235 | 0 |  |  |  |  | 0 | die "Invalid target $value"; | 
| 236 |  |  |  |  |  |  | } | 
| 237 | 0 |  |  |  |  | 0 | $params{target} = $value; | 
| 238 |  |  |  |  |  |  | } | 
| 239 |  |  |  |  |  |  |  | 
| 240 |  |  |  |  |  |  | elsif ($name eq 'version') { | 
| 241 |  |  |  |  |  |  | try { | 
| 242 | 0 |  |  | 0 |  | 0 | $params{version} = version->parse($value); | 
| 243 |  |  |  |  |  |  | } | 
| 244 |  |  |  |  |  |  | catch { | 
| 245 | 0 |  |  | 0 |  | 0 | die "Failed to parse version $value"; | 
| 246 |  |  |  |  |  |  | } | 
| 247 | 0 |  |  |  |  | 0 | } | 
| 248 |  |  |  |  |  |  |  | 
| 249 |  |  |  |  |  |  | elsif ($name eq 'completeness') { | 
| 250 | 0 | 0 |  |  |  | 0 | $params{completeness} = ($value ? 1 : 0); | 
| 251 |  |  |  |  |  |  | } | 
| 252 |  |  |  |  |  |  | } # Done inputting parameters | 
| 253 |  |  |  |  |  |  |  | 
| 254 |  |  |  |  |  |  | # Catch someone setting version without setting target | 
| 255 | 90 | 50 | 33 |  |  | 337 | if (   (exists $params{version}) | 
| 256 |  |  |  |  |  |  | && (!exists $params{target}) | 
| 257 |  |  |  |  |  |  | ) { | 
| 258 | 0 |  |  |  |  | 0 | die "Version has been set, but no target was provided"; | 
| 259 |  |  |  |  |  |  | } | 
| 260 |  |  |  |  |  |  |  | 
| 261 |  |  |  |  |  |  | # We're done with parameter processing and validation; do some work! | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | # Prepare a hash that will be turned into the dictionary | 
| 264 | 90 |  |  |  |  | 130 | my %dict; | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | # Go through each key that could exist, and skip the ones that are undef. | 
| 267 | 90 |  |  |  |  | 457 | Readonly my $keys => $self->keys(); | 
| 268 | 90 |  |  |  |  | 11140 | Readonly my $payload => $self->payload(); | 
| 269 | 90 |  |  |  |  | 9155 | foreach my $key (CORE::keys(%$keys)) { | 
| 270 |  |  |  |  |  |  | # If the key isn't set, then skip it | 
| 271 | 199 | 100 |  |  |  | 2697 | next unless defined($payload->{$key}); | 
| 272 |  |  |  |  |  |  |  | 
| 273 |  |  |  |  |  |  | # If target has been set, check it against the key's target | 
| 274 | 196 | 50 |  |  |  | 663 | if (exists $params{target}) { | 
| 275 | 0 | 0 |  |  |  | 0 | if (!exists($keys->{$key}->{targets}->{$params{target}})) { | 
| 276 |  |  |  |  |  |  | # This key isn't used on this target, should we die? | 
| 277 | 0 | 0 | 0 |  |  | 0 | if (   (exists($params{completeness})) | 
| 278 |  |  |  |  |  |  | && ($params{completeness}) | 
| 279 |  |  |  |  |  |  | ) { | 
| 280 | 0 |  |  |  |  | 0 | die "Key $key has been set, but isn't supported on this target"; | 
| 281 |  |  |  |  |  |  | } | 
| 282 |  |  |  |  |  |  |  | 
| 283 |  |  |  |  |  |  | # If we're here, this key isn't used on this target, but we | 
| 284 |  |  |  |  |  |  | # shouldn't die, so just skip the key. | 
| 285 | 0 |  |  |  |  | 0 | next; | 
| 286 |  |  |  |  |  |  | } | 
| 287 |  |  |  |  |  |  |  | 
| 288 |  |  |  |  |  |  | # If we're here, this key is used on this target; check the version! | 
| 289 | 0 |  |  |  |  | 0 | my $key_version = $keys->{$key}->{targets}->{$params{target}}; | 
| 290 | 0 | 0 | 0 |  |  | 0 | if (   (exists($params{version})) | 
| 291 |  |  |  |  |  |  | && ($params{version} < version->parse($key_version)) | 
| 292 |  |  |  |  |  |  | ) { | 
| 293 |  |  |  |  |  |  | # This key is too new for us, should we die? | 
| 294 | 0 | 0 | 0 |  |  | 0 | if (   (exists($params{completeness})) | 
| 295 |  |  |  |  |  |  | && ($params{completeness}) | 
| 296 |  |  |  |  |  |  | ) { | 
| 297 | 0 |  |  |  |  | 0 | die "Key $key is only supported in newer OS versions"; | 
| 298 |  |  |  |  |  |  | } | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  | # If we're here, this key is too new for us, but we shouldn't | 
| 301 |  |  |  |  |  |  | # die, so just skip the key. | 
| 302 | 0 |  |  |  |  | 0 | next; | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | # If we're here, then the version isn't set, or we're new enough! | 
| 306 |  |  |  |  |  |  | } # Done checking target & version | 
| 307 |  |  |  |  |  |  |  | 
| 308 |  |  |  |  |  |  | # Serialize the payload contents as a plist fragment, and store | 
| 309 | 196 |  | 100 |  |  | 561 | $dict{$key} = serialize($keys->{$key}->{type}, | 
| 310 |  |  |  |  |  |  | $payload->{$key}, | 
| 311 |  |  |  |  |  |  | $keys->{$key}->{subtype} || undef | 
| 312 |  |  |  |  |  |  | ); | 
| 313 |  |  |  |  |  |  | } # Done going through each payload key | 
| 314 |  |  |  |  |  |  |  | 
| 315 |  |  |  |  |  |  | # Now that we have a populated $dict, make our final plist object! | 
| 316 | 90 |  |  |  |  | 552 | my $plist = Mac::PropertyList::dict->new(\%dict); | 
| 317 | 90 |  |  |  |  | 1960 | return $plist; | 
| 318 |  |  |  |  |  |  | } | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  |  | 
| 321 |  |  |  |  |  |  | =head2 populate_id() | 
| 322 |  |  |  |  |  |  |  | 
| 323 |  |  |  |  |  |  | Populates the C and C fields, if they are not | 
| 324 |  |  |  |  |  |  | already set.  In addition, if the payload has any keys of type | 
| 325 |  |  |  |  |  |  | C<$PayloadClass>, then C will also be called on them. | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | Sub-classes may decide to override this, so as to add extra functionality. | 
| 328 |  |  |  |  |  |  |  | 
| 329 |  |  |  |  |  |  | =cut | 
| 330 |  |  |  |  |  |  |  | 
| 331 |  |  |  |  |  |  | sub populate_id { | 
| 332 | 0 |  |  | 0 | 1 | 0 | my ($self) = @_; | 
| 333 |  |  |  |  |  |  |  | 
| 334 | 0 |  |  |  |  | 0 | my $keys = $self->keys; | 
| 335 | 0 |  |  |  |  | 0 | my $payload = $self->payload; | 
| 336 |  |  |  |  |  |  |  | 
| 337 |  |  |  |  |  |  | # Go through each key, and check the type | 
| 338 | 0 |  |  |  |  | 0 | foreach my $key (CORE::keys %$keys) { | 
| 339 | 0 |  |  |  |  | 0 | my $type = $keys->{$key}->{type}; | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | # We can call this method on other classes | 
| 342 | 0 | 0 | 0 |  |  | 0 | if (   ($type !~ m/^\d+$/) | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 | 0 |  |  |  |  | 
| 343 |  |  |  |  |  |  | || ($type == $ProfileClass) | 
| 344 |  |  |  |  |  |  | ) { | 
| 345 |  |  |  |  |  |  | # Only populate IDs on objects that exist | 
| 346 | 0 | 0 |  |  |  | 0 | if (defined $payload->{$key}) { | 
| 347 | 0 |  |  |  |  | 0 | my $object = $payload->{$key}; | 
| 348 | 0 |  |  |  |  | 0 | $object->populate_id(); | 
| 349 |  |  |  |  |  |  | } | 
| 350 |  |  |  |  |  |  | } | 
| 351 |  |  |  |  |  |  |  | 
| 352 |  |  |  |  |  |  | # We can fill in UUIDs | 
| 353 |  |  |  |  |  |  | elsif ($type == $ProfileUUID) { | 
| 354 | 0 | 0 |  |  |  | 0 | if (!defined $payload->{$key}) { | 
| 355 |  |  |  |  |  |  | # Make a new (random) GUID | 
| 356 | 0 |  |  |  |  | 0 | $payload->{$key} = new Data::GUID; | 
| 357 |  |  |  |  |  |  | } | 
| 358 |  |  |  |  |  |  | } | 
| 359 |  |  |  |  |  |  |  | 
| 360 |  |  |  |  |  |  | # We can fill in identifiers | 
| 361 |  |  |  |  |  |  | elsif ($type == $ProfileIdentifier) { | 
| 362 | 0 | 0 |  |  |  | 0 | if (!defined $payload->{$key}) { | 
| 363 |  |  |  |  |  |  | # Just make some simple random identifier | 
| 364 | 0 |  |  |  |  | 0 | $payload->{$key} = 'payload' . int(rand(2**30)); | 
| 365 |  |  |  |  |  |  | } | 
| 366 |  |  |  |  |  |  | } | 
| 367 |  |  |  |  |  |  |  | 
| 368 |  |  |  |  |  |  | # If we have an array of objects, we can do them, too! | 
| 369 |  |  |  |  |  |  | elsif (   ($type == $ProfileArray) | 
| 370 |  |  |  |  |  |  | && (   $keys->{$key}->{subtype} !~ m/^\d+$/ | 
| 371 |  |  |  |  |  |  | || $keys->{$key}->{subtype} == $ProfileClass | 
| 372 |  |  |  |  |  |  | ) | 
| 373 |  |  |  |  |  |  | ) { | 
| 374 | 0 |  |  |  |  | 0 | foreach my $item (@{$payload->{$key}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 375 | 0 |  |  |  |  | 0 | $item->populate_id(); | 
| 376 |  |  |  |  |  |  | } | 
| 377 |  |  |  |  |  |  | } | 
| 378 |  |  |  |  |  |  |  | 
| 379 |  |  |  |  |  |  | # If we have an dictionary of objects, we can do them, also! | 
| 380 |  |  |  |  |  |  | elsif (   ($type == $ProfileDict) | 
| 381 |  |  |  |  |  |  | && (   $keys->{$key}->{subtype} !~ m/^\d+$/ | 
| 382 |  |  |  |  |  |  | || $keys->{$key}->{subtype} == $ProfileClass | 
| 383 |  |  |  |  |  |  | ) | 
| 384 |  |  |  |  |  |  | ) { | 
| 385 | 0 |  |  |  |  | 0 | foreach my $item (CORE::keys %{$payload->{$key}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 386 | 0 |  |  |  |  | 0 | $payload->{$key}->{$item}->populate_id(); | 
| 387 |  |  |  |  |  |  | } | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | # That's it!  Move on to the next key | 
| 391 |  |  |  |  |  |  | } | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  |  | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  |  | 
| 396 |  |  |  |  |  |  | =head2 exportable([C]) | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | Returns true if the payload is complete enough to be exported.  In other words, | 
| 399 |  |  |  |  |  |  | all required keys must have values provided. | 
| 400 |  |  |  |  |  |  |  | 
| 401 |  |  |  |  |  |  | If C (a value from L) is provided, | 
| 402 |  |  |  |  |  |  | then this will be taken into account.  For example, a I payload | 
| 403 |  |  |  |  |  |  | will never be exportable to iOS. | 
| 404 |  |  |  |  |  |  |  | 
| 405 |  |  |  |  |  |  | =cut | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | sub exportable { | 
| 408 |  |  |  |  |  |  | ... | 
| 409 | 0 |  |  | 0 | 1 | 0 | } | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | =head2 validate_key($key, $value) | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | Confirm the value provided is valid for the given payload key, and return a | 
| 414 |  |  |  |  |  |  | de-tained copy of C<$value>, or C if the provided value is invalid. | 
| 415 |  |  |  |  |  |  |  | 
| 416 |  |  |  |  |  |  | C<$key> is the name of the payload key being set, and C<$value> is the proposed | 
| 417 |  |  |  |  |  |  | new value.  This class will perform checking for all payload types except for | 
| 418 |  |  |  |  |  |  | Data payloads.  The checks performed will be very basic. | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | Subclasses should override this method to check their keys, and then call | 
| 421 |  |  |  |  |  |  | SUPER::validate_key($self, $key, $value) to check the remaining keys. | 
| 422 |  |  |  |  |  |  |  | 
| 423 |  |  |  |  |  |  | The following exceptions may be thrown: | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | =over 4 | 
| 426 |  |  |  |  |  |  |  | 
| 427 |  |  |  |  |  |  | =item Config::Apple::Profile::Payload::Common::KeyUnknown | 
| 428 |  |  |  |  |  |  |  | 
| 429 |  |  |  |  |  |  | Thrown if the payload key referenced is unknown. | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | =back | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | B  An exception will B be thrown if the value is found to be | 
| 434 |  |  |  |  |  |  | invalid.  This is intentional! | 
| 435 |  |  |  |  |  |  |  | 
| 436 |  |  |  |  |  |  | B  To test the result of this method, you should use C, | 
| 437 |  |  |  |  |  |  | because it's possible for a valid value to be false (for example, 0)! | 
| 438 |  |  |  |  |  |  |  | 
| 439 |  |  |  |  |  |  | =cut | 
| 440 |  |  |  |  |  |  |  | 
| 441 |  |  |  |  |  |  | sub validate_key { | 
| 442 | 235 |  |  | 235 | 1 | 562 | my ($self, $key, $value) = @_; | 
| 443 |  |  |  |  |  |  |  | 
| 444 |  |  |  |  |  |  | # Does our payload key exist? | 
| 445 | 235 | 50 |  |  |  | 1138 | if (!exists $self->keys()->{$key}) { | 
| 446 | 0 |  |  |  |  | 0 | die "Payload key $key is unknown"; | 
| 447 |  |  |  |  |  |  | } | 
| 448 |  |  |  |  |  |  |  | 
| 449 |  |  |  |  |  |  | # At this point, we would have checks for specific payload keys, | 
| 450 |  |  |  |  |  |  | # but our common keys don't need any special checking. | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | # Get our payload key's value type | 
| 453 | 235 |  |  |  |  | 2226 | my $type = $self->keys()->{$key}->{type}; | 
| 454 |  |  |  |  |  |  |  | 
| 455 |  |  |  |  |  |  | # If we are working with a basic type, then call the basic validator! | 
| 456 | 235 | 50 | 100 |  |  | 3413 | if (   ($type == $ProfileString) | 
|  |  |  | 100 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 457 |  |  |  |  |  |  | || ($type == $ProfileNumber) | 
| 458 |  |  |  |  |  |  | || ($type == $ProfileReal) | 
| 459 |  |  |  |  |  |  | || ($type == $ProfileBool) | 
| 460 |  |  |  |  |  |  | || ($type == $ProfileData) | 
| 461 |  |  |  |  |  |  | || ($type == $ProfileDate) | 
| 462 |  |  |  |  |  |  | || ($type == $ProfileNSDataBlob) | 
| 463 |  |  |  |  |  |  | || ($type == $ProfileDict) | 
| 464 |  |  |  |  |  |  | || ($type == $ProfileArray) | 
| 465 |  |  |  |  |  |  | || ($type == $ProfileIdentifier) | 
| 466 |  |  |  |  |  |  | || ($type == $ProfileUUID) | 
| 467 |  |  |  |  |  |  | ) { | 
| 468 | 235 |  |  |  |  | 14675 | return Config::Apple::Profile::Payload::Types::Validation::validate($type, $value); | 
| 469 |  |  |  |  |  |  | } | 
| 470 |  |  |  |  |  |  |  | 
| 471 |  |  |  |  |  |  | # If we're still here, then something's wrong, so fail. | 
| 472 |  |  |  |  |  |  | ## no critic (ProhibitExplicitReturnUndef) | 
| 473 | 0 |  |  |  |  |  | return undef; | 
| 474 |  |  |  |  |  |  | ## use critic | 
| 475 |  |  |  |  |  |  | } | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | =head1 PAYLOAD KEYS | 
| 479 |  |  |  |  |  |  |  | 
| 480 |  |  |  |  |  |  | Every payload type has a certain number of common keys.  Those common keys are | 
| 481 |  |  |  |  |  |  | defined (not stored) in C<%payloadKeys>. | 
| 482 |  |  |  |  |  |  |  | 
| 483 |  |  |  |  |  |  | For general information on payload types, see | 
| 484 |  |  |  |  |  |  | L. | 
| 485 |  |  |  |  |  |  |  | 
| 486 |  |  |  |  |  |  | =head2 C | 
| 487 |  |  |  |  |  |  |  | 
| 488 |  |  |  |  |  |  | A C for this specific payload.  It must be unique. | 
| 489 |  |  |  |  |  |  |  | 
| 490 |  |  |  |  |  |  | =head2 C | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | A C for this specific payload.  It must be unique. | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | =head2 C | 
| 495 |  |  |  |  |  |  |  | 
| 496 |  |  |  |  |  |  | I | 
| 497 |  |  |  |  |  |  |  | 
| 498 |  |  |  |  |  |  | A C that the user will be able to see when looking at the details of the | 
| 499 |  |  |  |  |  |  | profile that is about to be installed. | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | =head2 C | 
| 502 |  |  |  |  |  |  |  | 
| 503 |  |  |  |  |  |  | I | 
| 504 |  |  |  |  |  |  |  | 
| 505 |  |  |  |  |  |  | A C that the user will be able to see when looking at the details of the | 
| 506 |  |  |  |  |  |  | profile that is about to be installed. | 
| 507 |  |  |  |  |  |  |  | 
| 508 |  |  |  |  |  |  | =head2 C | 
| 509 |  |  |  |  |  |  |  | 
| 510 |  |  |  |  |  |  | I | 
| 511 |  |  |  |  |  |  |  | 
| 512 |  |  |  |  |  |  | A C that the user will be able to see when looking at the details of the | 
| 513 |  |  |  |  |  |  | profile that is about to be installed. | 
| 514 |  |  |  |  |  |  |  | 
| 515 |  |  |  |  |  |  | =head2 C | 
| 516 |  |  |  |  |  |  |  | 
| 517 |  |  |  |  |  |  | A C that identifies which type of payload this is.  This value may | 
| 518 |  |  |  |  |  |  | not be set by the client.  Instead, the value is automatically determined based | 
| 519 |  |  |  |  |  |  | on which C class is being used. | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | =head2 C | 
| 522 |  |  |  |  |  |  |  | 
| 523 |  |  |  |  |  |  | A C that identifies the version of the payload type.  This specifies the | 
| 524 |  |  |  |  |  |  | version of the standard, not the client's own revision number.  Right now, all | 
| 525 |  |  |  |  |  |  | payload types have a version number of C<1>. | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | =cut | 
| 528 |  |  |  |  |  |  |  | 
| 529 |  |  |  |  |  |  | Readonly our %payloadKeys => ( | 
| 530 |  |  |  |  |  |  | 'PayloadIdentifier' => { | 
| 531 |  |  |  |  |  |  | type => $ProfileIdentifier, | 
| 532 |  |  |  |  |  |  | description => ('A Java-style reversed-domain-name identifier for' | 
| 533 |  |  |  |  |  |  | . 'this payload.'), | 
| 534 |  |  |  |  |  |  | targets => { | 
| 535 |  |  |  |  |  |  | $TargetIOS => '5.0', | 
| 536 |  |  |  |  |  |  | $TargetMACOSX => '10.7', | 
| 537 |  |  |  |  |  |  | }, | 
| 538 |  |  |  |  |  |  | unique => 1, | 
| 539 |  |  |  |  |  |  | }, | 
| 540 |  |  |  |  |  |  | 'PayloadUUID' => { | 
| 541 |  |  |  |  |  |  | type => $ProfileUUID, | 
| 542 |  |  |  |  |  |  | description => 'A GUID for this payload.', | 
| 543 |  |  |  |  |  |  | targets => { | 
| 544 |  |  |  |  |  |  | $TargetIOS => '5.0', | 
| 545 |  |  |  |  |  |  | $TargetMACOSX => '10.7', | 
| 546 |  |  |  |  |  |  | }, | 
| 547 |  |  |  |  |  |  | unique => 1, | 
| 548 |  |  |  |  |  |  | }, | 
| 549 |  |  |  |  |  |  | 'PayloadDisplayName' => { | 
| 550 |  |  |  |  |  |  | type => $ProfileString, | 
| 551 |  |  |  |  |  |  | description => ('A short string that the user will see when ' | 
| 552 |  |  |  |  |  |  | . 'installing the profile.'), | 
| 553 |  |  |  |  |  |  | targets => { | 
| 554 |  |  |  |  |  |  | $TargetIOS => '5.0', | 
| 555 |  |  |  |  |  |  | $TargetMACOSX => '10.7', | 
| 556 |  |  |  |  |  |  | }, | 
| 557 |  |  |  |  |  |  | optional => 1, | 
| 558 |  |  |  |  |  |  | }, | 
| 559 |  |  |  |  |  |  | 'PayloadDescription' => { | 
| 560 |  |  |  |  |  |  | type => $ProfileString, | 
| 561 |  |  |  |  |  |  | description => "A longer description of the payload's purpose.", | 
| 562 |  |  |  |  |  |  | targets => { | 
| 563 |  |  |  |  |  |  | $TargetIOS => '5.0', | 
| 564 |  |  |  |  |  |  | $TargetMACOSX => '10.7', | 
| 565 |  |  |  |  |  |  | }, | 
| 566 |  |  |  |  |  |  | optional => 1, | 
| 567 |  |  |  |  |  |  | }, | 
| 568 |  |  |  |  |  |  | 'PayloadOrganization' => { | 
| 569 |  |  |  |  |  |  | type => $ProfileString, | 
| 570 |  |  |  |  |  |  | description => "The name of the payload's creator.", | 
| 571 |  |  |  |  |  |  | targets => { | 
| 572 |  |  |  |  |  |  | $TargetIOS => '5.0', | 
| 573 |  |  |  |  |  |  | $TargetMACOSX => '10.7', | 
| 574 |  |  |  |  |  |  | }, | 
| 575 |  |  |  |  |  |  | optional => 1, | 
| 576 |  |  |  |  |  |  | }, | 
| 577 |  |  |  |  |  |  | );  # End of %payloadKeys | 
| 578 |  |  |  |  |  |  |  | 
| 579 |  |  |  |  |  |  |  | 
| 580 |  |  |  |  |  |  | =head1 DEVELOPER NOTES | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | The following sections have information that will be useful to people working | 
| 583 |  |  |  |  |  |  | on the code that makes up this release. | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | =head2 C<%payloadKeys> contents | 
| 586 |  |  |  |  |  |  |  | 
| 587 |  |  |  |  |  |  | The C<%payloadKeys> hash is critical, so it is important to know how it is | 
| 588 |  |  |  |  |  |  | constructed.  To start, each key in the hash is a key that appears in a payload. | 
| 589 |  |  |  |  |  |  | The value corresponding to the key is a hashref, which can contain the following | 
| 590 |  |  |  |  |  |  | keys: | 
| 591 |  |  |  |  |  |  |  | 
| 592 |  |  |  |  |  |  | =over 4 | 
| 593 |  |  |  |  |  |  |  | 
| 594 |  |  |  |  |  |  | =item C | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | This key's value is a value from L. | 
| 597 |  |  |  |  |  |  | It is used to specify the type of data the profile key contains. | 
| 598 |  |  |  |  |  |  |  | 
| 599 |  |  |  |  |  |  | The type is used when creating L objects, and when doing | 
| 600 |  |  |  |  |  |  | value-checking. | 
| 601 |  |  |  |  |  |  |  | 
| 602 |  |  |  |  |  |  | If a payload class uses <$ProfileClass> as a type, then the payload class is | 
| 603 |  |  |  |  |  |  | responsible for providing an instance method named C, which takes | 
| 604 |  |  |  |  |  |  | the payload key name as its only parameter, and returns a new object. | 
| 605 |  |  |  |  |  |  |  | 
| 606 |  |  |  |  |  |  | This key must be present. | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | =item C | 
| 609 |  |  |  |  |  |  |  | 
| 610 |  |  |  |  |  |  | This key is required when C is set to C<$ProfileDict> or C<$ProfileArray>. | 
| 611 |  |  |  |  |  |  |  | 
| 612 |  |  |  |  |  |  | If C is set to C<$ProfileDict>, then C contains the type of | 
| 613 |  |  |  |  |  |  | data stored as values.  That data type will be used for validation, when | 
| 614 |  |  |  |  |  |  | entries are added to the Perl hash representing the dictionary. | 
| 615 |  |  |  |  |  |  |  | 
| 616 |  |  |  |  |  |  | If C is set to C<$ProfileArray>, then C contains the type of | 
| 617 |  |  |  |  |  |  | data stored in the array.  That data type will be used for validation, when | 
| 618 |  |  |  |  |  |  | entries are added to the Perl array. | 
| 619 |  |  |  |  |  |  |  | 
| 620 |  |  |  |  |  |  | If a payload class uses <$ProfileClass> as a subtype, then the payload class is | 
| 621 |  |  |  |  |  |  | responsible for providing an instance method named C, which takes | 
| 622 |  |  |  |  |  |  | the payload key name as its only parameter, and returns a new object. | 
| 623 |  |  |  |  |  |  |  | 
| 624 |  |  |  |  |  |  | For other values of the C key, this key must I be present. | 
| 625 |  |  |  |  |  |  |  | 
| 626 |  |  |  |  |  |  | =item C | 
| 627 |  |  |  |  |  |  |  | 
| 628 |  |  |  |  |  |  | This key's value contains a human-readable description of the profile key.  The | 
| 629 |  |  |  |  |  |  | purpose of this is so that client software can easily enumerate profile keys, | 
| 630 |  |  |  |  |  |  | such as when making a web application. | 
| 631 |  |  |  |  |  |  |  | 
| 632 |  |  |  |  |  |  | This key must be present. | 
| 633 |  |  |  |  |  |  |  | 
| 634 |  |  |  |  |  |  | =item C | 
| 635 |  |  |  |  |  |  |  | 
| 636 |  |  |  |  |  |  | This key's value is a hashref.  Within the hashref, the keys are platform | 
| 637 |  |  |  |  |  |  | identifiers, scalars taken from C.  The value | 
| 638 |  |  |  |  |  |  | for each key is a version object representing the earliest version of the | 
| 639 |  |  |  |  |  |  | named platform's OS which supports this payload key. | 
| 640 |  |  |  |  |  |  |  | 
| 641 |  |  |  |  |  |  | If a platform does not support a particular key at all, that platform should not | 
| 642 |  |  |  |  |  |  | be included in the hashref. | 
| 643 |  |  |  |  |  |  |  | 
| 644 |  |  |  |  |  |  | This key must be present, and the hashref must contain at least one entry. | 
| 645 |  |  |  |  |  |  |  | 
| 646 |  |  |  |  |  |  | =item C | 
| 647 |  |  |  |  |  |  |  | 
| 648 |  |  |  |  |  |  | If this key is present, then this payload key does not have to be present. | 
| 649 |  |  |  |  |  |  | This might mean that a key is completely optional (like C), | 
| 650 |  |  |  |  |  |  | or it might mean that the value will be auto-generated (like C). | 
| 651 |  |  |  |  |  |  |  | 
| 652 |  |  |  |  |  |  | It doesn't matter what this key is set to, its presence is what's important. | 
| 653 |  |  |  |  |  |  |  | 
| 654 |  |  |  |  |  |  | Optional checks are done when L is run, at the very least. | 
| 655 |  |  |  |  |  |  |  | 
| 656 |  |  |  |  |  |  | =item C | 
| 657 |  |  |  |  |  |  |  | 
| 658 |  |  |  |  |  |  | If this key is present, then this payload key's value needs to be unique across | 
| 659 |  |  |  |  |  |  | all payloads in the profile.  This is normally used for things like the UUID and | 
| 660 |  |  |  |  |  |  | the payload identifier, which need to be unique. | 
| 661 |  |  |  |  |  |  |  | 
| 662 |  |  |  |  |  |  | It doesn't matter what this key is set to, its presence is what's important. | 
| 663 |  |  |  |  |  |  |  | 
| 664 |  |  |  |  |  |  | Uniqueness checks are done during profile creation time only. | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | =item C | 
| 667 |  |  |  |  |  |  |  | 
| 668 |  |  |  |  |  |  | If this key is present, then this payload key's value is something that should | 
| 669 |  |  |  |  |  |  | only be transmitted when the profile is encrypted.  This is meant for things | 
| 670 |  |  |  |  |  |  | like passwords, which should not be sent in the clear. | 
| 671 |  |  |  |  |  |  |  | 
| 672 |  |  |  |  |  |  | Right now, none of the code in this release does anything with this key.  It is | 
| 673 |  |  |  |  |  |  | provided solely for future use. | 
| 674 |  |  |  |  |  |  |  | 
| 675 |  |  |  |  |  |  | =item C | 
| 676 |  |  |  |  |  |  |  | 
| 677 |  |  |  |  |  |  | If this key is present, then the corresponding value will be used as the value | 
| 678 |  |  |  |  |  |  | for the payload key.  Any attempts by the user to change the payload key's value | 
| 679 |  |  |  |  |  |  | will throw an exception. | 
| 680 |  |  |  |  |  |  |  | 
| 681 |  |  |  |  |  |  | This is used for things like PayloadVersion and PayloadType, which are fixed. | 
| 682 |  |  |  |  |  |  |  | 
| 683 |  |  |  |  |  |  | =back | 
| 684 |  |  |  |  |  |  |  | 
| 685 |  |  |  |  |  |  | =head1 ACKNOWLEDGEMENTS | 
| 686 |  |  |  |  |  |  |  | 
| 687 |  |  |  |  |  |  | Refer to the L for acknowledgements. | 
| 688 |  |  |  |  |  |  |  | 
| 689 |  |  |  |  |  |  | =head1 AUTHOR | 
| 690 |  |  |  |  |  |  |  | 
| 691 |  |  |  |  |  |  | A. Karl Kornel, C<<  >> | 
| 692 |  |  |  |  |  |  |  | 
| 693 |  |  |  |  |  |  | =head1 COPYRIGHT AND LICENSE | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | Copyright © 2014 A. Karl Kornel. | 
| 696 |  |  |  |  |  |  |  | 
| 697 |  |  |  |  |  |  | This program is free software; you can redistribute it and/or modify it | 
| 698 |  |  |  |  |  |  | under the terms of either: the GNU General Public License as published | 
| 699 |  |  |  |  |  |  | by the Free Software Foundation; or the Artistic License. | 
| 700 |  |  |  |  |  |  |  | 
| 701 |  |  |  |  |  |  | See L for more information. | 
| 702 |  |  |  |  |  |  |  | 
| 703 |  |  |  |  |  |  | =cut | 
| 704 |  |  |  |  |  |  |  | 
| 705 |  |  |  |  |  |  | 1; |