examples: annotate examples
[nit.git] / src / platform / xcode_templates.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 # Templates and other services to create XCode projects
16 module xcode_templates
17
18 import template
19
20 import platform
21 import compiler::abstract_compiler
22
23 redef class Sys
24 # Map to identify the PBX file type for a given file extension
25 private var pbx_file_types: Map[String, String] is lazy do
26 var map = new HashMap[String, String]
27
28 # Source code
29 map["m"] = "sourcecode.c.objc"
30 map["c"] = "sourcecode.c.c"
31 map["h"] = "sourcecode.c.h"
32 map["cpp"] = "sourcecode.cpp.cpp"
33 map["hpp"] = "sourcecode.cpp.h"
34 map["vsh"] = "sourcecode.glsl"
35 map["fsh"] = "sourcecode.glsl"
36
37 # Images
38 map["png"] = "image.png"
39 map["gif"] = "image.gif"
40 map["jpg"] = "image.jpeg"
41 map["jpeg"] = "image.jpeg"
42 map["pdf"] = "image.pdf"
43 map["ico"] = "image.ico"
44
45 # Others
46 map["app"] = "wrapper.application"
47 map["plist"] = "text.plist.xml"
48 map["storyboard"] = "file.storyboard"
49 map["xib"] = "file.xib"
50 map["xcassets"] = "folder.assetcatalog"
51 map["xctest"] = "wrapper.cfbundle"
52
53 return map
54 end
55
56 # Generator of PBX UUIDs quique to an execution of the compiler
57 private var pbx_uuid_generator = new PbxUUIDGenerator is lazy
58 end
59
60 # Generator of PBX UUIDs
61 #
62 # PBX UUID are composed of 24 hex characters.
63 # They only need to be unique within the same project.
64 #
65 # This implementation simply counts upward from 0.
66 class PbxUUIDGenerator
67 private var seed = 0
68
69 # Generate a new UUID
70 fun next_uuid: String
71 do
72 seed += 1
73
74 var hex_val = seed.to_hex.to_upper
75 return "0"*(24-hex_val.length) + hex_val
76 end
77 end
78
79 # Reference to a file for the PBX format of a project file
80 #
81 # TODO create subclasses for different file types, this is currently for
82 # compilable source files only.
83 class PbxFile
84
85 # Path to `self`
86 var path: String
87
88 # UUID for build elements
89 private var build_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
90
91 # File reference UUID
92 private var ref_uuid: String = sys.pbx_uuid_generator.next_uuid is lazy
93
94 # Documentation to add besides this file in the template
95 private fun doc: String do return path
96
97 # PBX file type for `self`
98 fun file_type: String
99 do
100 var map = sys.pbx_file_types
101 var ext = path.file_extension
102 if ext != null and map.keys.has(ext) then return map[ext]
103 return "unknown"
104 end
105
106 # PBX description of this file
107 private fun description: Writable do return """
108 {{{ref_uuid}}} /* {{{doc}}} */ = {
109 isa = PBXFileReference;
110 fileEncoding = 4;
111 lastKnownFileType = {{{file_type}}};
112 path = {{{path}}};
113 sourceTree = "<group>";
114 };
115 """
116
117 private fun add_to_project(project: PbxprojectTemplate)
118 do
119 project.source_files.add self
120 project.files.add self
121 end
122 end
123
124 # Template for a PBX project file, usually a `project.pbcproj`
125 #
126 # This file list all information required to build an XCode project.
127 # It would usually be written and read by XCode.
128 # From the command line, xcodebuild can read this file but not write it.
129 #
130 # Information in the file (simplified list):
131 #
132 # * Compilable source files
133 # * Asset files
134 # * Build configurations (Release and debug modes, cflags, etc.)
135 # * List of files composing the project
136 class PbxprojectTemplate
137 super Template
138
139 # Name of the project
140 var name: String
141
142 # All body/implementation source files to be compiled
143 private var source_files = new Array[PbxFile]
144
145 # All asset files added to the app package
146 private var asset_files = new Array[PbxFile]
147
148 # All files used by this project
149 private var files = new Array[PbxFile]
150
151 # Add `file` to this project
152 fun add_file(file: PbxFile) do file.add_to_project(self)
153
154 redef fun rendering
155 do
156 add """
157 // !$*UTF8*$!
158 {
159 archiveVersion = 1;
160 classes = {
161 };
162 objectVersion = 46;
163 objects = {
164
165 /* Begin PBXBuildFile section */
166 """
167
168 # List build files (compilable sources and assets) with their reference UUID
169 for array in [source_files, asset_files] do for file in array do add """
170 {{{file.build_uuid}}} /* {{{file.doc}}} */ = {
171 isa = PBXBuildFile;
172 fileRef = {{{file.ref_uuid}}} /* {{{file.doc}}} */;
173 };
174 """
175
176 add """
177 0FDD07A21C6F8E0E006FF70E /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0FDD07A11C6F8E0E006FF70E /* LaunchScreen.storyboard */; };
178 /* End PBXBuildFile section */
179
180 /* Begin PBXFileReference section */
181 /* Static generated files */
182 AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */ = {
183 isa = PBXFileReference;
184 explicitFileType = wrapper.application;
185 includeInIndex = 0;
186 path = {{{name}}}.app;
187 sourceTree = BUILT_PRODUCTS_DIR;
188 };
189 AF9F83D01A5F0D21004B62C0 /* Info.plist */ = {
190 isa = PBXFileReference;
191 lastKnownFileType = text.plist.xml;
192 path = Info.plist;
193 sourceTree = "<group>";
194 };
195 AF9F83DE1A5F0D21004B62C0 /* Base */ = {
196 isa = PBXFileReference;
197 lastKnownFileType = file.storyboard;
198 name = Base;
199 path = Base.lproj/Main.storyboard;
200 sourceTree = "<group>";
201 };
202 AF9F83E01A5F0D21004B62C0 /* Images.xcassets */ = {
203 isa = PBXFileReference;
204 lastKnownFileType = folder.assetcatalog;
205 path = Images.xcassets;
206 sourceTree = "<group>";
207 };
208 AF9F83E31A5F0D21004B62C0 /* Base */ = {
209 isa = PBXFileReference;
210 lastKnownFileType = file.xib;
211 name = Base;
212 path = Base.lproj/LaunchScreen.xib;
213 sourceTree = "<group>";
214 };
215
216 /* Changing generated files */
217 """
218 # Describe all known files
219 for file in files do add file.description
220
221 add """
222 0FDD07A11C6F8E0E006FF70E /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
223 /* End PBXFileReference section */
224
225 /* Begin PBXFrameworksBuildPhase section */
226 AF9F83C91A5F0D21004B62C0 /* Frameworks */ = {
227 isa = PBXFrameworksBuildPhase;
228 buildActionMask = 2147483647;
229 files = (
230 );
231 runOnlyForDeploymentPostprocessing = 0;
232 };
233 /* End PBXFrameworksBuildPhase section */
234
235 /* Begin PBXGroup section */
236 AF9F83C31A5F0D21004B62C0 = {
237 isa = PBXGroup;
238 children = (
239 AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */,
240 AF9F83CD1A5F0D21004B62C0 /* Products */,
241 0FDD07A11C6F8E0E006FF70E /* LaunchScreen.storyboard */,
242 );
243 sourceTree = "<group>";
244 };
245 AF9F83CD1A5F0D21004B62C0 /* Products */ = {
246 isa = PBXGroup;
247 children = (
248 AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */,
249 );
250 name = Products;
251 sourceTree = "<group>";
252 };
253 AF9F83CE1A5F0D21004B62C0 /* {{{name}}} */ = {
254 isa = PBXGroup;
255 children = (
256 """
257 # Reference all known files
258 for file in files do add """
259 {{{file.ref_uuid}}} /* {{{file.doc}}} */,
260 """
261
262 add """
263 );
264 path = {{{name}}};
265 sourceTree = "<group>";
266 };
267 /* End PBXGroup section */
268
269 /* Begin PBXNativeTarget section */
270 AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */ = {
271 isa = PBXNativeTarget;
272 buildConfigurationList = AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */;
273 buildPhases = (
274 AF9F83C81A5F0D21004B62C0 /* Sources */,
275 AF9F83C91A5F0D21004B62C0 /* Frameworks */,
276 AF9F83CA1A5F0D21004B62C0 /* Resources */,
277 );
278 buildRules = (
279 );
280 dependencies = (
281 );
282 name = {{{name}}};
283 productName = {{{name}}};
284 productReference = AF9F83CC1A5F0D21004B62C0 /* {{{name}}}.app */;
285 productType = "com.apple.product-type.application";
286 };
287 /* End PBXNativeTarget section */
288
289 /* Begin PBXProject section */
290 AF9F83C41A5F0D21004B62C0 /* Project object */ = {
291 isa = PBXProject;
292 attributes = {
293 LastUpgradeCheck = 0610;
294 TargetAttributes = {
295 AF9F83CB1A5F0D21004B62C0 = {
296 CreatedOnToolsVersion = 6.1.1;
297 };
298 };
299 };
300 buildConfigurationList = AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */;
301 compatibilityVersion = "Xcode 3.2";
302 developmentRegion = English;
303 hasScannedForEncodings = 0;
304 knownRegions = (
305 en,
306 Base,
307 );
308 mainGroup = AF9F83C31A5F0D21004B62C0;
309 productRefGroup = AF9F83CD1A5F0D21004B62C0 /* Products */;
310 projectDirPath = "";
311 projectRoot = "";
312 targets = (
313 AF9F83CB1A5F0D21004B62C0 /* {{{name}}} */,
314 );
315 };
316 /* End PBXProject section */
317
318 /* Begin PBXResourcesBuildPhase section */
319 AF9F83CA1A5F0D21004B62C0 /* Resources */ = {
320 isa = PBXResourcesBuildPhase;
321 buildActionMask = 2147483647;
322 files = (
323 """
324 # Reference all asset files by their build UUID
325 for file in asset_files do add """
326 {{{file.build_uuid}}} /* {{{file.doc}}} */,
327 """
328
329 add """
330 0FDD07A21C6F8E0E006FF70E /* LaunchScreen.storyboard in Resources */,
331 );
332 runOnlyForDeploymentPostprocessing = 0;
333 };
334 /* End PBXResourcesBuildPhase section */
335
336 /* Begin PBXSourcesBuildPhase section */
337 AF9F83C81A5F0D21004B62C0 /* Sources */ = {
338 isa = PBXSourcesBuildPhase;
339 buildActionMask = 2147483647;
340 files = (
341 """
342 # Reference all compilable source files by their build UUID
343 for file in source_files do add """
344 {{{file.build_uuid}}} /* {{{file.doc}}} */,
345 """
346 add """
347 );
348 runOnlyForDeploymentPostprocessing = 0;
349 };
350 /* End PBXSourcesBuildPhase section */
351
352 /* Begin XCBuildConfiguration section */
353 AF9F83F11A5F0D21004B62C0 /* Debug */ = {
354 isa = XCBuildConfiguration;
355 buildSettings = {
356 ALWAYS_SEARCH_USER_PATHS = NO;
357 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
358 CLANG_CXX_LIBRARY = "libc++";
359 CLANG_ENABLE_MODULES = YES;
360 CLANG_ENABLE_OBJC_ARC = YES;
361 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
362 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
363 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
364 COPY_PHASE_STRIP = NO;
365 ENABLE_STRICT_OBJC_MSGSEND = YES;
366 GCC_C_LANGUAGE_STANDARD = gnu99;
367 GCC_DYNAMIC_NO_PIC = NO;
368 GCC_OPTIMIZATION_LEVEL = 0;
369 GCC_PREPROCESSOR_DEFINITIONS = (
370 "DEBUG=1",
371 "$(inherited)",
372 );
373 GCC_SYMBOLS_PRIVATE_EXTERN = NO;
374 GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
375 GCC_WARN_UNDECLARED_SELECTOR = YES;
376 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
377 IPHONEOS_DEPLOYMENT_TARGET = 8.1;
378 MTL_ENABLE_DEBUG_INFO = YES;
379 ONLY_ACTIVE_ARCH = YES;
380 SDKROOT = iphoneos;
381 TARGETED_DEVICE_FAMILY = "1,2";
382 };
383 name = Debug;
384 };
385 AF9F83F21A5F0D21004B62C0 /* Release */ = {
386 isa = XCBuildConfiguration;
387 buildSettings = {
388 ALWAYS_SEARCH_USER_PATHS = NO;
389 CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
390 CLANG_CXX_LIBRARY = "libc++";
391 CLANG_ENABLE_MODULES = YES;
392 CLANG_ENABLE_OBJC_ARC = YES;
393 CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
394 CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
395 "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
396 COPY_PHASE_STRIP = YES;
397 ENABLE_NS_ASSERTIONS = NO;
398 ENABLE_STRICT_OBJC_MSGSEND = YES;
399 GCC_C_LANGUAGE_STANDARD = gnu99;
400 GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
401 GCC_WARN_UNDECLARED_SELECTOR = YES;
402 GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
403 IPHONEOS_DEPLOYMENT_TARGET = 8.1;
404 MTL_ENABLE_DEBUG_INFO = NO;
405 SDKROOT = iphoneos;
406 TARGETED_DEVICE_FAMILY = "1,2";
407 VALIDATE_PRODUCT = YES;
408 };
409 name = Release;
410 };
411 AF9F83F41A5F0D21004B62C0 /* Debug */ = {
412 isa = XCBuildConfiguration;
413 buildSettings = {
414 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
415 INFOPLIST_FILE = {{{name}}}/Info.plist;
416 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
417 PRODUCT_NAME = "$(TARGET_NAME)";
418 };
419 name = Debug;
420 };
421 AF9F83F51A5F0D21004B62C0 /* Release */ = {
422 isa = XCBuildConfiguration;
423 buildSettings = {
424 ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
425 INFOPLIST_FILE = {{{name}}}/Info.plist;
426 LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
427 PRODUCT_NAME = "$(TARGET_NAME)";
428 };
429 name = Release;
430 };
431 /* End XCBuildConfiguration section */
432
433 /* Begin XCConfigurationList section */
434 AF9F83C71A5F0D21004B62C0 /* Build configuration list for PBXProject "{{{name}}}" */ = {
435 isa = XCConfigurationList;
436 buildConfigurations = (
437 AF9F83F11A5F0D21004B62C0 /* Debug */,
438 AF9F83F21A5F0D21004B62C0 /* Release */,
439 );
440 defaultConfigurationIsVisible = 0;
441 defaultConfigurationName = Release;
442 };
443 AF9F83F31A5F0D21004B62C0 /* Build configuration list for PBXNativeTarget "{{{name}}}" */ = {
444 isa = XCConfigurationList;
445 buildConfigurations = (
446 AF9F83F41A5F0D21004B62C0 /* Debug */,
447 AF9F83F51A5F0D21004B62C0 /* Release */,
448 );
449 defaultConfigurationIsVisible = 0;
450 };
451 /* End XCConfigurationList section */
452 };
453 rootObject = AF9F83C41A5F0D21004B62C0 /* Project object */;
454 }
455 """
456 end
457 end
458
459 # Template for a property list used by XCode for iOS projects
460 class PlistTemplate
461 super Template
462
463 # Value of CFBundleName, pretty name of the application
464 var product_name: String
465
466 # Value of CFBundleIdentifier, namespace of the app
467 var bundle_identifier: String
468
469 # Value of CFBundleShortVersionString, human readable version
470 var short_version: String
471
472 # Value of CFBundleVersion, often a revision number
473 var bundle_version: String
474
475 redef fun rendering
476 do
477 add """
478 <?xml version="1.0" encoding="UTF-8"?>
479 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
480 <plist version="1.0">
481 <dict>
482 <key>CFBundleDevelopmentRegion</key>
483 <string>en</string>
484 <key>CFBundleExecutable</key>
485 <string>$(EXECUTABLE_NAME)</string>
486 <key>CFBundleIdentifier</key>
487 <string>{{{bundle_identifier}}}</string>
488 <key>CFBundleInfoDictionaryVersion</key>
489 <string>6.0</string>
490 <key>CFBundleName</key>
491 <string>{{{product_name}}}</string>
492 <key>CFBundlePackageType</key>
493 <string>APPL</string>
494 <key>CFBundleShortVersionString</key>
495 <string>{{{short_version}}}</string>
496 <key>CFBundleSignature</key>
497 <string>????</string>
498 <key>CFBundleVersion</key>
499 <string>{{{bundle_version}}}</string>
500 <key>LSRequiresIPhoneOS</key>
501 <true/>
502 <key>UIRequiredDeviceCapabilities</key>
503 <array>
504 <string>armv7</string>
505 </array>
506 <key>UISupportedInterfaceOrientations</key>
507 <array>
508 <string>UIInterfaceOrientationPortrait</string>
509 <string>UIInterfaceOrientationLandscapeLeft</string>
510 <string>UIInterfaceOrientationLandscapeRight</string>
511 </array>
512 <key>UISupportedInterfaceOrientations~ipad</key>
513 <array>
514 <string>UIInterfaceOrientationPortrait</string>
515 <string>UIInterfaceOrientationPortraitUpsideDown</string>
516 <string>UIInterfaceOrientationLandscapeLeft</string>
517 <string>UIInterfaceOrientationLandscapeRight</string>
518 </array>
519
520 <key>UILaunchStoryboardName</key>
521 <string>LaunchScreen</string>
522
523 <key>NSAppTransportSecurity</key>
524 <dict>
525 <key>NSAllowsArbitraryLoads</key><true/>
526 </dict>
527 </dict>
528 </plist>
529 """
530 end
531 end
532
533 # Template for the loading screen to generate `LaunchScreen.storyboard`
534 class LaunchScreenStoryboardTemplate
535 super Template
536
537 # Large text to show in the center of the loading screen
538 var title = "" is writable
539
540 # Text to show at the bottom of the loading screen
541 var subtitle = "" is writable
542
543 # TODO make this more customizable by moving the subviews block as an attribute
544 # or by allowing to pass a custom file from the ` res/` folder.
545
546 redef fun rendering
547 do
548 add """
549 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
550 <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9531" systemVersion="15D21" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" initialViewController="01J-lp-oVM">
551 <dependencies>
552 <deployment identifier="iOS"/>
553 <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9529"/>
554 <capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
555 </dependencies>
556 <scenes>
557 <!--View Controller-->
558 <scene sceneID="EHf-IW-A2E">
559 <objects>
560 <viewController id="01J-lp-oVM" sceneMemberID="viewController">
561 <layoutGuides>
562 <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
563 <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
564 </layoutGuides>
565 <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
566 <rect key="frame" x="0.0" y="0.0" width="600" height="600"/>
567 <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
568 <subviews>
569 <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="{{{subtitle}}}" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd">
570 <rect key="frame" x="20" y="559" width="560" height="21"/>
571 <fontDescription key="fontDescription" type="boldSystem" pointSize="17"/>
572 <color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
573 <nil key="highlightedColor"/>
574 </label>
575 <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="{{{title}}}" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
576 <rect key="frame" x="20" y="176" width="560" height="43"/>
577 <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
578 <color key="textColor" red="0.0" green="0.5" blue="1" alpha="1" colorSpace="calibratedRGB"/>
579 <nil key="highlightedColor"/>
580 </label>
581 </subviews>
582 <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
583 <constraints>
584 <constraint firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
585 <constraint firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
586 <constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="SfN-ll-jLj"/>
587 <constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
588 <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
589 <constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" constant="20" symbolic="YES" id="x7j-FC-K8j"/>
590 </constraints>
591 </view>
592 </viewController>
593 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
594 </objects>
595 <point key="canvasLocation" x="53" y="375"/>
596 </scene>
597 </scenes>
598 </document>"""
599 end
600 end