Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 440 lines (309 sloc) 24.004 kB
7d6a323 @tomaz Copied all the changes from the old generating branch.
authored
1 //
2 // GBApplicationSettingsProvider.h
3 // appledoc
4 //
5 // Created by Tomaz Kragelj on 3.10.10.
6 // Copyright (C) 2010, Gentle Bytes. All rights reserved.
7 //
8
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
9 #import "GBCommentComponentsProvider.h"
10 #import "GBApplicationStringsProvider.h"
11
12 @class GBModelBase;
7d6a323 @tomaz Copied all the changes from the old generating branch.
authored
13
14 /** Main application settings provider.
15
16 This object implements `GBApplicationStringsProviding` interface and is used by `GBAppledocApplication` to prepare application-wide settings including factory defaults, global and session values. The main purpose of the class is to simplify `GBAppledocApplication` class by decoupling it from the actual settings providing implementation.
1ab0711 @tomaz Added developers check list for creating new command line switches.
authored
17
18 To create a new setting use the following check list to update `GBApplicationSettingsProvider`:
19
20 1. Create the property here (don't forget about `@synthetize`!).
21 2. Set default value in initializer.
22
23 If the setting should be mapped to command line switch also do the following in `GBAppledocApplication`:
24
25 1. Create a new global string as `static NSString` containing the command line switch name.
26 2. Register the switch to `DDCli` (add negated switch if it's a boolean).
d4a942e @tomaz Added command line switches for warnings on empty descriptions and un…
authored
27 3. Add unit test in `GBAppledocApplicationTesting.m` that validates the switch is properly mapped to setting property (note that boolean switches require testing normal and negated variants!).
1ab0711 @tomaz Added developers check list for creating new command line switches.
authored
28 4. Add KVC setter and map to corresponding property to make the test pass (again booleans require two setters).
29 5. If the switch value uses template placeholders, add unit test in `GBApplicationSettingsProviderTesting.m` that validates the switch is handled.
30 6. If previous point was used, add the code to `replaceAllOccurencesOfPlaceholderStringsInSettingsValues` to make the test pass.
31 7. Add the switch value printout to `printSettingsAndArguments:`.
32 8. Add the switch help printout to `printHelp`.
7d6a323 @tomaz Copied all the changes from the old generating branch.
authored
33 */
a422865 @tomaz Removed GBApplicationSettingsProvider NSCopying.
authored
34 @interface GBApplicationSettingsProvider : NSObject
7d6a323 @tomaz Copied all the changes from the old generating branch.
authored
35
36 ///---------------------------------------------------------------------------------------
37 /// @name Initialization & disposal
38 ///---------------------------------------------------------------------------------------
39
40 /** Returns autoreleased instance of the class.
41 */
42 + (id)provider;
43
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
44 ///---------------------------------------------------------------------------------------
45 /// @name Project values handling
46 ///---------------------------------------------------------------------------------------
47
48 /** Human readable name of the project. */
49 @property (copy) NSString *projectName;
50
51 /** Human readable name of the project company. */
52 @property (copy) NSString *projectCompany;
53
54 /** Human readable version of the project. */
55 @property (copy) NSString *projectVersion;
56
57 /** Company unique identifier, ussualy in the form of reverse domain like _com.company_. */
58 @property (copy) NSString *companyIdentifier;
59
afef3b2 @tomaz Implemented proper docset packaging handling. Relates to #45.
authored
60 /** Project identifier which is derived by normalizing `projectName`. */
61 @property (readonly) NSString *projectIdentifier;
62
63 /** Version identifier which is derived by normalizing `projectVersion`. */
64 @property (readonly) NSString *versionIdentifier;
65
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
66 ///---------------------------------------------------------------------------------------
67 /// @name Documentation set handling
68 ///---------------------------------------------------------------------------------------
69
70 /** Documentation set bundle identifier. */
71 @property (copy) NSString *docsetBundleIdentifier;
72
73 /** Documentation set bundle name. */
74 @property (copy) NSString *docsetBundleName;
75
76 /** Documentation set certificate issuer. */
77 @property (copy) NSString *docsetCertificateIssuer;
78
79 /** Documentation set certificate signer. */
80 @property (copy) NSString *docsetCertificateSigner;
81
82 /** Documentation set description. */
83 @property (copy) NSString *docsetDescription;
84
85 /** Documentation set fallback URL. */
86 @property (copy) NSString *docsetFallbackURL;
87
88 /** Documentation set feed name. */
89 @property (copy) NSString *docsetFeedName;
90
91 /** Documentation set feed URL. */
92 @property (copy) NSString *docsetFeedURL;
93
895b881 @tomaz Fixed published atom file handling. Closes #45.
authored
94 /** Documentation set package URL. */
95 @property (copy) NSString *docsetPackageURL;
96
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
97 /** Documentation set minimum Xcode version. */
98 @property (copy) NSString *docsetMinimumXcodeVersion;
99
100 /** Documentation set platform family. */
101 @property (copy) NSString *docsetPlatformFamily;
102
103 /** Documentation set publisher identifier. */
104 @property (copy) NSString *docsetPublisherIdentifier;
105
106 /** Documentation set publisher name. */
107 @property (copy) NSString *docsetPublisherName;
108
109 /** Documentation set human readble copyright message. */
110 @property (copy) NSString *docsetCopyrightMessage;
111
afef3b2 @tomaz Implemented proper docset packaging handling. Relates to #45.
authored
112 /** The name of the documentation set installed bundle. The folder is generated in `docsetInstallPath`. */
113 @property (copy) NSString *docsetBundleFilename;
114
115 /** The name of the documentation set atom file when generating publishing files. The file is generated in `outputPath`. */
116 @property (copy) NSString *docsetAtomFilename;
117
118 /** The name of the documentation set compressed package file when generating publishing files. The file is generated in `outputPath`. */
119 @property (copy) NSString *docsetPackageFilename;
120
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
121 ///---------------------------------------------------------------------------------------
122 /// @name Paths handling
123 ///---------------------------------------------------------------------------------------
124
125 /** The base path to template files used for generating various output files. */
126 @property (copy) NSString *templatesPath;
127
128 /** The base path of the generated files. */
129 @property (copy) NSString *outputPath;
130
131 /** The path to which documentation set is to be installed. */
132 @property (copy) NSString *docsetInstallPath;
133
134 /** The path to `docsetutil` tool, including tool filename. */
135 @property (copy) NSString *docsetUtilPath;
136
137 /** The list of all full or partial paths to be ignored.
138
139 It's recommended to check if a path string ends with any of the given paths before processing it. This should catch directory and file names properly as directories are processed first.
140 */
141 @property (retain) NSMutableArray *ignoredPaths;
142
143 ///---------------------------------------------------------------------------------------
144 /// @name Behavior handling
145 ///---------------------------------------------------------------------------------------
146
a28b2ff @tomaz Implemented preparing for docset publishing. Closes #45.
authored
147 /* Indicates whether HTML files should be generated or not.
148
149 If `YES`, HTML files are generated in `outputPath` from parsed and processed data. If `NO`, input files are parsed and processed, but nothing is generated.
150
151 @see createDocSet
152 */
153 @property (assign) BOOL createHTML;
154
155 /** Specifies whether documentation set should be created from the HTML files.
156
157 If `YES`, HTML files from html subdirectory in `outputPath` are moved to proper subdirectory within docset output files, then helper files are generated from parsed data. Documentation set files are also indexed. If `NO`, HTML files are left in the output path.
158
d6b842b @tomaz Fixed comment warnings for various objects.
authored
159 @see createHTML
a28b2ff @tomaz Implemented preparing for docset publishing. Closes #45.
authored
160 @see installDocSet
161 @see publishDocSet
162 */
163 @property (assign) BOOL createDocSet;
164
165 /** Specifies whether the documentation set should be installed or not.
166
167 If `YES`, temporary files used for indexing and removed, then documentation set bundle is created from the files from docset output path and is moved to `docsetInstallPath`. If `NO`, all documentation set files are left in output path.
168
169 @see createDocSet
170 @see publishDocSet
171 */
172 @property (assign) BOOL installDocSet;
173
174 /** Specifies whether the documentation set should be prepared for publishing or not.
175
176 If `YES`, installed documentation set is packaged for publishing - an atom feed is created and documentation set is archived. If the atom feed file is alreay found, it is updated with new information. Both, the feed and archived docset files are located within `outputPath`. If `NO`, documentation set is not prepared for publishing.
177
178 @see createDocSet
179 @see installDocSet
180 */
181 @property (assign) BOOL publishDocSet;
182
183 /** Specifies whether intermediate files should be kept in `outputPath` or not.
184
185 If `YES`, all intermediate files (i.e. HTML files and documentation set files) are kept in output path. If `NO`, only final results are kept. This setting not only affects how the files are being handled, it also affects performance. If intermediate files are not kept, appledoc moves files between various generation phases, otherwise it copies them. So it's prefferable to leave this option to `NO`. This option only affects output files, input source files are always left intact!
186 */
187 @property (assign) BOOL keepIntermediateFiles;
188
efce669 @tomaz Implemented optional disabling of first paragraph repeat for members.…
authored
189 /** Indicates whether the first paragraph needs to be repeated within method and property description or not.
190
191 If `YES`, first paragraph is repeated in members description, otherwise not.
192 */
193 @property (assign) BOOL repeatFirstParagraphForMemberDescription;
194
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
195 /* Indicates whether undocumented classes, categories or protocols should be kept or ignored when generating output.
196
197 If `YES` undocumented objects are kept and are used for output generation. If `NO`, these objects are ignored, but only if all their members are also not documented - as soon as a single member is documented, the object is included in output together with all of it's documented members.
198
199 @warning *Note:* Several properties define how undocumented objects are handled: `keepUndocumentedObjects`, `keepUndocumentedMembers` and `findUndocumentedMembersDocumentation`. To better understand how these work together, this is the workflow used when processing parsed objects, prior than passing them to output generators:
200
201 1. If `findUndocumentedMembersDocumentation` is `YES`, all undocumented methods and properties documentation is searched for in known super class hierarchy. If documentation is found in any of the super classes, it is copied to inherited member as well. If `findUndocumentedMembersDocumentation` is `NO`, members are left undocumented and are handled that way in next steps.
202 2. If `keepUndocumentedMembers` is `NO`, all parsed objects' members are iterated over. Any undocumented method or property is removed from class (of course any documentation copied over from super classes in previous step is considered valid too). If `keepUndocumentedMembers` is `NO`, all members are left and if `warnOnUndocumentedMembers` is `YES`, warnings are logged for all undocumented members.
203 3. If `keepUndocumentedObjects` is `NO`, all undocumented classes, categories and protocols that have no documented method or property are also removed. If `keepUndocumentedObjects` is `NO`, all objects are left in the store and are used for output generation and if `warnOnUndocumentedObject` is `YES`, warnings are logged for all undocumented objects.
204
205 @see keepUndocumentedMembers
206 @see findUndocumentedMembersDocumentation;
207 @see warnOnUndocumentedObject
208 */
209 @property (assign) BOOL keepUndocumentedObjects;
210
211 /* Indicates whether undocumented methods or properties should be processed or not.
212
213 If `YES`, undocumented members are still used for output generation. If `NO`, these members are ignored, as if they are not part of the object. Note that this only affects documented objects: if an object is not documented and none of it's members is documented, the object is not processed for output, even if this value is `YES`!
214
215 @warning *Note:* This property works together with `keepUndocumentedObjects` and `findUndocumentedMembersDocumentation`. To understand how they are used, read documentation for `keepUndocumentedObjects`.
216
217 @see keepUndocumentedObjects
218 @see findUndocumentedMembersDocumentation
219 @see warnOnUndocumentedMember
220 */
221 @property (assign) BOOL keepUndocumentedMembers;
222
223 /** Specifies whether undocumented inherited methods or properties should be searched for in known places.
224
225 If `YES`, any undocumented overriden method or property is searched for in known super classes and adopted protocols and if documentation is found there, it is copied over. This works great for objects which would otherwise only show class documentation and no member. It's also how Apple documentation uses. Defaults to `YES`.
226
227 @warning *Note:* This property works together with `keepUndocumentedObjects` and `keepUndocumentedMembers`. To understand how they are used, read documentation for `keepUndocumentedObjects`.
228
229 @see keepUndocumentedObjects
230 @see keepUndocumentedMembers
231 */
232 @property (assign) BOOL findUndocumentedMembersDocumentation;
233
234 /** Indicates whether categories should be merges to classes they extend or not.
235
236 If `YES`, all methods from categories and extensions are merged to their classes. If `NO`, categories are left as independent objects in generated output. This is the main categories merging on/off switch, it merely enables or disables merging, other category merging settings define how exactly the methods from categories and extensions are merged into their classes.
237
238 Default value is `YES` and should be left so as this seems to be the way Apple has it's documentation generated.
239
240 @warning *Important:* Only categories for known project classes are merged. Categories to other framework classes, such as Foundation, AppKit or UIKit are not merged. In other words: only if the class source code is available on any of the given input paths, and is properly documented, it gets it's categories and extension methods merged! Also note that this option affects your documentation links - if any link is pointing to category that's going to be merged, it will be considered invalid link, so it's best to decide whther to merge categories of nor in advance and then consistently use properly formatted links.
241
242 @see keepMergedCategoriesSections
243 @see prefixMergedCategoriesSectionsWithCategoryName
244 */
245 @property (assign) BOOL mergeCategoriesToClasses;
246
247 /** Indicates whether category or extension sections should be preserved when merging into extended class.
248
249 If `YES`, all the sections from category or extension documentation are preserved. In such case, `prefixMergedCategoriesSectionsWithCategoryName` may optionally be used to prefix section name with category name or not. If `NO`, category or extension sections are ignored and a single section with category name is created in the class.
250
251 Default value is `NO`. If you use many sections within the categories, you should probably leave this option unchanged as preserving all category sections might yield fragmented class documentation. Experiment a bit to see what works best for you.
252
253 @warning *Note:* This option is ignored unless `mergeCategoriesToClasses` is used.
254
255 @see prefixMergedCategoriesSectionsWithCategoryName
256 @see mergeCategoriesToClasses
257 */
258 @property (assign) BOOL keepMergedCategoriesSections;
259
260 /** Indicates whether merged section names from categories should be prefixed with category name.
261
262 If `YES`, all merged section names from categories are prefixed with category name to make them more easily identifiable. If `NO`, section names are not changed. The first option is useful in case end users of your code are aware of different categories (if you're writting a framework for example). On the other hand, if you're using categories mostly as a way to split class definition to multiple files, you might want to keep this option off.
263
264 @warning *Note:* This option is ignored unless `mergeCategoriesToClasses` and `keepMergedCategoriesSections` is used. The option is also ignored for extensions; only section names are used for extensions!
265
266 @see keepMergedCategoriesSections
267 @see mergeCategoriesToClasses
268 */
269 @property (assign) BOOL prefixMergedCategoriesSectionsWithCategoryName;
270
271 ///---------------------------------------------------------------------------------------
272 /// @name Warnings handling
273 ///---------------------------------------------------------------------------------------
274
b427cd7 @tomaz Implemented settings for enabling or disabling validation warnings.
authored
275 /** Indicates whether appledoc will warn if `--output` argument is not given.
276
277 Although appledoc still generates output in current directory, it's better to warn the user as in most cases this is not what she wants (for example if appledoc is invoked from Xcode build script, current working directory might point to some unpredicted location). appledoc also writes the exact path that will be used for generating output.
278
279 Note that in case documentation set is installed to Xcode, setting output path is irrelevant as all files from output are moved to locations Xcode uses for finding documentation sets.
280 */
281 @property (assign) BOOL warnOnMissingOutputPathArgument;
282
283 /** Indicates whether appledoc will warn if `--company-id` argument is not given.
284
285 Although appledoc deducts this information from other values, it's better to warn the user as deducted information doesn't necessarily produce correct results.
286
287 Note that the warning is only issued if documentation set creation is requested.
288 */
289 @property (assign) BOOL warnOnMissingCompanyIdentifier;
290
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
291 /** Indicates whether appledoc will warn if it encounters an undocumented class, category or protocol.
292
293 @see warnOnUndocumentedMember
294 */
295 @property (assign) BOOL warnOnUndocumentedObject;
296
4f44437 @tomaz Added settings for enabling or disabling various processing warnings.
authored
297 /** Indicates whether appledoc will warn if it encounters an undocumented method or property.
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
298
299 @see warnOnUndocumentedObject
300 */
301 @property (assign) BOOL warnOnUndocumentedMember;
302
4f44437 @tomaz Added settings for enabling or disabling various processing warnings.
authored
303 /** Indicates whether appledoc will warn if it encounters an empty description (@bug, @warning, example section etc.).
304 */
305 @property (assign) BOOL warnOnEmptyDescription;
306
307 /** Indicates whether appledoc will warn if it encounters unknown directive or styling element.
308 */
309 @property (assign) BOOL warnOnUnknownDirective;
310
7aa04af @tomaz Implemented optional disabling of invalid cross reference warnings.
authored
311 /** Indicates whether invalid cross reference should result in warning or not. */
312 @property (assign) BOOL warnOnInvalidCrossReference;
313
3a8da42 @tomaz Implemented optional disabling for missing method arguments warnings.
authored
314 /** Indicates whether missing method argument descriptions in comments should result in warnings or not. */
315 @property (assign) BOOL warnOnMissingMethodArgument;
316
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
317 ///---------------------------------------------------------------------------------------
318 /// @name Application-wide HTML helpers
319 ///---------------------------------------------------------------------------------------
320
d7ece46 @tomaz Fixed HTML and XML handling within example blocks. Closes #54.
authored
321 /** Returns a new string by escaping the given HTML.
322
323 @param string HTML string to escape.
324 @return Returns escaped HTML string.
325 */
326 - (NSString *)stringByEscapingHTML:(NSString *)string;
327
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
328 /** Returns HTML reference name for the given object.
329
330 This should only be used for creating anchors that need to be referenced from other parts of the same HTML file. The method works for top-level objects as well as their members.
331
332 @param object The object for which to return reference name.
333 @return Returns the reference name of the object.
334 @exception NSException Thrown if the given object is `nil`.
335 @see htmlReferenceForObject:fromSource:
336 @see htmlReferenceForObjectFromIndex:
337 */
338 - (NSString *)htmlReferenceNameForObject:(GBModelBase *)object;
339
340 /** Returns relative HTML reference to the given object from the context of the given source object.
341
342 This is useful for generating hrefs from one object HTML file to another. This is the swiss army knife king of a method for all hrefs generation. It works for any kind of links:
343
344 - Index to top-level object (if source is `nil`).
345 - Index to a member of a top-level object (if source is `nil`).
346 - Top-level object to same top-level object.
347 - Top-level object to a different top-level object.
348 - Top-level object to one of it's members.
349 - Member object to it's top-level object.
350 - Member object to another top-level object.
351 - Member object to another member of the same top-level object.
352 - Member object to a member of another top-level object.
353
354 @param object The object for which to generate the reference to.
355 @param source The source object from which to generate the reference from or `nil` for index to object reference.
356 @return Returns the reference string.
357 @exception NSException Thrown if object is `nil`.
358 @see htmlReferenceForObjectFromIndex:
359 @see htmlReferenceNameForObject:
360 */
361 - (NSString *)htmlReferenceForObject:(GBModelBase *)object fromSource:(GBModelBase *)source;
362
363 /** Returns relative HTML reference to the given object from the context of index file.
364
365 This is simply a helper method for `htmlReferenceForObject:fromSource:`, passing the given object as object parameter and `nil` as source.
366
d6b842b @tomaz Fixed comment warnings for various objects.
authored
367 @param object The object for which to generate the reference to.
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
368 @return Returns the reference string.
369 @exception NSException Thrown if object is `nil`.
370 @see htmlReferenceForObject:fromSource:
371 @see htmlReferenceNameForObject:
372 */
373 - (NSString *)htmlReferenceForObjectFromIndex:(GBModelBase *)object;
374
375 /** The file extension for html files.
376 */
377 @property (readonly) NSString *htmlExtension;
378
379 ///---------------------------------------------------------------------------------------
380 /// @name Helper methods
381 ///---------------------------------------------------------------------------------------
382
383 /** Replaces all occurences of placeholder strings in all related values of the receiver.
384
385 This message should be sent once all the values have been set. It is a convenience method that prepares all values that can use placeholder strings. From this point on, the rest of the application can simply use properties to get final values instead of sending `stringByReplacingOccurencesOfPlaceholdersInString:` all the time.
386
387 Note that `stringByReplacingOccurencesOfPlaceholdersInString:` is still available for cases where placeholder strings may be used elsewhere (template files for example).
388
389 @see stringByReplacingOccurencesOfPlaceholdersInString:
390 */
391 - (void)replaceAllOccurencesOfPlaceholderStringsInSettingsValues;
392
393 /** Replaces all placeholders occurences in the given string.
394
395 This method provides application-wide string placeholders replacement functionality. It replaces all known placeholders with actual values from the receiver. Placeholders are identified by a dollar mark, followed by placeholder name. The following placeholders are supported (note that case is important!):
396
f18465e @tomaz Fixed HTML footer year and last update strings. Closes #49.
authored
397 - `%PROJECT`: Replaced by `projectName` value.
398 - `%PROJECTID`: Replaced by `projectIdentifier` value.
399 - `%COMPANY`: Replaced by `projectCompany` value.
400 - `%COMPANYID`: Replaced by `companyIdentifier` value.
401 - `%VERSION`: Replaced by `projectVersion` value.
402 - `%VERSIONID`: Replaced by `versionIdentifier` value.
403 - `%DOCSETBUNDLEFILENAME`: Replaced by `docsetBundleFilename` value.
404 - `%DOCSETATOMFILENAME`: Replaced by `docsetAtomFilename` value.
405 - `%DOCSETPACKAGEFILENAME`: Replaced by `docsetPackageFilename` value.
406 - `%YEAR`: Replaced by current year as four digit string.
407 - `%UPDATEDATE`: Replaced by current date in the form of year, month and day with format `YYYY-MM-DD`. For example `2010-11-30`.
1586e38 @tomaz Refactored settings handling by removing GBApplicationSettingsProvidi…
authored
408
409 @param string The string to replace placeholder occurences in.
410 @return Returns new string with all placeholder occurences replaced.
411 @see replaceAllOccurencesOfPlaceholderStringsInSettingsValues
412 */
413 - (NSString *)stringByReplacingOccurencesOfPlaceholdersInString:(NSString *)string;
414
415 ///---------------------------------------------------------------------------------------
416 /// @name Helper classes
417 ///---------------------------------------------------------------------------------------
418
419 /** Returns the `GBCommentComponentsProvider` object that identifies comment components. */
420 @property (retain) GBCommentComponentsProvider *commentComponents;
421
422 /** Returns the `GBApplicationStringsProvider` object that specifies all string templates used for output generation. */
423 @property (retain) GBApplicationStringsProvider *stringTemplates;
424
7d6a323 @tomaz Copied all the changes from the old generating branch.
authored
425 @end
1f23b3e @tomaz Refactored template placeholder strings by moving them to global cons…
authored
426
427 #pragma -
428
429 extern NSString *kGBTemplatePlaceholderCompanyID;
430 extern NSString *kGBTemplatePlaceholderProjectID;
431 extern NSString *kGBTemplatePlaceholderVersionID;
432 extern NSString *kGBTemplatePlaceholderProject;
433 extern NSString *kGBTemplatePlaceholderCompany;
434 extern NSString *kGBTemplatePlaceholderVersion;
435 extern NSString *kGBTemplatePlaceholderDocSetBundleFilename;
436 extern NSString *kGBTemplatePlaceholderDocSetAtomFilename;
437 extern NSString *kGBTemplatePlaceholderDocSetPackageFilename;
438 extern NSString *kGBTemplatePlaceholderYear;
439 extern NSString *kGBTemplatePlaceholderUpdateDate;
Something went wrong with that request. Please try again.