├── WeatherApp
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── cloud-sun.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── Preview Content
│ ├── Preview Assets.xcassets
│ │ └── Contents.json
│ ├── weatherData.json
│ └── ModelData.swift
├── WeatherAppApp.swift
├── Views
│ ├── LoadingView.swift
│ ├── WelcomeView.swift
│ ├── ContentView.swift
│ └── WeatherView.swift
├── Extensions.swift
├── Managers
│ ├── LocationManager.swift
│ └── WeatherManager.swift
└── WeatherComponent
│ └── WeatherRow.swift
├── WeatherApp.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── mucha.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
└── project.pbxproj
└── README.md
/WeatherApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/WeatherApp/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/WeatherApp/Assets.xcassets/AppIcon.appiconset/cloud-sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mnaibei/WeatherApp/HEAD/WeatherApp/Assets.xcassets/AppIcon.appiconset/cloud-sun.png
--------------------------------------------------------------------------------
/WeatherApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/WeatherApp/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/WeatherApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "cloud-sun.png",
5 | "idiom" : "universal",
6 | "platform" : "ios",
7 | "size" : "1024x1024"
8 | }
9 | ],
10 | "info" : {
11 | "author" : "xcode",
12 | "version" : 1
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/WeatherApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/WeatherApp/WeatherAppApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WeatherAppApp.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 29/09/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct WeatherAppApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/WeatherApp.xcodeproj/xcuserdata/mucha.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | WeatherApp.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/WeatherApp/Views/LoadingView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LoadingView.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 29/09/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct LoadingView: View {
11 | var body: some View {
12 | ProgressView()
13 | .progressViewStyle(CircularProgressViewStyle(tint: .white))
14 | .frame(maxWidth: .infinity, maxHeight: .infinity)
15 | }
16 | }
17 |
18 | struct LoadingView_Previews: PreviewProvider {
19 | static var previews: some View {
20 | LoadingView()
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/WeatherApp/Extensions.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Extensions.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 30/09/2022.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | extension Double{
12 | func roundDouble()-> String{
13 | return String(format: "%.0f", self)
14 | }
15 | }
16 |
17 | extension View{
18 | func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View{
19 | clipShape(RoundedCorner(radius: radius, corners: corners))
20 | }
21 | }
22 |
23 | // Custom RoundedCorner shape used for cornerRadius extension above
24 | struct RoundedCorner: Shape {
25 | var radius: CGFloat = .infinity
26 | var corners: UIRectCorner = .allCorners
27 |
28 | func path(in rect: CGRect) -> Path {
29 | let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
30 | return Path(path.cgPath)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/WeatherApp/Preview Content/weatherData.json:
--------------------------------------------------------------------------------
1 | {
2 | "coord": {
3 | "lon": 36.8167,
4 | "lat": -1.2833
5 | },
6 | "weather": [
7 | {
8 | "id": 803,
9 | "main": "Clouds",
10 | "description": "broken clouds",
11 | "icon": "04d"
12 | }
13 | ],
14 | "base": "stations",
15 | "main": {
16 | "temp": 22.81,
17 | "feels_like": 22.48,
18 | "temp_min": 22.62,
19 | "temp_max": 23.31,
20 | "pressure": 1021,
21 | "humidity": 51
22 | },
23 | "visibility": 10000,
24 | "wind": {
25 | "speed": 6.69,
26 | "deg": 140
27 | },
28 | "clouds": {
29 | "all": 75
30 | },
31 | "dt": 1664534653,
32 | "sys": {
33 | "type": 1,
34 | "id": 2558,
35 | "country": "KE",
36 | "sunrise": 1664507951,
37 | "sunset": 1664551579
38 | },
39 | "timezone": 10800,
40 | "id": 184745,
41 | "name": "Nairobi",
42 | "cod": 200
43 | }
44 |
--------------------------------------------------------------------------------
/WeatherApp/Managers/LocationManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // LocationManager.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 29/09/2022.
6 | //
7 |
8 | import Foundation
9 | import CoreLocation
10 |
11 | class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
12 | let manager = CLLocationManager()
13 |
14 | @Published var location: CLLocationCoordinate2D?
15 | @Published var isLoading = false
16 |
17 | override init() {
18 | super.init()
19 | manager.delegate = self
20 | }
21 | func requestLocation(){
22 | isLoading = true
23 | manager.requestLocation()
24 | }
25 | func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
26 | location = locations.first?.coordinate
27 | isLoading = false
28 | }
29 | func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
30 | print("Error getting your Location", error)
31 | isLoading = false
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/WeatherApp/Preview Content/ModelData.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ModelData.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 30/09/2022.
6 | //
7 |
8 | import Foundation
9 |
10 | // If you wish to Archive this project, move this file outside of the Preview Content folder, as this folder is not taken into consideration by the Xcode Archive
11 | var previewWeather: ResponseBody = load("weatherData.json")
12 |
13 | func load(_ filename: String) -> T {
14 | let data: Data
15 |
16 | guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
17 | else {
18 | fatalError("Couldn't find \(filename) in main bundle.")
19 | }
20 |
21 | do {
22 | data = try Data(contentsOf: file)
23 | } catch {
24 | fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
25 | }
26 |
27 | do {
28 | let decoder = JSONDecoder()
29 | return try decoder.decode(T.self, from: data)
30 | } catch {
31 | fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/WeatherApp/WeatherComponent/WeatherRow.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WeatherRow.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 30/09/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct WeatherRow: View {
11 | var logo: String
12 | var name: String
13 | var value: String
14 |
15 | var body: some View {
16 | HStack(spacing: 20) {
17 | Image(systemName: logo)
18 | .font(.title2)
19 | .frame(width: 20, height: 20)
20 | .padding()
21 | .background(Color(hue: 1.0, saturation: 0.0, brightness: 0.888))
22 | .cornerRadius(50)
23 |
24 |
25 | VStack(alignment: .leading, spacing: 8) {
26 | Text(name)
27 | .font(.caption)
28 |
29 | Text(value)
30 | .bold()
31 | .font(.title)
32 | }
33 | }
34 | }
35 | }
36 |
37 | struct WeatherRow_Previews: PreviewProvider {
38 | static var previews: some View {
39 | WeatherRow(logo: "thermometer", name: "Feels like", value: "8°")
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/WeatherApp/Views/WelcomeView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WelcomeView.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 29/09/2022.
6 | //
7 |
8 | import SwiftUI
9 | import CoreLocationUI
10 |
11 | struct WelcomeView: View {
12 | @EnvironmentObject var locationManager:
13 | LocationManager
14 |
15 |
16 | var body: some View {
17 | VStack{
18 | VStack(spacing: 20){
19 | Text("Weather App")
20 | .bold().font(.title)
21 |
22 | Text("Share Location")
23 | .padding()
24 | }
25 | .multilineTextAlignment(.center)
26 | .padding()
27 |
28 | LocationButton(.shareCurrentLocation) {
29 | locationManager.requestLocation()
30 | }
31 | .cornerRadius(30)
32 | .symbolVariant(.fill)
33 | .foregroundColor(.black)
34 |
35 | }
36 | .frame(maxWidth: .infinity, maxHeight: .infinity)
37 | }
38 | }
39 |
40 | struct WelcomeView_Previews: PreviewProvider {
41 | static var previews: some View {
42 | WelcomeView()
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/WeatherApp/Views/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 29/09/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ContentView: View {
11 | @StateObject var locationManager = LocationManager()
12 | var weatherManager = WeatherManager()
13 | @State var weather: ResponseBody?
14 |
15 | var body: some View {
16 | VStack{
17 | if let location = locationManager.location{
18 | if let weather = weather{
19 | WeatherView(weather: weather)
20 | } else{
21 | LoadingView()
22 | .task {
23 | do{
24 | weather = try await weatherManager.getCurrentWeather(latitude: location.latitude, longitude: location.longitude)
25 |
26 | }catch{
27 | print("error getting weather: \(error)")
28 | }
29 | }
30 |
31 | }
32 | }
33 | else{
34 | if locationManager.isLoading{
35 | LoadingView()
36 | }else{
37 | WelcomeView()
38 | .environmentObject(locationManager)
39 | }
40 | }
41 | }
42 | .background(Color(hue: 0.679, saturation: 0.956, brightness: 0.441))
43 | .preferredColorScheme(.dark)
44 | }
45 | }
46 |
47 | struct ContentView_Previews: PreviewProvider {
48 | static var previews: some View {
49 | ContentView()
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/WeatherApp/Managers/WeatherManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WeatherManager.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 29/09/2022.
6 | //
7 |
8 | import Foundation
9 | import CoreLocation
10 |
11 | class WeatherManager{
12 | func getCurrentWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> ResponseBody{
13 | guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?lat=\(latitude)&lon=\(longitude)&appid=\("YourAPIKEY")&units=metric") else {fatalError("Missing URL")}
14 |
15 | let urlRequest = URLRequest(url: url)
16 |
17 | let(data, response) = try await URLSession.shared.data(for: urlRequest)
18 | guard (response as? HTTPURLResponse)?.statusCode == 200 else{ fatalError("Error fetching data")}
19 | let decodeData = try JSONDecoder().decode(ResponseBody.self, from: data)
20 |
21 | return decodeData
22 | }
23 | }
24 | // Model of the response body we get from calling the OpenWeather API
25 | struct ResponseBody: Decodable {
26 | var coord: CoordinatesResponse
27 | var weather: [WeatherResponse]
28 | var main: MainResponse
29 | var name: String
30 | var wind: WindResponse
31 |
32 | struct CoordinatesResponse: Decodable {
33 | var lon: Double
34 | var lat: Double
35 | }
36 |
37 | struct WeatherResponse: Decodable {
38 | var id: Double
39 | var main: String
40 | var description: String
41 | var icon: String
42 | }
43 |
44 | struct MainResponse: Decodable {
45 | var temp: Double
46 | var feels_like: Double
47 | var temp_min: Double
48 | var temp_max: Double
49 | var pressure: Double
50 | var humidity: Double
51 | }
52 |
53 | struct WindResponse: Decodable {
54 | var speed: Double
55 | var deg: Double
56 | }
57 | }
58 |
59 | extension ResponseBody.MainResponse {
60 | var feelsLike: Double { return feels_like }
61 | var tempMin: Double { return temp_min }
62 | var tempMax: Double { return temp_max }
63 | }
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |

6 |
7 |
8 |
Weather App
9 |
10 |
11 |
12 |
13 |
14 | # 📗 Table of Contents
15 |
16 | - [📖 About the Project](#about-project)
17 | - [🛠 Built With](#built-with)
18 | - [Tech Stack](#tech-stack)
19 | - [Key Features](#key-features)
20 | - [💻 Getting Started](#getting-started)
21 | - [Setup](#setup)
22 | - [Prerequisites](#prerequisites)
23 | - [Usage](#usage)
24 | - [👥 Authors](#authors)
25 | - [🔭 Future Features](#future-features)
26 | - [🤝 Contributing](#contributing)
27 | - [⭐️ Show your support](#support)
28 | - [🙏 Acknowledgements](#acknowledgements)
29 | - [❓ FAQ (OPTIONAL)](#faq)
30 | - [📝 License](#license)
31 |
32 |
33 |
34 | # 📖 Weather App
35 |
36 | > This is a weather app for iOS built using Swift
37 |
38 | ## 🛠 Built With
39 |
40 | ### Tech Stack
41 |
42 | > Swift
43 |
44 | (back to top)
45 |
46 |
49 |
50 | ### Key Features
51 |
52 | - **[Weather Tracked during the day]**
53 |
54 | (back to top)
55 |
56 |
57 |
58 | ## 💻 Getting Started
59 |
60 | To get a local copy up and running, follow these steps.
61 |
62 | Some pictures available below
63 | 
64 |
65 | https://user-images.githubusercontent.com/69506217/193301008-ae9f5f5b-76a4-405f-be72-fdd2c6a6f5f7.mp4
66 |
67 | ### Prerequisites
68 |
69 | In order to run this project you need:
70 |
71 | ```sh
72 | sudo apt install git-all
73 | ```
74 |
75 | ### Setup
76 |
77 | Clone this repository to your desired folder:
78 |
79 | ```sh
80 | cd my-folder
81 | git clone git@github.com:mnaibei/weatherapp.git
82 | ```
83 |
84 | ### Usage
85 |
86 | To run the project, execute the following command:
87 |
88 | ```sh
89 | Open open xcode and run
90 | ```
91 |
92 | (back to top)
93 |
94 |
95 |
96 | ## 👥 Authors
97 |
98 | 👤 **Mucha Naibei**
99 |
100 | - GitHub: [mnaibei](https://github.com/mnaibei)
101 | - Twitter: [MNaibei\_](https://twitter.com/mnaibei_)
102 | - LinkedIn: [Mucha Julius](https://linkedin.com/in/mucha-julius)
103 |
104 | (back to top)
105 |
106 |
107 |
108 | ## 🔭 Future Features
109 |
110 | - [ ] **[More Cities]**
111 |
112 | (back to top)
113 |
114 |
115 |
116 | ## 🤝 Contributing
117 |
118 | Contributions, issues, and feature requests are welcome!
119 |
120 | Feel free to check the [issues page](../../issues/).
121 |
122 | (back to top)
123 |
124 |
125 |
126 | ## ⭐️ Show your support
127 |
128 | If you like this project give me a follow
129 |
130 | (back to top)
131 |
132 |
133 |
134 | ## 🙏 Acknowledgments
135 |
136 | I would like to thank Mdawida Homestay
137 |
138 | (back to top)
139 |
140 |
141 |
142 | ## 📝 License
143 |
144 | This project is [MIT](https://github.com/mnaibei/mdawidahomestay/blob/dev/LICENSE) licensed.
145 |
146 | (back to top)
147 |
148 |
--------------------------------------------------------------------------------
/WeatherApp/Views/WeatherView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WeatherView.swift
3 | // WeatherApp
4 | //
5 | // Created by Mucha Naibei on 30/09/2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct WeatherView: View {
11 | var weather: ResponseBody
12 |
13 |
14 | var body: some View {
15 | ZStack(alignment: .leading){
16 | VStack{
17 | VStack(alignment: .leading, spacing: 5){
18 | Text(weather.name)
19 | .bold() .font(.title)
20 | Text("Today,\(Date().formatted(.dateTime.month().day().hour().minute()))")
21 | .fontWeight(.light)
22 | }
23 |
24 | .frame(maxWidth: .infinity, alignment: .leading)
25 | Spacer()
26 |
27 | VStack{
28 | HStack{
29 | VStack(spacing: 20){
30 | Image(systemName: "cloud")
31 | .font(.system(size: 40))
32 | Text(weather.weather[0].main)
33 | }
34 | .frame(width: 150, alignment: .leading)
35 |
36 | Spacer()
37 |
38 |
39 | Text(weather.main.feelsLike.roundDouble() + "°")
40 | .font(.system(size: 100))
41 | .fontWeight(.bold)
42 | .padding()
43 | }
44 | Spacer()
45 | .frame(height: 80)
46 |
47 | AsyncImage(url: URL(string: "https://cdn.pixabay.com/photo/2020/01/24/21/33/city-4791269_960_720.png")){
48 | image in image
49 | .resizable()
50 | .aspectRatio(contentMode: .fit)
51 | .frame(width: 350)
52 | }placeholder: {
53 | ProgressView()
54 | }
55 |
56 | Spacer()
57 | }
58 | .frame(maxWidth: .infinity)
59 | }
60 |
61 | .padding()
62 | .frame(maxWidth: .infinity, alignment: .leading)
63 |
64 | VStack{
65 | Spacer()
66 |
67 | VStack(alignment: .leading, spacing: 20){
68 | Text("Today's Weather")
69 | .bold()
70 | .padding(.bottom)
71 |
72 | HStack{
73 | WeatherRow(logo: "thermometer.low", name: "Min Temp", value: (weather.main.tempMin.roundDouble() + "°"))
74 |
75 | Spacer()
76 |
77 | WeatherRow(logo: "thermometer.high", name: "Max Temp", value: (weather.main.tempMax.roundDouble() + "°"))
78 |
79 | }
80 | HStack{
81 | WeatherRow(logo: "wind", name: "Wind Speed", value: (weather.wind.speed.roundDouble() + "m/s"))
82 |
83 | Spacer()
84 |
85 | WeatherRow(logo: "humidity", name: "Humidity", value: (weather.main.humidity.roundDouble() + "%"))
86 |
87 |
88 | }
89 | HStack{
90 | WeatherRow(logo: "aqi.medium", name: "Pressure", value: (weather.main.pressure.roundDouble() + "hpa"))
91 |
92 | Spacer()
93 |
94 | /* WeatherRow(logo: "humidity", name: "Humidity", value: (weather.main..roundDouble() + "%"))*/
95 |
96 |
97 | }
98 |
99 | }
100 | .frame(maxWidth: .infinity, alignment: .leading)
101 | .padding()
102 | .padding(.bottom, 20)
103 | .foregroundColor(Color(hue: 0.679, saturation: 0.956, brightness: 0.441))
104 | .background(.white)
105 | .cornerRadius(20, corners: [.topLeft, .topRight])
106 |
107 | }
108 | }
109 |
110 | .edgesIgnoringSafeArea(.bottom)
111 | .background(Color(hue: 0.679, saturation: 0.956, brightness: 0.441))
112 | .preferredColorScheme(.dark)
113 | }
114 | }
115 |
116 | struct WeatherView_Previews: PreviewProvider {
117 | static var previews: some View {
118 | WeatherView(weather: previewWeather)
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/WeatherApp.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 56;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 058632EB28E6ED1700F26333 /* WeatherView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058632EA28E6ED1700F26333 /* WeatherView.swift */; };
11 | 058632ED28E6EDB900F26333 /* ModelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058632EC28E6EDB900F26333 /* ModelData.swift */; };
12 | 058632EF28E6EE1100F26333 /* weatherData.json in Resources */ = {isa = PBXBuildFile; fileRef = 058632EE28E6EE1100F26333 /* weatherData.json */; };
13 | 058632F128E6F68C00F26333 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058632F028E6F68C00F26333 /* Extensions.swift */; };
14 | 058632F428E7297C00F26333 /* WeatherRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 058632F328E7297C00F26333 /* WeatherRow.swift */; };
15 | 05B37DC528E609A80089594B /* WeatherAppApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B37DC428E609A80089594B /* WeatherAppApp.swift */; };
16 | 05B37DC728E609A80089594B /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B37DC628E609A80089594B /* ContentView.swift */; };
17 | 05B37DC928E609AA0089594B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 05B37DC828E609AA0089594B /* Assets.xcassets */; };
18 | 05B37DCC28E609AA0089594B /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 05B37DCB28E609AA0089594B /* Preview Assets.xcassets */; };
19 | 05B37DD428E60D050089594B /* LocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B37DD328E60D050089594B /* LocationManager.swift */; };
20 | 05B37DD728E60F600089594B /* WelcomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B37DD628E60F600089594B /* WelcomeView.swift */; };
21 | 05B37DD928E61A150089594B /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B37DD828E61A150089594B /* LoadingView.swift */; };
22 | 05B37DDB28E61E520089594B /* WeatherManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05B37DDA28E61E520089594B /* WeatherManager.swift */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXFileReference section */
26 | 058632EA28E6ED1700F26333 /* WeatherView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherView.swift; sourceTree = ""; };
27 | 058632EC28E6EDB900F26333 /* ModelData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelData.swift; sourceTree = ""; };
28 | 058632EE28E6EE1100F26333 /* weatherData.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = weatherData.json; sourceTree = ""; };
29 | 058632F028E6F68C00F26333 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; };
30 | 058632F328E7297C00F26333 /* WeatherRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherRow.swift; sourceTree = ""; };
31 | 05B37DC128E609A80089594B /* WeatherApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WeatherApp.app; sourceTree = BUILT_PRODUCTS_DIR; };
32 | 05B37DC428E609A80089594B /* WeatherAppApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherAppApp.swift; sourceTree = ""; };
33 | 05B37DC628E609A80089594B /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
34 | 05B37DC828E609AA0089594B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
35 | 05B37DCB28E609AA0089594B /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
36 | 05B37DD328E60D050089594B /* LocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; };
37 | 05B37DD628E60F600089594B /* WelcomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeView.swift; sourceTree = ""; };
38 | 05B37DD828E61A150089594B /* LoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingView.swift; sourceTree = ""; };
39 | 05B37DDA28E61E520089594B /* WeatherManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherManager.swift; sourceTree = ""; };
40 | /* End PBXFileReference section */
41 |
42 | /* Begin PBXFrameworksBuildPhase section */
43 | 05B37DBE28E609A80089594B /* Frameworks */ = {
44 | isa = PBXFrameworksBuildPhase;
45 | buildActionMask = 2147483647;
46 | files = (
47 | );
48 | runOnlyForDeploymentPostprocessing = 0;
49 | };
50 | /* End PBXFrameworksBuildPhase section */
51 |
52 | /* Begin PBXGroup section */
53 | 058632F228E7295000F26333 /* WeatherComponent */ = {
54 | isa = PBXGroup;
55 | children = (
56 | 058632F328E7297C00F26333 /* WeatherRow.swift */,
57 | );
58 | path = WeatherComponent;
59 | sourceTree = "";
60 | };
61 | 05B37DB828E609A80089594B = {
62 | isa = PBXGroup;
63 | children = (
64 | 05B37DC328E609A80089594B /* WeatherApp */,
65 | 05B37DC228E609A80089594B /* Products */,
66 | );
67 | sourceTree = "";
68 | };
69 | 05B37DC228E609A80089594B /* Products */ = {
70 | isa = PBXGroup;
71 | children = (
72 | 05B37DC128E609A80089594B /* WeatherApp.app */,
73 | );
74 | name = Products;
75 | sourceTree = "";
76 | };
77 | 05B37DC328E609A80089594B /* WeatherApp */ = {
78 | isa = PBXGroup;
79 | children = (
80 | 058632F228E7295000F26333 /* WeatherComponent */,
81 | 05B37DD528E60EEF0089594B /* Views */,
82 | 05B37DD228E60CEA0089594B /* Managers */,
83 | 05B37DC428E609A80089594B /* WeatherAppApp.swift */,
84 | 05B37DC828E609AA0089594B /* Assets.xcassets */,
85 | 05B37DCA28E609AA0089594B /* Preview Content */,
86 | 058632F028E6F68C00F26333 /* Extensions.swift */,
87 | );
88 | path = WeatherApp;
89 | sourceTree = "";
90 | };
91 | 05B37DCA28E609AA0089594B /* Preview Content */ = {
92 | isa = PBXGroup;
93 | children = (
94 | 05B37DCB28E609AA0089594B /* Preview Assets.xcassets */,
95 | 058632EC28E6EDB900F26333 /* ModelData.swift */,
96 | 058632EE28E6EE1100F26333 /* weatherData.json */,
97 | );
98 | path = "Preview Content";
99 | sourceTree = "";
100 | };
101 | 05B37DD228E60CEA0089594B /* Managers */ = {
102 | isa = PBXGroup;
103 | children = (
104 | 05B37DD328E60D050089594B /* LocationManager.swift */,
105 | 05B37DDA28E61E520089594B /* WeatherManager.swift */,
106 | );
107 | path = Managers;
108 | sourceTree = "";
109 | };
110 | 05B37DD528E60EEF0089594B /* Views */ = {
111 | isa = PBXGroup;
112 | children = (
113 | 05B37DC628E609A80089594B /* ContentView.swift */,
114 | 05B37DD628E60F600089594B /* WelcomeView.swift */,
115 | 05B37DD828E61A150089594B /* LoadingView.swift */,
116 | 058632EA28E6ED1700F26333 /* WeatherView.swift */,
117 | );
118 | path = Views;
119 | sourceTree = "";
120 | };
121 | /* End PBXGroup section */
122 |
123 | /* Begin PBXNativeTarget section */
124 | 05B37DC028E609A80089594B /* WeatherApp */ = {
125 | isa = PBXNativeTarget;
126 | buildConfigurationList = 05B37DCF28E609AA0089594B /* Build configuration list for PBXNativeTarget "WeatherApp" */;
127 | buildPhases = (
128 | 05B37DBD28E609A80089594B /* Sources */,
129 | 05B37DBE28E609A80089594B /* Frameworks */,
130 | 05B37DBF28E609A80089594B /* Resources */,
131 | );
132 | buildRules = (
133 | );
134 | dependencies = (
135 | );
136 | name = WeatherApp;
137 | productName = WeatherApp;
138 | productReference = 05B37DC128E609A80089594B /* WeatherApp.app */;
139 | productType = "com.apple.product-type.application";
140 | };
141 | /* End PBXNativeTarget section */
142 |
143 | /* Begin PBXProject section */
144 | 05B37DB928E609A80089594B /* Project object */ = {
145 | isa = PBXProject;
146 | attributes = {
147 | BuildIndependentTargetsInParallel = 1;
148 | LastSwiftUpdateCheck = 1400;
149 | LastUpgradeCheck = 1400;
150 | TargetAttributes = {
151 | 05B37DC028E609A80089594B = {
152 | CreatedOnToolsVersion = 14.0;
153 | };
154 | };
155 | };
156 | buildConfigurationList = 05B37DBC28E609A80089594B /* Build configuration list for PBXProject "WeatherApp" */;
157 | compatibilityVersion = "Xcode 14.0";
158 | developmentRegion = en;
159 | hasScannedForEncodings = 0;
160 | knownRegions = (
161 | en,
162 | Base,
163 | );
164 | mainGroup = 05B37DB828E609A80089594B;
165 | productRefGroup = 05B37DC228E609A80089594B /* Products */;
166 | projectDirPath = "";
167 | projectRoot = "";
168 | targets = (
169 | 05B37DC028E609A80089594B /* WeatherApp */,
170 | );
171 | };
172 | /* End PBXProject section */
173 |
174 | /* Begin PBXResourcesBuildPhase section */
175 | 05B37DBF28E609A80089594B /* Resources */ = {
176 | isa = PBXResourcesBuildPhase;
177 | buildActionMask = 2147483647;
178 | files = (
179 | 05B37DCC28E609AA0089594B /* Preview Assets.xcassets in Resources */,
180 | 058632EF28E6EE1100F26333 /* weatherData.json in Resources */,
181 | 05B37DC928E609AA0089594B /* Assets.xcassets in Resources */,
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | };
185 | /* End PBXResourcesBuildPhase section */
186 |
187 | /* Begin PBXSourcesBuildPhase section */
188 | 05B37DBD28E609A80089594B /* Sources */ = {
189 | isa = PBXSourcesBuildPhase;
190 | buildActionMask = 2147483647;
191 | files = (
192 | 05B37DDB28E61E520089594B /* WeatherManager.swift in Sources */,
193 | 058632F128E6F68C00F26333 /* Extensions.swift in Sources */,
194 | 05B37DC728E609A80089594B /* ContentView.swift in Sources */,
195 | 05B37DC528E609A80089594B /* WeatherAppApp.swift in Sources */,
196 | 05B37DD428E60D050089594B /* LocationManager.swift in Sources */,
197 | 058632F428E7297C00F26333 /* WeatherRow.swift in Sources */,
198 | 05B37DD928E61A150089594B /* LoadingView.swift in Sources */,
199 | 058632ED28E6EDB900F26333 /* ModelData.swift in Sources */,
200 | 058632EB28E6ED1700F26333 /* WeatherView.swift in Sources */,
201 | 05B37DD728E60F600089594B /* WelcomeView.swift in Sources */,
202 | );
203 | runOnlyForDeploymentPostprocessing = 0;
204 | };
205 | /* End PBXSourcesBuildPhase section */
206 |
207 | /* Begin XCBuildConfiguration section */
208 | 05B37DCD28E609AA0089594B /* Debug */ = {
209 | isa = XCBuildConfiguration;
210 | buildSettings = {
211 | ALWAYS_SEARCH_USER_PATHS = NO;
212 | CLANG_ANALYZER_NONNULL = YES;
213 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
214 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
215 | CLANG_ENABLE_MODULES = YES;
216 | CLANG_ENABLE_OBJC_ARC = YES;
217 | CLANG_ENABLE_OBJC_WEAK = YES;
218 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
219 | CLANG_WARN_BOOL_CONVERSION = YES;
220 | CLANG_WARN_COMMA = YES;
221 | CLANG_WARN_CONSTANT_CONVERSION = YES;
222 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
223 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
224 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
225 | CLANG_WARN_EMPTY_BODY = YES;
226 | CLANG_WARN_ENUM_CONVERSION = YES;
227 | CLANG_WARN_INFINITE_RECURSION = YES;
228 | CLANG_WARN_INT_CONVERSION = YES;
229 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
230 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
231 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
233 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
234 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
235 | CLANG_WARN_STRICT_PROTOTYPES = YES;
236 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
237 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
238 | CLANG_WARN_UNREACHABLE_CODE = YES;
239 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
240 | COPY_PHASE_STRIP = NO;
241 | DEBUG_INFORMATION_FORMAT = dwarf;
242 | ENABLE_STRICT_OBJC_MSGSEND = YES;
243 | ENABLE_TESTABILITY = YES;
244 | GCC_C_LANGUAGE_STANDARD = gnu11;
245 | GCC_DYNAMIC_NO_PIC = NO;
246 | GCC_NO_COMMON_BLOCKS = YES;
247 | GCC_OPTIMIZATION_LEVEL = 0;
248 | GCC_PREPROCESSOR_DEFINITIONS = (
249 | "DEBUG=1",
250 | "$(inherited)",
251 | );
252 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
253 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
254 | GCC_WARN_UNDECLARED_SELECTOR = YES;
255 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
256 | GCC_WARN_UNUSED_FUNCTION = YES;
257 | GCC_WARN_UNUSED_VARIABLE = YES;
258 | IPHONEOS_DEPLOYMENT_TARGET = 16.0;
259 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
260 | MTL_FAST_MATH = YES;
261 | ONLY_ACTIVE_ARCH = YES;
262 | SDKROOT = iphoneos;
263 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
264 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
265 | };
266 | name = Debug;
267 | };
268 | 05B37DCE28E609AA0089594B /* Release */ = {
269 | isa = XCBuildConfiguration;
270 | buildSettings = {
271 | ALWAYS_SEARCH_USER_PATHS = NO;
272 | CLANG_ANALYZER_NONNULL = YES;
273 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
274 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
275 | CLANG_ENABLE_MODULES = YES;
276 | CLANG_ENABLE_OBJC_ARC = YES;
277 | CLANG_ENABLE_OBJC_WEAK = YES;
278 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
279 | CLANG_WARN_BOOL_CONVERSION = YES;
280 | CLANG_WARN_COMMA = YES;
281 | CLANG_WARN_CONSTANT_CONVERSION = YES;
282 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
283 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
284 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
285 | CLANG_WARN_EMPTY_BODY = YES;
286 | CLANG_WARN_ENUM_CONVERSION = YES;
287 | CLANG_WARN_INFINITE_RECURSION = YES;
288 | CLANG_WARN_INT_CONVERSION = YES;
289 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
290 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
291 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
292 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
293 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
294 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
295 | CLANG_WARN_STRICT_PROTOTYPES = YES;
296 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
297 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
298 | CLANG_WARN_UNREACHABLE_CODE = YES;
299 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
300 | COPY_PHASE_STRIP = NO;
301 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
302 | ENABLE_NS_ASSERTIONS = NO;
303 | ENABLE_STRICT_OBJC_MSGSEND = YES;
304 | GCC_C_LANGUAGE_STANDARD = gnu11;
305 | GCC_NO_COMMON_BLOCKS = YES;
306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
307 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
308 | GCC_WARN_UNDECLARED_SELECTOR = YES;
309 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
310 | GCC_WARN_UNUSED_FUNCTION = YES;
311 | GCC_WARN_UNUSED_VARIABLE = YES;
312 | IPHONEOS_DEPLOYMENT_TARGET = 16.0;
313 | MTL_ENABLE_DEBUG_INFO = NO;
314 | MTL_FAST_MATH = YES;
315 | SDKROOT = iphoneos;
316 | SWIFT_COMPILATION_MODE = wholemodule;
317 | SWIFT_OPTIMIZATION_LEVEL = "-O";
318 | VALIDATE_PRODUCT = YES;
319 | };
320 | name = Release;
321 | };
322 | 05B37DD028E609AA0089594B /* Debug */ = {
323 | isa = XCBuildConfiguration;
324 | buildSettings = {
325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
326 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
327 | CODE_SIGN_STYLE = Automatic;
328 | CURRENT_PROJECT_VERSION = 1;
329 | DEVELOPMENT_ASSET_PATHS = "\"WeatherApp/Preview Content\"";
330 | DEVELOPMENT_TEAM = D6AY938CAT;
331 | ENABLE_PREVIEWS = YES;
332 | GENERATE_INFOPLIST_FILE = YES;
333 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
334 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
335 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
336 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
337 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
338 | LD_RUNPATH_SEARCH_PATHS = (
339 | "$(inherited)",
340 | "@executable_path/Frameworks",
341 | );
342 | MARKETING_VERSION = 1.0;
343 | PRODUCT_BUNDLE_IDENTIFIER = com.home.Scrumdinger.WeatherApp;
344 | PRODUCT_NAME = "$(TARGET_NAME)";
345 | SWIFT_EMIT_LOC_STRINGS = YES;
346 | SWIFT_VERSION = 5.0;
347 | TARGETED_DEVICE_FAMILY = "1,2";
348 | };
349 | name = Debug;
350 | };
351 | 05B37DD128E609AA0089594B /* Release */ = {
352 | isa = XCBuildConfiguration;
353 | buildSettings = {
354 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
355 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
356 | CODE_SIGN_STYLE = Automatic;
357 | CURRENT_PROJECT_VERSION = 1;
358 | DEVELOPMENT_ASSET_PATHS = "\"WeatherApp/Preview Content\"";
359 | DEVELOPMENT_TEAM = D6AY938CAT;
360 | ENABLE_PREVIEWS = YES;
361 | GENERATE_INFOPLIST_FILE = YES;
362 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
363 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
364 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
365 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
366 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
367 | LD_RUNPATH_SEARCH_PATHS = (
368 | "$(inherited)",
369 | "@executable_path/Frameworks",
370 | );
371 | MARKETING_VERSION = 1.0;
372 | PRODUCT_BUNDLE_IDENTIFIER = com.home.Scrumdinger.WeatherApp;
373 | PRODUCT_NAME = "$(TARGET_NAME)";
374 | SWIFT_EMIT_LOC_STRINGS = YES;
375 | SWIFT_VERSION = 5.0;
376 | TARGETED_DEVICE_FAMILY = "1,2";
377 | };
378 | name = Release;
379 | };
380 | /* End XCBuildConfiguration section */
381 |
382 | /* Begin XCConfigurationList section */
383 | 05B37DBC28E609A80089594B /* Build configuration list for PBXProject "WeatherApp" */ = {
384 | isa = XCConfigurationList;
385 | buildConfigurations = (
386 | 05B37DCD28E609AA0089594B /* Debug */,
387 | 05B37DCE28E609AA0089594B /* Release */,
388 | );
389 | defaultConfigurationIsVisible = 0;
390 | defaultConfigurationName = Release;
391 | };
392 | 05B37DCF28E609AA0089594B /* Build configuration list for PBXNativeTarget "WeatherApp" */ = {
393 | isa = XCConfigurationList;
394 | buildConfigurations = (
395 | 05B37DD028E609AA0089594B /* Debug */,
396 | 05B37DD128E609AA0089594B /* Release */,
397 | );
398 | defaultConfigurationIsVisible = 0;
399 | defaultConfigurationName = Release;
400 | };
401 | /* End XCConfigurationList section */
402 | };
403 | rootObject = 05B37DB928E609A80089594B /* Project object */;
404 | }
405 |
--------------------------------------------------------------------------------