Add Weather Sample app and remove unnecessary codes in Voicememo app (#146)
author안주원/Common Platform Lab(SR)/Staff Engineer/삼성전자 <juwon.ahn@samsung.com>
Thu, 6 Feb 2020 08:00:25 +0000 (17:00 +0900)
committer유리나/Common Platform Lab(SR)/Staff Engineer/삼성전자 <rina6350.you@samsung.com>
Thu, 6 Feb 2020 08:00:25 +0000 (17:00 +0900)
76 files changed:
Test/Voicememo2020/VoiceMemo/App.xaml.cs
Test/Voicememo2020/VoiceMemo/Converters/DurationToRemainingTimeConverter.cs
Test/Voicememo2020/VoiceMemo/Converters/RecordsCountToViewVisibilityConverter.cs
Test/Voicememo2020/VoiceMemo/Converters/SttToPropertyConverter.cs
Test/Voicememo2020/VoiceMemo/Models/Record.cs
Test/Voicememo2020/VoiceMemo/Renderers/GraphicPopUpRenderer.cs
Test/Voicememo2020/VoiceMemo/Renderers/ProgressbarPopupRenderer.cs
Test/Voicememo2020/VoiceMemo/Views/MainPage.xaml.cs
Test/Weather/LICENSE [new file with mode: 0755]
Test/Weather/README.md [new file with mode: 0755]
Test/Weather/Screenshots/weatherApp_screen01.png [new file with mode: 0755]
Test/Weather/Screenshots/weatherApp_screen02.png [new file with mode: 0755]
Test/Weather/Screenshots/weatherApp_screen03.png [new file with mode: 0755]
Test/Weather/Screenshots/weatherApp_screen04.png [new file with mode: 0755]
Test/Weather/Screenshots/weatherApp_screen05.png [new file with mode: 0755]
Test/Weather/Weather.sln [new file with mode: 0755]
Test/Weather/Weather/App.cs [new file with mode: 0755]
Test/Weather/Weather/Behaviors/CountryCodeValidatorBehavior.cs [new file with mode: 0755]
Test/Weather/Weather/Behaviors/CurrentWeatherPageBehavior.cs [new file with mode: 0755]
Test/Weather/Weather/Config/ApiConfig.cs [new file with mode: 0755]
Test/Weather/Weather/Controls/DoubleLabel.xaml [new file with mode: 0755]
Test/Weather/Weather/Controls/DoubleLabel.xaml.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/DegreeToCardinalDirectionConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/ErrorMessageConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/ImageSourceConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/MeasurementSystemConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/TimeStampToDateConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/TimeStampToTimeConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/TimeStampWithOffsetAndTimezoneConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Converters/TimeStampWithOffsetConverter.cs [new file with mode: 0755]
Test/Weather/Weather/Data/city.list.json [new file with mode: 0755]
Test/Weather/Weather/Data/country.list.json [new file with mode: 0755]
Test/Weather/Weather/Models/Location/City.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Location/Coordinates.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Location/Country.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Location/TimeZone.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/Clouds.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/CurrentWeather.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/Forecast.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/SunData.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/WeatherBase.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/WeatherData.cs [new file with mode: 0755]
Test/Weather/Weather/Models/Weather/Wind.cs [new file with mode: 0755]
Test/Weather/Weather/Service/CityProvider.cs [new file with mode: 0755]
Test/Weather/Weather/Service/CountryProvider.cs [new file with mode: 0755]
Test/Weather/Weather/Service/ICityProvider.cs [new file with mode: 0755]
Test/Weather/Weather/Service/ICountryProvider.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/BindableString.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/ErrorHandler.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/HttpException.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/IRequest.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/JsonFileReader.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/NotificationTask.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/Request.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/TimeStamp.cs [new file with mode: 0755]
Test/Weather/Weather/Utils/UnitFormatter.cs [new file with mode: 0755]
Test/Weather/Weather/ViewModels/ApiErrorViewModel.cs [new file with mode: 0755]
Test/Weather/Weather/ViewModels/CurrentWeatherViewModel.cs [new file with mode: 0755]
Test/Weather/Weather/ViewModels/ForecastViewModel.cs [new file with mode: 0755]
Test/Weather/Weather/ViewModels/MainPageViewModel.cs [new file with mode: 0755]
Test/Weather/Weather/ViewModels/ViewModelBase.cs [new file with mode: 0755]
Test/Weather/Weather/Views/ApiErrorPage.xaml [new file with mode: 0755]
Test/Weather/Weather/Views/ApiErrorPage.xaml.cs [new file with mode: 0755]
Test/Weather/Weather/Views/CurrentWeatherPage.xaml [new file with mode: 0755]
Test/Weather/Weather/Views/CurrentWeatherPage.xaml.cs [new file with mode: 0755]
Test/Weather/Weather/Views/ForecastPage.xaml [new file with mode: 0755]
Test/Weather/Weather/Views/ForecastPage.xaml.cs [new file with mode: 0755]
Test/Weather/Weather/Views/MainPage.xaml [new file with mode: 0755]
Test/Weather/Weather/Views/MainPage.xaml.cs [new file with mode: 0755]
Test/Weather/Weather/Views/MissingKeyErrorPage.xaml [new file with mode: 0755]
Test/Weather/Weather/Views/MissingKeyErrorPage.xaml.cs [new file with mode: 0755]
Test/Weather/Weather/Weather.cs [new file with mode: 0755]
Test/Weather/Weather/Weather.csproj [new file with mode: 0755]
Test/Weather/Weather/shared/res/Weather.png [new file with mode: 0755]
Test/Weather/Weather/tizen-manifest.xml [new file with mode: 0755]
XSF.sln

index d60c756..d48e7ab 100755 (executable)
@@ -43,11 +43,6 @@ namespace VoiceMemo
             firstPage = (MainPage)PageFactory.GetInstance(Pages.StandBy);
             MainPage = new NavigationPage(firstPage);
             mainPageModel = (MainPageModel)firstPage.BindingContext;
-
-            //firstPageCS = (MainPageCS)PageFactory.GetInstance(Pages.StandByCS);
-            //MainPage = new NavigationPage(firstPageCS);
-
-            //mainPageModel = (MainPageModel)firstPageCS.BindingContext;
         }
 
         // database for voice records
index 7944565..9efcfcc 100755 (executable)
@@ -49,8 +49,6 @@ namespace VoiceMemo.Converters
                 case RemainingTimeType.TimeText:
                     int minutes = remains / 60000;
                     int seconds = (remains - minutes * 60000) / 1000;
-                    //Console.WriteLine("[DurationToRemainingTimeConverter  -  TimeText] remaining time : " + remains);
-                    // return the remaining time, formatted as {minutes}:{seconds}
                     return String.Format("{0:00}:{1:00}", minutes, seconds);
                 default:
                     return null;
index 2e1a4b0..484e05d 100755 (executable)
@@ -54,7 +54,6 @@ namespace VoiceMemo.Converters
         {
             int RecordsCnt = System.Convert.ToInt32(value);
             ViewType viewType = (ViewType)parameter;
-            //Console.WriteLine("[RecordsCountToViewVisibilityConverter] RecordsCount = " + RecordsCnt + ", viewType :" + viewType);
 
             switch (viewType)
             {
index 76ebb80..48915ee 100755 (executable)
@@ -49,7 +49,6 @@ namespace VoiceMemo.Converters
         {
             bool isSttOn = (bool)System.Convert.ToBoolean(value);
             SttPropertyType type = (SttPropertyType)parameter;
-            //Console.WriteLine("[SttToPropertyConverter] isSttOn: " + isSttOn + ", type:" + type);
             switch (type)
             {
                 case SttPropertyType.TextString:
index 945697a..8f86f41 100755 (executable)
@@ -71,7 +71,6 @@ namespace VoiceMemo.Models
                 bool changed = SetProperty(ref _Checked, value, "Checked");
                 if (changed)
                 {
-                    //Console.WriteLine("Record.Checked : " + Checked + " --> CheckedNamesCount changed..");
                     ((App)App.Current).mainPageModel.CheckedNamesCount += Checked ? 1 : -1;
                 }
             }
index 363c8fb..edc8511 100755 (executable)
@@ -35,7 +35,6 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
 
         public GraphicPopUpRenderer()
         {
-            Console.WriteLine("GraphicPopUpRenderer()  GetHashCode:" + this.GetHashCode());
             _popUp = new Popup(TForms.NativeParent)
             {
                 Style = "toast/circle",
@@ -54,19 +53,16 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
 
         private void _popUp_Dismissed(object sender, EventArgs e)
         {
-            Console.WriteLine("[GraphicPopUpRenderer._popUp_Dismissed] ");
         }
 
         private void TimedOutHandler(object sender, EventArgs e)
         {
-            Console.WriteLine("[GraphicPopUpRenderer.TimedOutHandler] ");
             TimedOut?.Invoke(this, EventArgs.Empty);
             _popUp.Dismiss();
         }
 
         private void BackButtonPressedHandler(object sender, EventArgs e)
         {
-            Console.WriteLine("[GraphicPopUpRenderer.BackButtonPressedHandler] ");
             BackButtonPressed?.Invoke(this, EventArgs.Empty);
             _popUp.Dismiss();
         }
@@ -84,7 +80,6 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
                 if (_Text != value)
                 {
                     _Text = value;
-                    Console.WriteLine("[GraphicPopUpRenderer--Update] Text (" + Text + ")");
                     _popUp.SetPartText("elm.text", Text);
                 }
             }
@@ -103,7 +98,6 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
                 if (_Duration != value)
                 {
                     _Duration = value;
-                    Console.WriteLine("[GraphicPopUpRenderer--Update] Duration (" + Duration + ")");
                     _popUp.Timeout = Duration;
                 }
             }
@@ -123,7 +117,6 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
                 return;
             }
 
-            Console.WriteLine("[GraphicPopUpRenderer.Dispose] ");
             if (disposing)
             {
                 if (_popUp != null)
@@ -140,7 +133,6 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
 
         public void Show()
         {
-            Console.WriteLine("[GraphicPopUpRenderer.Show] ");
             _popUp.Show();
         }
     }
index 2f6bca8..04d584c 100755 (executable)
@@ -74,32 +74,26 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
 
         private void _popUp_ShowAnimationFinished(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._popUp_ShowAnimationFinished] ");
         }
 
         private void _popUp_Resized(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._popUp_Resized] ");
         }
 
         private void _popUp_RenderPost(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._popUp_RenderPost] ");
         }
 
         private void _popUp_Moved(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._popUp_Moved] ");
         }
 
         private void _popUp2_Dismissed(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._popUp2_Dismissed] ");
         }
 
         private void _popUp_Dismissed(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._popUp_Dismissed] ");
         }
 
         /// <summary>
@@ -109,27 +103,23 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
         /// <param name="e">EventArgs</param>
         private void _progressbar_Deleted(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer._progressbar_Deleted] ");
             _popUp2.Show();
         }
 
         private void ProgressbarPopup_TimedOutHandler(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer.ProgressbarPopup_TimedOutHandler] ");
             // Remove Progressbar from Popup when doing progressbar is done
             _popUp.SetPartContent("elm.swallow.progress", null);
         }
 
         private void TimedOutHandler(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer.TimedOutHandler] 0");
             TimedOut?.Invoke(this, EventArgs.Empty);
             _popUp.Dismiss();
         }
 
         private void BackButtonPressedHandler(object sender, EventArgs e)
         {
-            Console.WriteLine("[ProgressbarPopupRenderer.BackButtonPressedHandler] ");
             BackButtonPressed?.Invoke(this, EventArgs.Empty);
             _popUp.Dismiss();
         }
@@ -147,7 +137,6 @@ namespace VoiceMemo.Tizen.Wearable.Renderers
                 if (_Text != value)
                 {
                     _Text = value;
-                    Console.WriteLine("[Update] Text (" + _Text + ")");
                     _popUp2.SetPartText("elm.text", _Text);
                 }
             }
index 8f28c64..6ca4e90 100755 (executable)
@@ -36,11 +36,13 @@ namespace VoiceMemo.Views
         public MainPage()
         {
             InitializeComponent();
-            Color stopIconColor = ColorConverter.OneUIColorConverter(new HSB(0, 98, 88, 100), null);
-            ImageAttributes.SetBlendColor(VoiceRecorderIconImage, stopIconColor); 
+            // Add tapGesture recognizer
             var tapGestureRecognizer = new TapGestureRecognizer();
             tapGestureRecognizer.Tapped += OnImageButtonClicked;
             VoiceRecorderIconImage.GestureRecognizers.Add(tapGestureRecognizer);
+            // TODO(vincent): blinking when red dot appearing.
+            Color stopIconColor = ColorConverter.OneUIColorConverter(new HSB(0, 98, 88, 100), null);
+            ImageAttributes.SetBlendColor(VoiceRecorderIconImage, stopIconColor); 
         }
 
         /// <summary>
diff --git a/Test/Weather/LICENSE b/Test/Weather/LICENSE
new file mode 100755 (executable)
index 0000000..51a2cd2
--- /dev/null
@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2017 Samsung
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/Test/Weather/README.md b/Test/Weather/README.md
new file mode 100755 (executable)
index 0000000..a2a1021
--- /dev/null
@@ -0,0 +1,24 @@
+# Weather
+
+This is a wearable port of [Weather](../../Mobile/Weather/) mobile app. 
+
+Weather is a sample application that demonstrates how to obtain data provided by the RESTful API using the [OpenWeatherMap](<https://openweathermap.org/>) API.
+
+![MainPage1](./Screenshots/weatherApp_screen01.png)
+![MainPage2](./Screenshots/weatherApp_screen02.png)
+![MainPage3](./Screenshots/weatherApp_screen03.png)
+![CurrentWeatherPage](./Screenshots/weatherApp_screen04.png)
+![ForecastPage](./Screenshots/weatherApp_screen05.png)
+
+### Features
+* Checking current weather (sample includes some US cities, check included [json files](./Weather/Data/) for details).
+* Checking forecast for next 5 days.
+
+### Prerequisites
+* [Visual Studio](https://www.visualstudio.com/) - Buildtool, IDE
+* [Visual Studio Tools for Tizen](https://developer.tizen.org/development/tizen-.net-preview/visual-studio-tools-tizen) - Visual Studio plugin for Tizen .NET application development
+* [Tizen CircularUI](https://samsung.github.io/Tizen.CircularUI/guide/Quickstart.html)
+
+### Author
+* Original mobile app was created by Michał Kołodziejski
+* Port to wearable by [@Piotr12](https://github.com/Piotr12)
diff --git a/Test/Weather/Screenshots/weatherApp_screen01.png b/Test/Weather/Screenshots/weatherApp_screen01.png
new file mode 100755 (executable)
index 0000000..68c4b0e
Binary files /dev/null and b/Test/Weather/Screenshots/weatherApp_screen01.png differ
diff --git a/Test/Weather/Screenshots/weatherApp_screen02.png b/Test/Weather/Screenshots/weatherApp_screen02.png
new file mode 100755 (executable)
index 0000000..b653d86
Binary files /dev/null and b/Test/Weather/Screenshots/weatherApp_screen02.png differ
diff --git a/Test/Weather/Screenshots/weatherApp_screen03.png b/Test/Weather/Screenshots/weatherApp_screen03.png
new file mode 100755 (executable)
index 0000000..6817a45
Binary files /dev/null and b/Test/Weather/Screenshots/weatherApp_screen03.png differ
diff --git a/Test/Weather/Screenshots/weatherApp_screen04.png b/Test/Weather/Screenshots/weatherApp_screen04.png
new file mode 100755 (executable)
index 0000000..8b27cc4
Binary files /dev/null and b/Test/Weather/Screenshots/weatherApp_screen04.png differ
diff --git a/Test/Weather/Screenshots/weatherApp_screen05.png b/Test/Weather/Screenshots/weatherApp_screen05.png
new file mode 100755 (executable)
index 0000000..1d45d23
Binary files /dev/null and b/Test/Weather/Screenshots/weatherApp_screen05.png differ
diff --git a/Test/Weather/Weather.sln b/Test/Weather/Weather.sln
new file mode 100755 (executable)
index 0000000..aa33270
--- /dev/null
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27703.2026
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Weather", "Weather\Weather.csproj", "{E6312AF9-328D-4A17-9677-1341036CB73A}"
+EndProject
+Global
+       GlobalSection(SolutionConfigurationPlatforms) = preSolution
+               Debug|Any CPU = Debug|Any CPU
+               Release|Any CPU = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(ProjectConfigurationPlatforms) = postSolution
+               {E6312AF9-328D-4A17-9677-1341036CB73A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+               {E6312AF9-328D-4A17-9677-1341036CB73A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+               {E6312AF9-328D-4A17-9677-1341036CB73A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+               {E6312AF9-328D-4A17-9677-1341036CB73A}.Release|Any CPU.Build.0 = Release|Any CPU
+       EndGlobalSection
+       GlobalSection(SolutionProperties) = preSolution
+               HideSolutionNode = FALSE
+       EndGlobalSection
+       GlobalSection(ExtensibilityGlobals) = postSolution
+               SolutionGuid = {86318113-EF47-4428-AF81-F34D84489808}
+       EndGlobalSection
+EndGlobal
diff --git a/Test/Weather/Weather/App.cs b/Test/Weather/Weather/App.cs
new file mode 100755 (executable)
index 0000000..6983d55
--- /dev/null
@@ -0,0 +1,61 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Weather.Config;
+using Weather.Views;
+using Xamarin.Forms;
+
+namespace Weather
+{
+    /// <summary>
+    /// Main App class - derives Xamarin.Forms application functionalities
+    /// </summary>
+    public class App : Application
+    {
+        #region properties
+
+        /// <summary>
+        /// Gets or sets value that indicates if weather and forecast for selected city is initialized.
+        /// </summary>
+        public bool IsInitialized { get; set; }
+
+        #endregion
+
+
+        #region methods
+
+        /// <summary>
+        /// App constructor. 
+        /// Makes sure that API Key is defined.
+        /// </summary>
+        public App()
+        {
+            // Its a NavigationPage based app that ...
+            MainPage =  new NavigationPage();
+
+            if (!ApiConfig.IsApiKeyDefined())
+            {
+                // either complains about a missing API key ...
+                MainPage.Navigation.PushAsync(new MissingKeyErrorPage(), false);
+            }
+            else
+            {
+                // or gets you started with a MainPage UI.
+                MainPage.Navigation.PushAsync(new MainPage(), false);                
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Behaviors/CountryCodeValidatorBehavior.cs b/Test/Weather/Weather/Behaviors/CountryCodeValidatorBehavior.cs
new file mode 100755 (executable)
index 0000000..4e3538a
--- /dev/null
@@ -0,0 +1,109 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Collections.Generic;
+using System.Linq;
+using Weather.Models.Location;
+using Weather.Service;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.Behaviors
+{
+    /// <summary>
+    /// Behavior class that validates user input in country entry.
+    /// </summary>
+    public class CountryCodeValidatorBehavior : Behavior<Entry>
+    {
+        #region fields
+
+        /// <summary>
+        /// Contains list of all supported countries.
+        /// </summary>
+        private CountryProvider _provider;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// Maximum length of user input.
+        /// </summary>
+        public int MaxLength { get; set; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public CountryCodeValidatorBehavior()
+        {
+            LoadCountryList();
+        }
+
+        /// <summary>
+        /// Called when behavior is attached to entry.
+        /// </summary>
+        /// <param name="bindable">Object to attach behavior.</param>
+        protected override void OnAttachedTo(Entry bindable)
+        {
+            base.OnAttachedTo(bindable);
+            bindable.TextChanged += EntryTextChanged;
+        }
+
+        /// <summary>
+        /// Called when behavior is detached from entry.
+        /// </summary>
+        /// <param name="bindable">Object to detach behavior.</param>
+        protected override void OnDetachingFrom(Entry bindable)
+        {
+            base.OnDetachingFrom(bindable);
+            bindable.TextChanged -= EntryTextChanged;
+        }
+
+        /// <summary>
+        /// Callback method, invoked when entry text is changed.
+        /// Changes user input to uppercase and forbids to enter more than "MaxLength" number of characters.
+        /// </summary>
+        /// <param name="sender">Object that invoked event.</param>
+        /// <param name="textChangedEventArgs">Event arguments.</param>
+        private void EntryTextChanged(object sender, TextChangedEventArgs textChangedEventArgs)
+        {
+            if (!(sender is Entry entry))
+            {
+                return;
+            }
+
+            entry.Text = entry.Text.Length > MaxLength
+                ? textChangedEventArgs.OldTextValue.ToUpper()
+                : textChangedEventArgs.NewTextValue.ToUpper();
+
+            entry.TextColor = _provider.Validate(entry.Text) ? Color.Gray : Color.Red;
+        }
+
+        /// <summary>
+        /// Loads supported city list from file.
+        /// </summary>
+        private void LoadCountryList()
+        {
+            var jsonFileReader = new JsonFileReader<IList<Country>>("Weather.Data.", "country.list.json");
+            jsonFileReader.Read();
+            _provider = new CountryProvider(jsonFileReader.Result.AsQueryable());
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Behaviors/CurrentWeatherPageBehavior.cs b/Test/Weather/Weather/Behaviors/CurrentWeatherPageBehavior.cs
new file mode 100755 (executable)
index 0000000..ffc67c8
--- /dev/null
@@ -0,0 +1,82 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using Xamarin.Forms;
+
+namespace Weather.Behaviors
+{
+    /// <summary>
+    /// Content page behavior that allows to bind command to "Appearing" event.
+    /// </summary>
+    public class CurrentWeatherPageBehavior : Behavior<ContentPage>
+    {
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set command that will be executed during page appearing.
+        /// </summary>
+        public static readonly BindableProperty AppearingCommandProperty =
+            BindableProperty.Create(nameof(AppearingCommand), typeof(Command), typeof(CurrentWeatherPageBehavior),
+                default(Command));
+
+        /// <summary>
+        /// Command that will be executed during page appearing.
+        /// </summary>
+        public Command AppearingCommand
+        {
+            get => (Command)GetValue(AppearingCommandProperty);
+            set => SetValue(AppearingCommandProperty, value);
+        }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Called when behavior is attached to content page.
+        /// </summary>
+        /// <param name="bindable">Object to attach behavior.</param>
+        protected override void OnAttachedTo(ContentPage bindable)
+        {
+            base.OnAttachedTo(bindable);
+            bindable.Appearing += PageOnAppearing;
+        }
+
+        /// <summary>
+        /// Called when behavior is detached from content page.
+        /// </summary>
+        /// <param name="bindable">Object to detach behavior.</param>
+        protected override void OnDetachingFrom(ContentPage bindable)
+        {
+            base.OnDetachingFrom(bindable);
+            bindable.Appearing -= PageOnAppearing;
+        }
+
+        /// <summary>
+        /// Called when content page is appearing.
+        /// </summary>
+        /// <param name="sender">Content page that sent event.</param>
+        /// <param name="eventArgs">Event arguments.</param>
+        private void PageOnAppearing(object sender, EventArgs eventArgs)
+        {
+            if (!((App)Application.Current).IsInitialized)
+            {
+                AppearingCommand?.Execute(sender);
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Config/ApiConfig.cs b/Test/Weather/Weather/Config/ApiConfig.cs
new file mode 100755 (executable)
index 0000000..fd9771d
--- /dev/null
@@ -0,0 +1,67 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+namespace Weather.Config
+{
+    /// <summary>
+    /// Foreign API configuration.
+    /// </summary>
+    public static class ApiConfig
+    {
+        #region fields
+
+        /// <summary>
+        /// Open Weather Map API key.
+        /// </summary>
+        /// <remarks>
+        /// To get your API key please visit http://openweathermap.org/appid
+        /// </remarks>
+        public const string API_KEY = "7c0d9b7749d114f810fe9a84b0b8ffdc";
+
+        /// <summary>
+        /// "OpenWeatherMap" current weather resource.
+        /// </summary>
+        public const string WEATHER_URL = "https://api.openweathermap.org/data/2.5/weather";
+
+        /// <summary>
+        /// "OpenWeatherMap" forecast resource.
+        /// </summary>
+        public const string FORECAST_URL = "https://api.openweathermap.org/data/2.5/forecast";
+
+        /// <summary>
+        /// "OpenWeatherMap" icon location template.
+        /// </summary>
+        public const string WEATHER_ICON = "http://openweathermap.org/img/w/{0}.png";
+
+        /// <summary>
+        /// Google API URL for getting timezones information.
+        /// </summary>
+        public const string TIMEZONE_URL = "https://maps.googleapis.com/maps/api/timezone/json";
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Checks if API key is defined.
+        /// </summary>
+        /// <returns>True if API key is set, otherwise false.</returns>
+        public static bool IsApiKeyDefined()
+        {    
+            return !string.IsNullOrEmpty(API_KEY);
+        }
+
+        #endregion
+    }
+}
diff --git a/Test/Weather/Weather/Controls/DoubleLabel.xaml b/Test/Weather/Weather/Controls/DoubleLabel.xaml
new file mode 100755 (executable)
index 0000000..a1ba71e
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             x:Class="Weather.Controls.DoubleLabel"
+             x:Name="Root"
+             Orientation="Vertical"
+             HorizontalOptions="CenterAndExpand">
+
+    <Label Text="{Binding Source={x:Reference Name=Root}, Path=MainText}"
+           FontSize="8"
+           HorizontalTextAlignment="Center" />
+    <Label Text="{Binding Source={x:Reference Name=Root}, Path=SubText}"
+           HorizontalTextAlignment="Center"
+           TextColor="LightSlateGray"
+           FontSize="6" />
+
+</StackLayout>
\ No newline at end of file
diff --git a/Test/Weather/Weather/Controls/DoubleLabel.xaml.cs b/Test/Weather/Weather/Controls/DoubleLabel.xaml.cs
new file mode 100755 (executable)
index 0000000..ff5700e
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using Xamarin.Forms;
+
+namespace Weather.Controls
+{
+    /// <summary>
+    /// Interaction logic for DoubleLabel.xaml.
+    /// </summary>
+    public partial class DoubleLabel
+    {
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set main text of control.
+        /// </summary>
+        public static readonly BindableProperty MainTextProperty =
+            BindableProperty.Create(nameof(MainText), typeof(string), typeof(DoubleLabel), default(string));
+
+        /// <summary>
+        /// Bindable property that allows to set sub text of control.
+        /// </summary>
+        public static readonly BindableProperty SubTextProperty =
+            BindableProperty.Create(nameof(SubText), typeof(string), typeof(DoubleLabel), default(string));
+
+        /// <summary>
+        /// Gets or sets main text of control.
+        /// </summary>
+        public string MainText
+        {
+            get => (string)GetValue(MainTextProperty);
+            set => SetValue(MainTextProperty, value);
+        }
+
+        /// <summary>
+        /// Gets or sets sub text of control.
+        /// </summary>
+        public string SubText
+        {
+            get => (string)GetValue(SubTextProperty);
+            set => SetValue(SubTextProperty, value);
+        }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default constructor.
+        /// </summary>
+        public DoubleLabel()
+        {
+            InitializeComponent();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/DegreeToCardinalDirectionConverter.cs b/Test/Weather/Weather/Converters/DegreeToCardinalDirectionConverter.cs
new file mode 100755 (executable)
index 0000000..f2f4a40
--- /dev/null
@@ -0,0 +1,61 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts double value to cardinal direction.
+    /// </summary>
+    public class DegreeToCardinalDirectionConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts double to cardinal value.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Cardinal direction.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            var directions = new[]
+            {
+                "North", "North-East", "East", "South-East", "South", "South-West", "West", "North-West", "North"
+            };
+
+            return value is double degree ? directions[(int)Math.Round(degree % 360 / 45)] : string.Empty;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/ErrorMessageConverter.cs b/Test/Weather/Weather/Converters/ErrorMessageConverter.cs
new file mode 100755 (executable)
index 0000000..51ba99e
--- /dev/null
@@ -0,0 +1,65 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts possible null string to error message.
+    /// </summary>
+    public class ErrorMessageConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts double to cardinal value.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Cardinal direction.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            var message = "None";
+
+            if (value is string msg)
+            {
+                message = msg;
+            }
+
+            return message;
+        }
+
+
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/ImageSourceConverter.cs b/Test/Weather/Weather/Converters/ImageSourceConverter.cs
new file mode 100755 (executable)
index 0000000..cc73557
--- /dev/null
@@ -0,0 +1,64 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Weather.Config;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts weather icon id to image source.
+    /// </summary>
+    public class ImageSourceConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts weather icon id to image source.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>URI to image.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            var url = string.Empty;
+
+            if (value is string iconCode)
+            {
+                url = string.Format(ApiConfig.WEATHER_ICON, iconCode);
+            }
+
+            return url;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/MeasurementSystemConverter.cs b/Test/Weather/Weather/Converters/MeasurementSystemConverter.cs
new file mode 100755 (executable)
index 0000000..2f8e500
--- /dev/null
@@ -0,0 +1,63 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts double value to value with unit.
+    /// </summary>
+    public class MeasurementSystemConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts double value to value with unit.
+        /// Unit depends on converter parameter.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Cardinal direction.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value is double && parameter is string)
+            {
+                return string.Format(new UnitFormatter(), "{0:" + parameter + "}", value);
+            }
+
+            return string.Empty;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/TimeStampToDateConverter.cs b/Test/Weather/Weather/Converters/TimeStampToDateConverter.cs
new file mode 100755 (executable)
index 0000000..7f0e321
--- /dev/null
@@ -0,0 +1,64 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts time stamp to date object.
+    /// </summary>
+    public class TimeStampToDateConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts time stamp to date object.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Date and hour in local format.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            var date = string.Empty;
+
+            if (value is ulong time)
+            {
+                date = TimeStamp.Convert(time).ToLocalTime().ToString("g");
+            }
+
+            return date;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/TimeStampToTimeConverter.cs b/Test/Weather/Weather/Converters/TimeStampToTimeConverter.cs
new file mode 100755 (executable)
index 0000000..e8ccb9e
--- /dev/null
@@ -0,0 +1,72 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts timestamp to time of the day.
+    /// </summary>
+    public class TimeStampToTimeConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts timestamp to time of the day.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Time of the day.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            var date = string.Empty;
+
+            if (value is ulong time)
+            {
+                if (parameter is Models.Location.TimeZone timeZone)
+                {
+                    date = TimeStamp.Convert(time).AddSeconds(timeZone.Offset)
+                        .ToString(culture.DateTimeFormat.ShortTimePattern);
+                }
+                else
+                {
+                    date = TimeStamp.Convert((ulong)value).ToString(culture.DateTimeFormat.ShortTimePattern);
+                }
+            }
+
+            return date;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/TimeStampWithOffsetAndTimezoneConverter.cs b/Test/Weather/Weather/Converters/TimeStampWithOffsetAndTimezoneConverter.cs
new file mode 100755 (executable)
index 0000000..cd974b7
--- /dev/null
@@ -0,0 +1,65 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts timestamp to region date and time with timezone.
+    /// </summary>
+    public class TimeStampWithOffsetAndTimezoneConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts timestamp to date and time with timezone.
+        /// Timezone depends on converter parameter.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Cardinal direction.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value is ulong timestamp && parameter is BindableString offsetString &&
+                long.TryParse(offsetString.Value, out long offset))
+            {
+                var time = TimeStamp.Convert(timestamp).AddSeconds(offset).ToString("g");
+                return $"{time} (GMT{offset / 60 / 60:+#;-#;+0})";
+            }
+
+            return string.Empty;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Converters/TimeStampWithOffsetConverter.cs b/Test/Weather/Weather/Converters/TimeStampWithOffsetConverter.cs
new file mode 100755 (executable)
index 0000000..33cd10f
--- /dev/null
@@ -0,0 +1,64 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.Converters
+{
+    /// <summary>
+    /// Class that converts timestamp to region date and time.
+    /// </summary>
+    public class TimeStampWithOffsetConverter : IValueConverter
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts timestamp to date and time with timezone.
+        /// Timezone depends on converter parameter.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Cardinal direction.</returns>
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (value is ulong timestamp && parameter is BindableString offsetString &&
+                long.TryParse(offsetString.Value, out long offset))
+            {
+                return TimeStamp.Convert(timestamp).AddSeconds(offset).ToShortTimeString();
+            }
+
+            return string.Empty;
+        }
+
+        /// <summary>
+        /// Does nothing, but it must be defined, because it is in "IValueConverter" interface.
+        /// </summary>
+        /// <param name="value">The value produced by the binding source.</param>
+        /// <param name="targetType">The type of the binding target property.</param>
+        /// <param name="parameter">The converter parameter to use.</param>
+        /// <param name="culture">The culture to use in the converter.</param>
+        /// <returns>Converted value.</returns>
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Data/city.list.json b/Test/Weather/Weather/Data/city.list.json
new file mode 100755 (executable)
index 0000000..b35d979
--- /dev/null
@@ -0,0 +1,2702 @@
+[
+  {
+    "id": 5128638,
+    "name": "New York",
+    "country": "US",
+    "coord": {
+      "lon": -75.499901,
+      "lat": 43.000351
+    }
+  },
+  {
+    "id": 5368361,
+    "name": "Los Angeles",
+    "country": "US",
+    "coord": {
+      "lon": -118.243683,
+      "lat": 34.052231
+    }
+  },
+  {
+    "id": 4887398,
+    "name": "Chicago",
+    "country": "US",
+    "coord": {
+      "lon": -87.650047,
+      "lat": 41.850029
+    }
+  },
+  {
+    "id": 4699066,
+    "name": "Houston",
+    "country": "US",
+    "coord": {
+      "lon": -95.363274,
+      "lat": 29.763281
+    }
+  },
+  {
+    "id": 5308655,
+    "name": "Phoenix",
+    "country": "US",
+    "coord": {
+      "lon": -112.074043,
+      "lat": 33.44838
+    }
+  },
+  {
+    "id": 4560349,
+    "name": "Philadelphia",
+    "country": "US",
+    "coord": {
+      "lon": -75.163788,
+      "lat": 39.952339
+    }
+  },
+  {
+    "id": 4726206,
+    "name": "San Antonio",
+    "country": "US",
+    "coord": {
+      "lon": -98.493629,
+      "lat": 29.42412
+    }
+  },
+  {
+    "id": 5391811,
+    "name": "San Diego",
+    "country": "US",
+    "coord": {
+      "lon": -117.157257,
+      "lat": 32.715328
+    }
+  },
+  {
+    "id": 4684888,
+    "name": "Dallas",
+    "country": "US",
+    "coord": {
+      "lon": -96.806671,
+      "lat": 32.783058
+    }
+  },
+  {
+    "id": 5392171,
+    "name": "San Jose",
+    "country": "US",
+    "coord": {
+      "lon": -121.894958,
+      "lat": 37.33939
+    }
+  },
+  {
+    "id": 4254010,
+    "name": "Austin",
+    "country": "US",
+    "coord": {
+      "lon": -85.808029,
+      "lat": 38.758389
+    }
+  },
+  {
+    "id": 4241704,
+    "name": "Jacksonville",
+    "country": "US",
+    "coord": {
+      "lon": -90.229012,
+      "lat": 39.73394
+    }
+  },
+  {
+    "id": 5391959,
+    "name": "San Francisco",
+    "country": "US",
+    "coord": {
+      "lon": -122.419418,
+      "lat": 37.774929
+    }
+  },
+  {
+    "id": 4256038,
+    "name": "Columbus",
+    "country": "US",
+    "coord": {
+      "lon": -85.921379,
+      "lat": 39.201439
+    }
+  },
+  {
+    "id": 4861716,
+    "name": "Indianapolis",
+    "country": "US",
+    "coord": {
+      "lon": -92.433517,
+      "lat": 41.39695
+    }
+  },
+  {
+    "id": 4691930,
+    "name": "Fort Worth",
+    "country": "US",
+    "coord": {
+      "lon": -97.320847,
+      "lat": 32.72541
+    }
+  },
+  {
+    "id": 4460243,
+    "name": "Charlotte",
+    "country": "US",
+    "coord": {
+      "lon": -80.843132,
+      "lat": 35.227089
+    }
+  },
+  {
+    "id": 5809844,
+    "name": "Seattle",
+    "country": "US",
+    "coord": {
+      "lon": -122.332069,
+      "lat": 47.606209
+    }
+  },
+  {
+    "id": 4463523,
+    "name": "Denver",
+    "country": "US",
+    "coord": {
+      "lon": -81.0298,
+      "lat": 35.53125
+    }
+  },
+  {
+    "id": 5520993,
+    "name": "El Paso",
+    "country": "US",
+    "coord": {
+      "lon": -106.486931,
+      "lat": 31.75872
+    }
+  },
+  {
+    "id": 4880731,
+    "name": "Washington",
+    "country": "US",
+    "coord": {
+      "lon": -91.69294,
+      "lat": 41.299179
+    }
+  },
+  {
+    "id": 4317656,
+    "name": "Boston",
+    "country": "US",
+    "coord": {
+      "lon": -92.055679,
+      "lat": 29.883261
+    }
+  },
+  {
+    "id": 4990729,
+    "name": "Detroit",
+    "country": "US",
+    "coord": {
+      "lon": -83.045753,
+      "lat": 42.331429
+    }
+  },
+  {
+    "id": 5003243,
+    "name": "Nashville",
+    "country": "US",
+    "coord": {
+      "lon": -85.093048,
+      "lat": 42.60281
+    }
+  },
+  {
+    "id": 4641239,
+    "name": "Memphis",
+    "country": "US",
+    "coord": {
+      "lon": -90.048981,
+      "lat": 35.149529
+    }
+  },
+  {
+    "id": 4720131,
+    "name": "Portland",
+    "country": "US",
+    "coord": {
+      "lon": -97.323883,
+      "lat": 27.877251
+    }
+  },
+  {
+    "id": 4544349,
+    "name": "Oklahoma City",
+    "country": "US",
+    "coord": {
+      "lon": -97.516434,
+      "lat": 35.46756
+    }
+  },
+  {
+    "id": 5506956,
+    "name": "Las Vegas",
+    "country": "US",
+    "coord": {
+      "lon": -115.137222,
+      "lat": 36.174969
+    }
+  },
+  {
+    "id": 4299276,
+    "name": "Louisville",
+    "country": "US",
+    "coord": {
+      "lon": -85.759407,
+      "lat": 38.254238
+    }
+  },
+  {
+    "id": 4347778,
+    "name": "Baltimore",
+    "country": "US",
+    "coord": {
+      "lon": -76.61219,
+      "lat": 39.290379
+    }
+  },
+  {
+    "id": 5263045,
+    "name": "Milwaukee",
+    "country": "US",
+    "coord": {
+      "lon": -87.906471,
+      "lat": 43.038898
+    }
+  },
+  {
+    "id": 5454711,
+    "name": "Albuquerque",
+    "country": "US",
+    "coord": {
+      "lon": -106.651138,
+      "lat": 35.084492
+    }
+  },
+  {
+    "id": 5318313,
+    "name": "Tucson",
+    "country": "US",
+    "coord": {
+      "lon": -110.926483,
+      "lat": 32.221741
+    }
+  },
+  {
+    "id": 4692400,
+    "name": "Fresno",
+    "country": "US",
+    "coord": {
+      "lon": -95.447441,
+      "lat": 29.538851
+    }
+  },
+  {
+    "id": 5389489,
+    "name": "Sacramento",
+    "country": "US",
+    "coord": {
+      "lon": -121.4944,
+      "lat": 38.58157
+    }
+  },
+  {
+    "id": 5304391,
+    "name": "Mesa",
+    "country": "US",
+    "coord": {
+      "lon": -111.822639,
+      "lat": 33.422272
+    }
+  },
+  {
+    "id": 4273837,
+    "name": "Kansas City",
+    "country": "US",
+    "coord": {
+      "lon": -94.627457,
+      "lat": 39.11417
+    }
+  },
+  {
+    "id": 4180439,
+    "name": "Atlanta",
+    "country": "US",
+    "coord": {
+      "lon": -84.387978,
+      "lat": 33.749001
+    }
+  },
+  {
+    "id": 5125086,
+    "name": "Long Beach",
+    "country": "US",
+    "coord": {
+      "lon": -73.657913,
+      "lat": 40.58844
+    }
+  },
+  {
+    "id": 5417598,
+    "name": "Colorado Springs",
+    "country": "US",
+    "coord": {
+      "lon": -104.821358,
+      "lat": 38.833881
+    }
+  },
+  {
+    "id": 4247770,
+    "name": "Raleigh",
+    "country": "US",
+    "coord": {
+      "lon": -88.531998,
+      "lat": 37.826988
+    }
+  },
+  {
+    "id": 4164138,
+    "name": "Miami",
+    "country": "US",
+    "coord": {
+      "lon": -80.193657,
+      "lat": 25.774269
+    }
+  },
+  {
+    "id": 4791259,
+    "name": "Virginia Beach",
+    "country": "US",
+    "coord": {
+      "lon": -75.977982,
+      "lat": 36.852928
+    }
+  },
+  {
+    "id": 5074472,
+    "name": "Omaha",
+    "country": "US",
+    "coord": {
+      "lon": -95.93779,
+      "lat": 41.25861
+    }
+  },
+  {
+    "id": 4276543,
+    "name": "Oakland",
+    "country": "US",
+    "coord": {
+      "lon": -95.636368,
+      "lat": 39.066669
+    }
+  },
+  {
+    "id": 5037649,
+    "name": "Minneapolis",
+    "country": "US",
+    "coord": {
+      "lon": -93.26384,
+      "lat": 44.979969
+    }
+  },
+  {
+    "id": 4553433,
+    "name": "Tulsa",
+    "country": "US",
+    "coord": {
+      "lon": -95.992783,
+      "lat": 36.15398
+    }
+  },
+  {
+    "id": 4282658,
+    "name": "Arlington",
+    "country": "US",
+    "coord": {
+      "lon": -84.307709,
+      "lat": 37.760639
+    }
+  },
+  {
+    "id": 4335045,
+    "name": "New Orleans",
+    "country": "US",
+    "coord": {
+      "lon": -90.075073,
+      "lat": 29.954651
+    }
+  },
+  {
+    "id": 4281730,
+    "name": "Wichita",
+    "country": "US",
+    "coord": {
+      "lon": -97.33754,
+      "lat": 37.692242
+    }
+  },
+  {
+    "id": 4188377,
+    "name": "Cleveland",
+    "country": "US",
+    "coord": {
+      "lon": -83.763237,
+      "lat": 34.597038
+    }
+  },
+  {
+    "id": 4174757,
+    "name": "Tampa",
+    "country": "US",
+    "coord": {
+      "lon": -82.458427,
+      "lat": 27.947519
+    }
+  },
+  {
+    "id": 5325738,
+    "name": "Bakersfield",
+    "country": "US",
+    "coord": {
+      "lon": -119.018707,
+      "lat": 35.373291
+    }
+  },
+  {
+    "id": 4883817,
+    "name": "Aurora",
+    "country": "US",
+    "coord": {
+      "lon": -88.320068,
+      "lat": 41.760578
+    }
+  },
+  {
+    "id": 5856195,
+    "name": "Honolulu",
+    "country": "US",
+    "coord": {
+      "lon": -157.858337,
+      "lat": 21.30694
+    }
+  },
+  {
+    "id": 5323810,
+    "name": "Anaheim",
+    "country": "US",
+    "coord": {
+      "lon": -117.914497,
+      "lat": 33.835289
+    }
+  },
+  {
+    "id": 5392900,
+    "name": "Santa Ana",
+    "country": "US",
+    "coord": {
+      "lon": -117.867828,
+      "lat": 33.745571
+    }
+  },
+  {
+    "id": 4683416,
+    "name": "Corpus Christi",
+    "country": "US",
+    "coord": {
+      "lon": -97.396378,
+      "lat": 27.800579
+    }
+  },
+  {
+    "id": 4522586,
+    "name": "Riverside",
+    "country": "US",
+    "coord": {
+      "lon": -84.1241,
+      "lat": 39.779781
+    }
+  },
+  {
+    "id": 4297983,
+    "name": "Lexington",
+    "country": "US",
+    "coord": {
+      "lon": -84.477722,
+      "lat": 37.988689
+    }
+  },
+  {
+    "id": 4407066,
+    "name": "Saint Louis",
+    "country": "US",
+    "coord": {
+      "lon": -90.197891,
+      "lat": 38.62727
+    }
+  },
+  {
+    "id": 5399020,
+    "name": "Stockton",
+    "country": "US",
+    "coord": {
+      "lon": -121.290779,
+      "lat": 37.957699
+    }
+  },
+  {
+    "id": 5206379,
+    "name": "Pittsburgh",
+    "country": "US",
+    "coord": {
+      "lon": -79.995888,
+      "lat": 40.44062
+    }
+  },
+  {
+    "id": 5045360,
+    "name": "Saint Paul",
+    "country": "US",
+    "coord": {
+      "lon": -93.093269,
+      "lat": 44.944408
+    }
+  },
+  {
+    "id": 4508722,
+    "name": "Cincinnati",
+    "country": "US",
+    "coord": {
+      "lon": -84.456886,
+      "lat": 39.161999
+    }
+  },
+  {
+    "id": 5879400,
+    "name": "Anchorage",
+    "country": "US",
+    "coord": {
+      "lon": -149.900284,
+      "lat": 61.21806
+    }
+  },
+  {
+    "id": 4294494,
+    "name": "Henderson",
+    "country": "US",
+    "coord": {
+      "lon": -87.590012,
+      "lat": 37.836151
+    }
+  },
+  {
+    "id": 4469146,
+    "name": "Greensboro",
+    "country": "US",
+    "coord": {
+      "lon": -79.791977,
+      "lat": 36.072639
+    }
+  },
+  {
+    "id": 4719457,
+    "name": "Plano",
+    "country": "US",
+    "coord": {
+      "lon": -96.698891,
+      "lat": 33.01984
+    }
+  },
+  {
+    "id": 4833930,
+    "name": "Newark",
+    "country": "US",
+    "coord": {
+      "lon": -89.227608,
+      "lat": 42.542229
+    }
+  },
+  {
+    "id": 5072006,
+    "name": "Lincoln",
+    "country": "US",
+    "coord": {
+      "lon": -96.666962,
+      "lat": 40.799999
+    }
+  },
+  {
+    "id": 5174035,
+    "name": "Toledo",
+    "country": "US",
+    "coord": {
+      "lon": -83.555206,
+      "lat": 41.66394
+    }
+  },
+  {
+    "id": 4167147,
+    "name": "Orlando",
+    "country": "US",
+    "coord": {
+      "lon": -81.379242,
+      "lat": 28.53834
+    }
+  },
+  {
+    "id": 5336899,
+    "name": "Chula Vista",
+    "country": "US",
+    "coord": {
+      "lon": -117.084198,
+      "lat": 32.640049
+    }
+  },
+  {
+    "id": 5359777,
+    "name": "Irvine",
+    "country": "US",
+    "coord": {
+      "lon": -117.823112,
+      "lat": 33.66946
+    }
+  },
+  {
+    "id": 4920423,
+    "name": "Fort Wayne",
+    "country": "US",
+    "coord": {
+      "lon": -85.12886,
+      "lat": 41.1306
+    }
+  },
+  {
+    "id": 5099836,
+    "name": "Jersey City",
+    "country": "US",
+    "coord": {
+      "lon": -74.077637,
+      "lat": 40.728161
+    }
+  },
+  {
+    "id": 4464368,
+    "name": "Durham",
+    "country": "US",
+    "coord": {
+      "lon": -78.898621,
+      "lat": 35.99403
+    }
+  },
+  {
+    "id": 4171563,
+    "name": "Saint Petersburg",
+    "country": "US",
+    "coord": {
+      "lon": -82.679268,
+      "lat": 27.770861
+    }
+  },
+  {
+    "id": 4705349,
+    "name": "Laredo",
+    "country": "US",
+    "coord": {
+      "lon": -99.507538,
+      "lat": 27.506411
+    }
+  },
+  {
+    "id": 5019588,
+    "name": "Buffalo",
+    "country": "US",
+    "coord": {
+      "lon": -93.874687,
+      "lat": 45.171909
+    }
+  },
+  {
+    "id": 4434663,
+    "name": "Madison",
+    "country": "US",
+    "coord": {
+      "lon": -90.115356,
+      "lat": 32.461811
+    }
+  },
+  {
+    "id": 5525577,
+    "name": "Lubbock",
+    "country": "US",
+    "coord": {
+      "lon": -101.855171,
+      "lat": 33.577862
+    }
+  },
+  {
+    "id": 4049176,
+    "name": "Chandler",
+    "country": "US",
+    "coord": {
+      "lon": -94.382729,
+      "lat": 39.300282
+    }
+  },
+  {
+    "id": 5313457,
+    "name": "Scottsdale",
+    "country": "US",
+    "coord": {
+      "lon": -111.899033,
+      "lat": 33.509209
+    }
+  },
+  {
+    "id": 5577409,
+    "name": "Glendale",
+    "country": "US",
+    "coord": {
+      "lon": -105.366379,
+      "lat": 40.081928
+    }
+  },
+  {
+    "id": 5511077,
+    "name": "Reno",
+    "country": "US",
+    "coord": {
+      "lon": -119.813797,
+      "lat": 39.529629
+    }
+  },
+  {
+    "id": 4776222,
+    "name": "Norfolk",
+    "country": "US",
+    "coord": {
+      "lon": -76.285217,
+      "lat": 36.846809
+    }
+  },
+  {
+    "id": 4499612,
+    "name": "Winston-Salem",
+    "country": "US",
+    "coord": {
+      "lon": -80.244217,
+      "lat": 36.099861
+    }
+  },
+  {
+    "id": 5509403,
+    "name": "North Las Vegas",
+    "country": "US",
+    "coord": {
+      "lon": -115.1175,
+      "lat": 36.19886
+    }
+  },
+  {
+    "id": 4700168,
+    "name": "Irving",
+    "country": "US",
+    "coord": {
+      "lon": -96.948891,
+      "lat": 32.814018
+    }
+  },
+  {
+    "id": 4752186,
+    "name": "Chesapeake",
+    "country": "US",
+    "coord": {
+      "lon": -76.27494,
+      "lat": 36.819038
+    }
+  },
+  {
+    "id": 5295903,
+    "name": "Gilbert",
+    "country": "US",
+    "coord": {
+      "lon": -111.789032,
+      "lat": 33.352829
+    }
+  },
+  {
+    "id": 4158476,
+    "name": "Hialeah",
+    "country": "US",
+    "coord": {
+      "lon": -80.278107,
+      "lat": 25.857599
+    }
+  },
+  {
+    "id": 4693003,
+    "name": "Garland",
+    "country": "US",
+    "coord": {
+      "lon": -96.638878,
+      "lat": 32.912621
+    }
+  },
+  {
+    "id": 4920512,
+    "name": "Fremont",
+    "country": "US",
+    "coord": {
+      "lon": -84.932739,
+      "lat": 41.730881
+    }
+  },
+  {
+    "id": 4315588,
+    "name": "Baton Rouge",
+    "country": "US",
+    "coord": {
+      "lon": -91.154549,
+      "lat": 30.45075
+    }
+  },
+  {
+    "id": 4305974,
+    "name": "Richmond",
+    "country": "US",
+    "coord": {
+      "lon": -84.294647,
+      "lat": 37.74786
+    }
+  },
+  {
+    "id": 5586437,
+    "name": "Boise",
+    "country": "US",
+    "coord": {
+      "lon": -116.203453,
+      "lat": 43.613499
+    }
+  },
+  {
+    "id": 5391710,
+    "name": "San Bernardino",
+    "country": "US",
+    "coord": {
+      "lon": -117.289772,
+      "lat": 34.108341
+    }
+  },
+  {
+    "id": 5811696,
+    "name": "Spokane",
+    "country": "US",
+    "coord": {
+      "lon": -117.429077,
+      "lat": 47.65966
+    }
+  },
+  {
+    "id": 4853828,
+    "name": "Des Moines",
+    "country": "US",
+    "coord": {
+      "lon": -93.609108,
+      "lat": 41.60054
+    }
+  },
+  {
+    "id": 5373900,
+    "name": "Modesto",
+    "country": "US",
+    "coord": {
+      "lon": -120.99688,
+      "lat": 37.639099
+    }
+  },
+  {
+    "id": 4049979,
+    "name": "Birmingham",
+    "country": "US",
+    "coord": {
+      "lon": -86.80249,
+      "lat": 33.52066
+    }
+  },
+  {
+    "id": 5812944,
+    "name": "Tacoma",
+    "country": "US",
+    "coord": {
+      "lon": -122.44429,
+      "lat": 47.25288
+    }
+  },
+  {
+    "id": 5349755,
+    "name": "Fontana",
+    "country": "US",
+    "coord": {
+      "lon": -117.435051,
+      "lat": 34.092232
+    }
+  },
+  {
+    "id": 5043473,
+    "name": "Rochester",
+    "country": "US",
+    "coord": {
+      "lon": -92.469902,
+      "lat": 44.021629
+    }
+  },
+  {
+    "id": 5380184,
+    "name": "Oxnard",
+    "country": "US",
+    "coord": {
+      "lon": -119.177048,
+      "lat": 34.197498
+    }
+  },
+  {
+    "id": 5374732,
+    "name": "Moreno Valley",
+    "country": "US",
+    "coord": {
+      "lon": -117.230591,
+      "lat": 33.937519
+    }
+  },
+  {
+    "id": 4194474,
+    "name": "Fayetteville",
+    "country": "US",
+    "coord": {
+      "lon": -84.454933,
+      "lat": 33.44873
+    }
+  },
+  {
+    "id": 4883817,
+    "name": "Aurora",
+    "country": "US",
+    "coord": {
+      "lon": -88.320068,
+      "lat": 41.760578
+    }
+  },
+  {
+    "id": 5577409,
+    "name": "Glendale",
+    "country": "US",
+    "coord": {
+      "lon": -105.366379,
+      "lat": 40.081928
+    }
+  },
+  {
+    "id": 5145215,
+    "name": "Yonkers",
+    "country": "US",
+    "coord": {
+      "lon": -73.89875,
+      "lat": 40.93121
+    }
+  },
+  {
+    "id": 5358705,
+    "name": "Huntington Beach",
+    "country": "US",
+    "coord": {
+      "lon": -117.999229,
+      "lat": 33.660301
+    }
+  },
+  {
+    "id": 4076784,
+    "name": "Montgomery",
+    "country": "US",
+    "coord": {
+      "lon": -86.299973,
+      "lat": 32.36681
+    }
+  },
+  {
+    "id": 5516233,
+    "name": "Amarillo",
+    "country": "US",
+    "coord": {
+      "lon": -101.831299,
+      "lat": 35.222
+    }
+  },
+  {
+    "id": 4119403,
+    "name": "Little Rock",
+    "country": "US",
+    "coord": {
+      "lon": -92.289589,
+      "lat": 34.746479
+    }
+  },
+  {
+    "id": 4267427,
+    "name": "Akron",
+    "country": "US",
+    "coord": {
+      "lon": -97.015038,
+      "lat": 37.351688
+    }
+  },
+  {
+    "id": 4256038,
+    "name": "Columbus",
+    "country": "US",
+    "coord": {
+      "lon": -85.921379,
+      "lat": 39.201439
+    }
+  },
+  {
+    "id": 4180531,
+    "name": "Augusta",
+    "country": "US",
+    "coord": {
+      "lon": -81.974838,
+      "lat": 33.47097
+    }
+  },
+  {
+    "id": 4994358,
+    "name": "Grand Rapids",
+    "country": "US",
+    "coord": {
+      "lon": -85.668091,
+      "lat": 42.96336
+    }
+  },
+  {
+    "id": 4341513,
+    "name": "Shreveport",
+    "country": "US",
+    "coord": {
+      "lon": -93.750183,
+      "lat": 32.52515
+    }
+  },
+  {
+    "id": 5780993,
+    "name": "Salt Lake City",
+    "country": "US",
+    "coord": {
+      "lon": -111.891052,
+      "lat": 40.76078
+    }
+  },
+  {
+    "id": 4699540,
+    "name": "Huntsville",
+    "country": "US",
+    "coord": {
+      "lon": -95.550781,
+      "lat": 30.72353
+    }
+  },
+  {
+    "id": 4076598,
+    "name": "Mobile",
+    "country": "US",
+    "coord": {
+      "lon": -88.043053,
+      "lat": 30.694361
+    }
+  },
+  {
+    "id": 4174715,
+    "name": "Tallahassee",
+    "country": "US",
+    "coord": {
+      "lon": -84.280731,
+      "lat": 30.438259
+    }
+  },
+  {
+    "id": 4694482,
+    "name": "Grand Prairie",
+    "country": "US",
+    "coord": {
+      "lon": -96.99778,
+      "lat": 32.74596
+    }
+  },
+  {
+    "id": 4276873,
+    "name": "Overland Park",
+    "country": "US",
+    "coord": {
+      "lon": -94.670792,
+      "lat": 38.982231
+    }
+  },
+  {
+    "id": 4634946,
+    "name": "Knoxville",
+    "country": "US",
+    "coord": {
+      "lon": -83.920738,
+      "lat": 35.96064
+    }
+  },
+  {
+    "id": 4169171,
+    "name": "Port Saint Lucie",
+    "country": "US",
+    "coord": {
+      "lon": -80.350327,
+      "lat": 27.29393
+    }
+  },
+  {
+    "id": 4956184,
+    "name": "Worcester",
+    "country": "US",
+    "coord": {
+      "lon": -71.802292,
+      "lat": 42.262589
+    }
+  },
+  {
+    "id": 4149077,
+    "name": "Brownsville",
+    "country": "US",
+    "coord": {
+      "lon": -80.241158,
+      "lat": 25.82176
+    }
+  },
+  {
+    "id": 5317058,
+    "name": "Tempe",
+    "country": "US",
+    "coord": {
+      "lon": -111.909309,
+      "lat": 33.414768
+    }
+  },
+  {
+    "id": 5393049,
+    "name": "Santa Clarita",
+    "country": "US",
+    "coord": {
+      "lon": -118.542587,
+      "lat": 34.391659
+    }
+  },
+  {
+    "id": 4776024,
+    "name": "Newport News",
+    "country": "US",
+    "coord": {
+      "lon": -76.428001,
+      "lat": 36.97876
+    }
+  },
+  {
+    "id": 4149962,
+    "name": "Cape Coral",
+    "country": "US",
+    "coord": {
+      "lon": -81.949532,
+      "lat": 26.562851
+    }
+  },
+  {
+    "id": 4263408,
+    "name": "Providence",
+    "country": "US",
+    "coord": {
+      "lon": -86.176659,
+      "lat": 39.490879
+    }
+  },
+  {
+    "id": 4155966,
+    "name": "Fort Lauderdale",
+    "country": "US",
+    "coord": {
+      "lon": -80.143379,
+      "lat": 26.122311
+    }
+  },
+  {
+    "id": 4612862,
+    "name": "Chattanooga",
+    "country": "US",
+    "coord": {
+      "lon": -85.309677,
+      "lat": 35.045631
+    }
+  },
+  {
+    "id": 5385955,
+    "name": "Rancho Cucamonga",
+    "country": "US",
+    "coord": {
+      "lon": -117.593109,
+      "lat": 34.1064
+    }
+  },
+  {
+    "id": 5129603,
+    "name": "Oceanside",
+    "country": "US",
+    "coord": {
+      "lon": -73.640129,
+      "lat": 40.63871
+    }
+  },
+  {
+    "id": 5393287,
+    "name": "Santa Rosa",
+    "country": "US",
+    "coord": {
+      "lon": -122.714432,
+      "lat": 38.440472
+    }
+  },
+  {
+    "id": 5351515,
+    "name": "Garden Grove",
+    "country": "US",
+    "coord": {
+      "lon": -117.941452,
+      "lat": 33.773911
+    }
+  },
+  {
+    "id": 5814616,
+    "name": "Vancouver",
+    "country": "US",
+    "coord": {
+      "lon": -122.661491,
+      "lat": 45.638729
+    }
+  },
+  {
+    "id": 5231851,
+    "name": "Sioux Falls",
+    "country": "US",
+    "coord": {
+      "lon": -96.700333,
+      "lat": 43.549969
+    }
+  },
+  {
+    "id": 4924493,
+    "name": "Ontario",
+    "country": "US",
+    "coord": {
+      "lon": -85.382477,
+      "lat": 41.702271
+    }
+  },
+  {
+    "id": 4710178,
+    "name": "McKinney",
+    "country": "US",
+    "coord": {
+      "lon": -96.615273,
+      "lat": 33.19762
+    }
+  },
+  {
+    "id": 5346111,
+    "name": "Elk Grove",
+    "country": "US",
+    "coord": {
+      "lon": -121.37162,
+      "lat": 38.408798
+    }
+  },
+  {
+    "id": 4241691,
+    "name": "Jackson",
+    "country": "US",
+    "coord": {
+      "lon": -87.650299,
+      "lat": 38.721161
+    }
+  },
+  {
+    "id": 4168139,
+    "name": "Pembroke Pines",
+    "country": "US",
+    "coord": {
+      "lon": -80.223938,
+      "lat": 26.003151
+    }
+  },
+  {
+    "id": 4950065,
+    "name": "Salem",
+    "country": "US",
+    "coord": {
+      "lon": -70.896721,
+      "lat": 42.519539
+    }
+  },
+  {
+    "id": 4525353,
+    "name": "Springfield",
+    "country": "US",
+    "coord": {
+      "lon": -83.808823,
+      "lat": 39.924229
+    }
+  },
+  {
+    "id": 5339631,
+    "name": "Corona",
+    "country": "US",
+    "coord": {
+      "lon": -117.566437,
+      "lat": 33.87529
+    }
+  },
+  {
+    "id": 4992263,
+    "name": "Eugene",
+    "country": "US",
+    "coord": {
+      "lon": -84.706947,
+      "lat": 43.292252
+    }
+  },
+  {
+    "id": 5577147,
+    "name": "Fort Collins",
+    "country": "US",
+    "coord": {
+      "lon": -105.084419,
+      "lat": 40.585258
+    }
+  },
+  {
+    "id": 4905687,
+    "name": "Peoria",
+    "country": "US",
+    "coord": {
+      "lon": -89.588989,
+      "lat": 40.693649
+    }
+  },
+  {
+    "id": 4692559,
+    "name": "Frisco",
+    "country": "US",
+    "coord": {
+      "lon": -96.823608,
+      "lat": 33.150669
+    }
+  },
+  {
+    "id": 4459467,
+    "name": "Cary",
+    "country": "US",
+    "coord": {
+      "lon": -78.78112,
+      "lat": 35.791538
+    }
+  },
+  {
+    "id": 4516233,
+    "name": "Lancaster",
+    "country": "US",
+    "coord": {
+      "lon": -82.599327,
+      "lat": 39.71368
+    }
+  },
+  {
+    "id": 5355933,
+    "name": "Hayward",
+    "country": "US",
+    "coord": {
+      "lon": -122.080803,
+      "lat": 37.668819
+    }
+  },
+  {
+    "id": 5380698,
+    "name": "Palmdale",
+    "country": "US",
+    "coord": {
+      "lon": -118.116463,
+      "lat": 34.57943
+    }
+  },
+  {
+    "id": 5391295,
+    "name": "Salinas",
+    "country": "US",
+    "coord": {
+      "lon": -121.655502,
+      "lat": 36.677738
+    }
+  },
+  {
+    "id": 4744091,
+    "name": "Alexandria",
+    "country": "US",
+    "coord": {
+      "lon": -77.046921,
+      "lat": 38.80484
+    }
+  },
+  {
+    "id": 5100280,
+    "name": "Lakewood",
+    "country": "US",
+    "coord": {
+      "lon": -74.217644,
+      "lat": 40.097889
+    }
+  },
+  {
+    "id": 4525353,
+    "name": "Springfield",
+    "country": "US",
+    "coord": {
+      "lon": -83.808823,
+      "lat": 39.924229
+    }
+  },
+  {
+    "id": 4364990,
+    "name": "Pasadena",
+    "country": "US",
+    "coord": {
+      "lon": -76.571083,
+      "lat": 39.10733
+    }
+  },
+  {
+    "id": 5400075,
+    "name": "Sunnyvale",
+    "country": "US",
+    "coord": {
+      "lon": -122.036346,
+      "lat": 37.368832
+    }
+  },
+  {
+    "id": 4163123,
+    "name": "Macon",
+    "country": "US",
+    "coord": {
+      "lon": -84.279068,
+      "lat": 30.49464
+    }
+  },
+  {
+    "id": 4503665,
+    "name": "Pomona",
+    "country": "US",
+    "coord": {
+      "lon": -74.575157,
+      "lat": 39.478451
+    }
+  },
+  {
+    "id": 4158928,
+    "name": "Hollywood",
+    "country": "US",
+    "coord": {
+      "lon": -80.14949,
+      "lat": 26.0112
+    }
+  },
+  {
+    "id": 4273837,
+    "name": "Kansas City",
+    "country": "US",
+    "coord": {
+      "lon": -94.627457,
+      "lat": 39.11417
+    }
+  },
+  {
+    "id": 5346827,
+    "name": "Escondido",
+    "country": "US",
+    "coord": {
+      "lon": -117.086418,
+      "lat": 33.119209
+    }
+  },
+  {
+    "id": 4381424,
+    "name": "Clarksville",
+    "country": "US",
+    "coord": {
+      "lon": -90.905128,
+      "lat": 39.370602
+    }
+  },
+  {
+    "id": 4898015,
+    "name": "Joliet",
+    "country": "US",
+    "coord": {
+      "lon": -88.081734,
+      "lat": 41.525028
+    }
+  },
+  {
+    "id": 5043556,
+    "name": "Rockford",
+    "country": "US",
+    "coord": {
+      "lon": -93.734413,
+      "lat": 45.088299
+    }
+  },
+  {
+    "id": 5403022,
+    "name": "Torrance",
+    "country": "US",
+    "coord": {
+      "lon": -118.34063,
+      "lat": 33.83585
+    }
+  },
+  {
+    "id": 4903279,
+    "name": "Naperville",
+    "country": "US",
+    "coord": {
+      "lon": -88.147293,
+      "lat": 41.785858
+    }
+  },
+  {
+    "id": 5102466,
+    "name": "Paterson",
+    "country": "US",
+    "coord": {
+      "lon": -74.171806,
+      "lat": 40.916771
+    }
+  },
+  {
+    "id": 4221552,
+    "name": "Savannah",
+    "country": "US",
+    "coord": {
+      "lon": -81.099831,
+      "lat": 32.083542
+    }
+  },
+  {
+    "id": 4254942,
+    "name": "Bridgeport",
+    "country": "US",
+    "coord": {
+      "lon": -86.317207,
+      "lat": 39.732269
+    }
+  },
+  {
+    "id": 5508180,
+    "name": "Mesquite",
+    "country": "US",
+    "coord": {
+      "lon": -114.067192,
+      "lat": 36.805531
+    }
+  },
+  {
+    "id": 4703223,
+    "name": "Killeen",
+    "country": "US",
+    "coord": {
+      "lon": -97.727798,
+      "lat": 31.117121
+    }
+  },
+  {
+    "id": 5140405,
+    "name": "Syracuse",
+    "country": "US",
+    "coord": {
+      "lon": -76.147423,
+      "lat": 43.048119
+    }
+  },
+  {
+    "id": 4709796,
+    "name": "McAllen",
+    "country": "US",
+    "coord": {
+      "lon": -98.230011,
+      "lat": 26.203409
+    }
+  },
+  {
+    "id": 4364990,
+    "name": "Pasadena",
+    "country": "US",
+    "coord": {
+      "lon": -76.571083,
+      "lat": 39.10733
+    }
+  },
+  {
+    "id": 4884416,
+    "name": "Bellevue",
+    "country": "US",
+    "coord": {
+      "lon": -89.680099,
+      "lat": 40.684479
+    }
+  },
+  {
+    "id": 5351247,
+    "name": "Fullerton",
+    "country": "US",
+    "coord": {
+      "lon": -117.925339,
+      "lat": 33.870289
+    }
+  },
+  {
+    "id": 4716805,
+    "name": "Orange",
+    "country": "US",
+    "coord": {
+      "lon": -93.736549,
+      "lat": 30.092991
+    }
+  },
+  {
+    "id": 4509884,
+    "name": "Dayton",
+    "country": "US",
+    "coord": {
+      "lon": -84.191612,
+      "lat": 39.758949
+    }
+  },
+  {
+    "id": 4164601,
+    "name": "Miramar",
+    "country": "US",
+    "coord": {
+      "lon": -80.232269,
+      "lat": 25.98731
+    }
+  },
+  {
+    "id": 5441492,
+    "name": "Thornton",
+    "country": "US",
+    "coord": {
+      "lon": -104.971916,
+      "lat": 39.868038
+    }
+  },
+  {
+    "id": 5784607,
+    "name": "West Valley City",
+    "country": "US",
+    "coord": {
+      "lon": -112.001053,
+      "lat": 40.691608
+    }
+  },
+  {
+    "id": 4276614,
+    "name": "Olathe",
+    "country": "US",
+    "coord": {
+      "lon": -94.81913,
+      "lat": 38.881401
+    }
+  },
+  {
+    "id": 4762894,
+    "name": "Hampton",
+    "country": "US",
+    "coord": {
+      "lon": -76.345222,
+      "lat": 37.029869
+    }
+  },
+  {
+    "id": 5094264,
+    "name": "Warren",
+    "country": "US",
+    "coord": {
+      "lon": -71.892029,
+      "lat": 43.923119
+    }
+  },
+  {
+    "id": 5001929,
+    "name": "Midland",
+    "country": "US",
+    "coord": {
+      "lon": -84.247208,
+      "lat": 43.615582
+    }
+  },
+  {
+    "id": 4739526,
+    "name": "Waco",
+    "country": "US",
+    "coord": {
+      "lon": -97.146667,
+      "lat": 31.54933
+    }
+  },
+  {
+    "id": 4574324,
+    "name": "Charleston",
+    "country": "US",
+    "coord": {
+      "lon": -79.930923,
+      "lat": 32.776569
+    }
+  },
+  {
+    "id": 4614867,
+    "name": "Columbia",
+    "country": "US",
+    "coord": {
+      "lon": -87.035278,
+      "lat": 35.61507
+    }
+  },
+  {
+    "id": 4990694,
+    "name": "Denton",
+    "country": "US",
+    "coord": {
+      "lon": -83.524101,
+      "lat": 42.25782
+    }
+  },
+  {
+    "id": 4186416,
+    "name": "Carrollton",
+    "country": "US",
+    "coord": {
+      "lon": -85.076607,
+      "lat": 33.580109
+    }
+  },
+  {
+    "id": 5316428,
+    "name": "Surprise",
+    "country": "US",
+    "coord": {
+      "lon": -112.333221,
+      "lat": 33.630589
+    }
+  },
+  {
+    "id": 5007655,
+    "name": "Roseville",
+    "country": "US",
+    "coord": {
+      "lon": -82.937141,
+      "lat": 42.497261
+    }
+  },
+  {
+    "id": 5011148,
+    "name": "Sterling Heights",
+    "country": "US",
+    "coord": {
+      "lon": -83.030197,
+      "lat": 42.580311
+    }
+  },
+  {
+    "id": 4644312,
+    "name": "Murfreesboro",
+    "country": "US",
+    "coord": {
+      "lon": -86.390266,
+      "lat": 35.845619
+    }
+  },
+  {
+    "id": 4692748,
+    "name": "Gainesville",
+    "country": "US",
+    "coord": {
+      "lon": -98.521423,
+      "lat": 30.677679
+    }
+  },
+  {
+    "id": 4850751,
+    "name": "Cedar Rapids",
+    "country": "US",
+    "coord": {
+      "lon": -91.644073,
+      "lat": 42.008331
+    }
+  },
+  {
+    "id": 5406567,
+    "name": "Visalia",
+    "country": "US",
+    "coord": {
+      "lon": -119.292061,
+      "lat": 36.330231
+    }
+  },
+  {
+    "id": 4151909,
+    "name": "Coral Springs",
+    "country": "US",
+    "coord": {
+      "lon": -80.270599,
+      "lat": 26.271191
+    }
+  },
+  {
+    "id": 4839366,
+    "name": "New Haven",
+    "country": "US",
+    "coord": {
+      "lon": -72.928162,
+      "lat": 41.308151
+    }
+  },
+  {
+    "id": 4843564,
+    "name": "Stamford",
+    "country": "US",
+    "coord": {
+      "lon": -73.538727,
+      "lat": 41.053429
+    }
+  },
+  {
+    "id": 5402405,
+    "name": "Thousand Oaks",
+    "country": "US",
+    "coord": {
+      "lon": -118.837593,
+      "lat": 34.170559
+    }
+  },
+  {
+    "id": 4382072,
+    "name": "Concord",
+    "country": "US",
+    "coord": {
+      "lon": -90.357338,
+      "lat": 38.524502
+    }
+  },
+  {
+    "id": 5097598,
+    "name": "Elizabeth",
+    "country": "US",
+    "coord": {
+      "lon": -74.210701,
+      "lat": 40.66399
+    }
+  },
+  {
+    "id": 4540465,
+    "name": "Lafayette",
+    "country": "US",
+    "coord": {
+      "lon": -95.103569,
+      "lat": 35.173988
+    }
+  },
+  {
+    "id": 5159537,
+    "name": "Kent",
+    "country": "US",
+    "coord": {
+      "lon": -81.357887,
+      "lat": 41.153671
+    }
+  },
+  {
+    "id": 4280539,
+    "name": "Topeka",
+    "country": "US",
+    "coord": {
+      "lon": -95.67804,
+      "lat": 39.048328
+    }
+  },
+  {
+    "id": 5396003,
+    "name": "Simi Valley",
+    "country": "US",
+    "coord": {
+      "lon": -118.781479,
+      "lat": 34.269451
+    }
+  },
+  {
+    "id": 5750516,
+    "name": "Santa Clara",
+    "country": "US",
+    "coord": {
+      "lon": -123.131203,
+      "lat": 44.103458
+    }
+  },
+  {
+    "id": 4505542,
+    "name": "Athens",
+    "country": "US",
+    "coord": {
+      "lon": -82.101257,
+      "lat": 39.329239
+    }
+  },
+  {
+    "id": 4835797,
+    "name": "Hartford",
+    "country": "US",
+    "coord": {
+      "lon": -72.685089,
+      "lat": 41.76371
+    }
+  },
+  {
+    "id": 5406222,
+    "name": "Victorville",
+    "country": "US",
+    "coord": {
+      "lon": -117.291161,
+      "lat": 34.53611
+    }
+  },
+  {
+    "id": 4669635,
+    "name": "Abilene",
+    "country": "US",
+    "coord": {
+      "lon": -99.733139,
+      "lat": 32.448738
+    }
+  },
+  {
+    "id": 4543762,
+    "name": "Norman",
+    "country": "US",
+    "coord": {
+      "lon": -97.439484,
+      "lat": 35.222569
+    }
+  },
+  {
+    "id": 5405380,
+    "name": "Vallejo",
+    "country": "US",
+    "coord": {
+      "lon": -122.256638,
+      "lat": 38.104092
+    }
+  },
+  {
+    "id": 5327684,
+    "name": "Berkeley",
+    "country": "US",
+    "coord": {
+      "lon": -122.272751,
+      "lat": 37.87159
+    }
+  },
+  {
+    "id": 4724129,
+    "name": "Round Rock",
+    "country": "US",
+    "coord": {
+      "lon": -97.678902,
+      "lat": 30.508261
+    }
+  },
+  {
+    "id": 4984247,
+    "name": "Ann Arbor",
+    "country": "US",
+    "coord": {
+      "lon": -83.740883,
+      "lat": 42.277561
+    }
+  },
+  {
+    "id": 5059163,
+    "name": "Fargo",
+    "country": "US",
+    "coord": {
+      "lon": -96.789803,
+      "lat": 46.87719
+    }
+  },
+  {
+    "id": 4614867,
+    "name": "Columbia",
+    "country": "US",
+    "coord": {
+      "lon": -87.035278,
+      "lat": 35.61507
+    }
+  },
+  {
+    "id": 5178127,
+    "name": "Allentown",
+    "country": "US",
+    "coord": {
+      "lon": -75.490181,
+      "lat": 40.608429
+    }
+  },
+  {
+    "id": 4257227,
+    "name": "Evansville",
+    "country": "US",
+    "coord": {
+      "lon": -87.555847,
+      "lat": 37.974758
+    }
+  },
+  {
+    "id": 4672989,
+    "name": "Beaumont",
+    "country": "US",
+    "coord": {
+      "lon": -94.101852,
+      "lat": 30.08605
+    }
+  },
+  {
+    "id": 5527554,
+    "name": "Odessa",
+    "country": "US",
+    "coord": {
+      "lon": -102.367638,
+      "lat": 31.84568
+    }
+  },
+  {
+    "id": 4145381,
+    "name": "Wilmington",
+    "country": "US",
+    "coord": {
+      "lon": -75.546593,
+      "lat": 39.745949
+    }
+  },
+  {
+    "id": 5412199,
+    "name": "Arvada",
+    "country": "US",
+    "coord": {
+      "lon": -105.087479,
+      "lat": 39.802761
+    }
+  },
+  {
+    "id": 5194748,
+    "name": "Independence",
+    "country": "US",
+    "coord": {
+      "lon": -80.309227,
+      "lat": 40.572289
+    }
+  },
+  {
+    "id": 5780026,
+    "name": "Provo",
+    "country": "US",
+    "coord": {
+      "lon": -111.658531,
+      "lat": 40.233841
+    }
+  },
+  {
+    "id": 5123993,
+    "name": "Lansing",
+    "country": "US",
+    "coord": {
+      "lon": -76.479942,
+      "lat": 42.484241
+    }
+  },
+  {
+    "id": 5345743,
+    "name": "El Monte",
+    "country": "US",
+    "coord": {
+      "lon": -118.027573,
+      "lat": 34.068619
+    }
+  },
+  {
+    "id": 4525353,
+    "name": "Springfield",
+    "country": "US",
+    "coord": {
+      "lon": -83.808823,
+      "lat": 39.924229
+    }
+  },
+  {
+    "id": 7257859,
+    "name": "Fairfield",
+    "country": "US",
+    "coord": {
+      "lon": -74.304024,
+      "lat": 40.882549
+    }
+  },
+  {
+    "id": 4151316,
+    "name": "Clearwater",
+    "country": "US",
+    "coord": {
+      "lon": -82.800102,
+      "lat": 27.965851
+    }
+  },
+  {
+    "id": 4905687,
+    "name": "Peoria",
+    "country": "US",
+    "coord": {
+      "lon": -89.588989,
+      "lat": 40.693649
+    }
+  },
+  {
+    "id": 5043473,
+    "name": "Rochester",
+    "country": "US",
+    "coord": {
+      "lon": -92.469902,
+      "lat": 44.021629
+    }
+  },
+  {
+    "id": 5334223,
+    "name": "Carlsbad",
+    "country": "US",
+    "coord": {
+      "lon": -117.350594,
+      "lat": 33.158089
+    }
+  },
+  {
+    "id": 5242810,
+    "name": "Westminster",
+    "country": "US",
+    "coord": {
+      "lon": -72.458702,
+      "lat": 43.06786
+    }
+  },
+  {
+    "id": 5784549,
+    "name": "West Jordan",
+    "country": "US",
+    "coord": {
+      "lon": -111.939102,
+      "lat": 40.609669
+    }
+  },
+  {
+    "id": 4718097,
+    "name": "Pearland",
+    "country": "US",
+    "coord": {
+      "lon": -95.286049,
+      "lat": 29.56357
+    }
+  },
+  {
+    "id": 4722625,
+    "name": "Richardson",
+    "country": "US",
+    "coord": {
+      "lon": -96.729721,
+      "lat": 32.948181
+    }
+  },
+  {
+    "id": 5343858,
+    "name": "Downey",
+    "country": "US",
+    "coord": {
+      "lon": -118.132568,
+      "lat": 33.94001
+    }
+  },
+  {
+    "id": 4164167,
+    "name": "Miami Gardens",
+    "country": "US",
+    "coord": {
+      "lon": -80.245598,
+      "lat": 25.942039
+    }
+  },
+  {
+    "id": 5401395,
+    "name": "Temecula",
+    "country": "US",
+    "coord": {
+      "lon": -117.148361,
+      "lat": 33.493641
+    }
+  },
+  {
+    "id": 5339840,
+    "name": "Costa Mesa",
+    "country": "US",
+    "coord": {
+      "lon": -117.918671,
+      "lat": 33.641129
+    }
+  },
+  {
+    "id": 4682464,
+    "name": "College Station",
+    "country": "US",
+    "coord": {
+      "lon": -96.334412,
+      "lat": 30.627979
+    }
+  },
+  {
+    "id": 4890864,
+    "name": "Elgin",
+    "country": "US",
+    "coord": {
+      "lon": -88.281189,
+      "lat": 42.037251
+    }
+  },
+  {
+    "id": 5375911,
+    "name": "Murrieta",
+    "country": "US",
+    "coord": {
+      "lon": -117.213921,
+      "lat": 33.553909
+    }
+  },
+  {
+    "id": 5729485,
+    "name": "Gresham",
+    "country": "US",
+    "coord": {
+      "lon": -122.43148,
+      "lat": 45.49818
+    }
+  },
+  {
+    "id": 4471025,
+    "name": "High Point",
+    "country": "US",
+    "coord": {
+      "lon": -80.005318,
+      "lat": 35.955688
+    }
+  },
+  {
+    "id": 4670957,
+    "name": "Antioch",
+    "country": "US",
+    "coord": {
+      "lon": -97.198067,
+      "lat": 32.31292
+    }
+  },
+  {
+    "id": 5359488,
+    "name": "Inglewood",
+    "country": "US",
+    "coord": {
+      "lon": -118.353127,
+      "lat": 33.961681
+    }
+  },
+  {
+    "id": 5587779,
+    "name": "Cambridge",
+    "country": "US",
+    "coord": {
+      "lon": -116.675987,
+      "lat": 44.572659
+    }
+  },
+  {
+    "id": 4942618,
+    "name": "Lowell",
+    "country": "US",
+    "coord": {
+      "lon": -71.31617,
+      "lat": 42.633419
+    }
+  },
+  {
+    "id": 5000598,
+    "name": "Manchester",
+    "country": "US",
+    "coord": {
+      "lon": -84.03772,
+      "lat": 42.150318
+    }
+  },
+  {
+    "id": 5640350,
+    "name": "Billings",
+    "country": "US",
+    "coord": {
+      "lon": -108.500687,
+      "lat": 45.783291
+    }
+  },
+  {
+    "id": 5435464,
+    "name": "Pueblo",
+    "country": "US",
+    "coord": {
+      "lon": -104.609138,
+      "lat": 38.254452
+    }
+  },
+  {
+    "id": 4167499,
+    "name": "Palm Bay",
+    "country": "US",
+    "coord": {
+      "lon": -80.588661,
+      "lat": 28.03446
+    }
+  },
+  {
+    "id": 4186974,
+    "name": "Centennial",
+    "country": "US",
+    "coord": {
+      "lon": -83.612389,
+      "lat": 33.58596
+    }
+  },
+  {
+    "id": 4305974,
+    "name": "Richmond",
+    "country": "US",
+    "coord": {
+      "lon": -84.294647,
+      "lat": 37.74786
+    }
+  },
+  {
+    "id": 5405878,
+    "name": "Ventura",
+    "country": "US",
+    "coord": {
+      "lon": -119.293167,
+      "lat": 34.278339
+    }
+  },
+  {
+    "id": 4169014,
+    "name": "Pompano Beach",
+    "country": "US",
+    "coord": {
+      "lon": -80.124771,
+      "lat": 26.23786
+    }
+  },
+  {
+    "id": 4589387,
+    "name": "North Charleston",
+    "country": "US",
+    "coord": {
+      "lon": -80.007507,
+      "lat": 32.888561
+    }
+  },
+  {
+    "id": 4936008,
+    "name": "Everett",
+    "country": "US",
+    "coord": {
+      "lon": -71.053658,
+      "lat": 42.408428
+    }
+  },
+  {
+    "id": 4845193,
+    "name": "Waterbury",
+    "country": "US",
+    "coord": {
+      "lon": -73.051498,
+      "lat": 41.558151
+    }
+  },
+  {
+    "id": 4177887,
+    "name": "West Palm Beach",
+    "country": "US",
+    "coord": {
+      "lon": -80.053368,
+      "lat": 26.71534
+    }
+  },
+  {
+    "id": 5574991,
+    "name": "Boulder",
+    "country": "US",
+    "coord": {
+      "lon": -105.270554,
+      "lat": 40.014992
+    }
+  },
+  {
+    "id": 5407933,
+    "name": "West Covina",
+    "country": "US",
+    "coord": {
+      "lon": -117.93895,
+      "lat": 34.068619
+    }
+  },
+  {
+    "id": 4531405,
+    "name": "Broken Arrow",
+    "country": "US",
+    "coord": {
+      "lon": -95.790817,
+      "lat": 36.052601
+    }
+  },
+  {
+    "id": 5338122,
+    "name": "Clovis",
+    "country": "US",
+    "coord": {
+      "lon": -119.702919,
+      "lat": 36.82523
+    }
+  },
+  {
+    "id": 5341430,
+    "name": "Daly City",
+    "country": "US",
+    "coord": {
+      "lon": -122.461922,
+      "lat": 37.705769
+    }
+  },
+  {
+    "id": 5123873,
+    "name": "Lakeland",
+    "country": "US",
+    "coord": {
+      "lon": -73.12011,
+      "lat": 40.80788
+    }
+  },
+  {
+    "id": 5393180,
+    "name": "Santa Maria",
+    "country": "US",
+    "coord": {
+      "lon": -120.435722,
+      "lat": 34.95303
+    }
+  },
+  {
+    "id": 4839822,
+    "name": "Norwalk",
+    "country": "US",
+    "coord": {
+      "lon": -73.407898,
+      "lat": 41.117599
+    }
+  },
+  {
+    "id": 4490315,
+    "name": "Sandy Springs",
+    "country": "US",
+    "coord": {
+      "lon": -77.944153,
+      "lat": 35.332661
+    }
+  },
+  {
+    "id": 5731371,
+    "name": "Hillsboro",
+    "country": "US",
+    "coord": {
+      "lon": -122.98983,
+      "lat": 45.522888
+    }
+  },
+  {
+    "id": 4580391,
+    "name": "Green Bay",
+    "country": "US",
+    "coord": {
+      "lon": -79.755363,
+      "lat": 33.014889
+    }
+  },
+  {
+    "id": 4738214,
+    "name": "Tyler",
+    "country": "US",
+    "coord": {
+      "lon": -95.301064,
+      "lat": 32.351261
+    }
+  },
+  {
+    "id": 4741752,
+    "name": "Wichita Falls",
+    "country": "US",
+    "coord": {
+      "lon": -98.493393,
+      "lat": 33.913712
+    }
+  },
+  {
+    "id": 4706057,
+    "name": "Lewisville",
+    "country": "US",
+    "coord": {
+      "lon": -96.994171,
+      "lat": 33.04623
+    }
+  },
+  {
+    "id": 4885983,
+    "name": "Burbank",
+    "country": "US",
+    "coord": {
+      "lon": -87.779503,
+      "lat": 41.733921
+    }
+  },
+  {
+    "id": 5577592,
+    "name": "Greeley",
+    "country": "US",
+    "coord": {
+      "lon": -104.709129,
+      "lat": 40.423309
+    }
+  },
+  {
+    "id": 5392423,
+    "name": "San Mateo",
+    "country": "US",
+    "coord": {
+      "lon": -122.325531,
+      "lat": 37.562988
+    }
+  },
+  {
+    "id": 5345529,
+    "name": "El Cajon",
+    "country": "US",
+    "coord": {
+      "lon": -116.962532,
+      "lat": 32.794769
+    }
+  },
+  {
+    "id": 5387288,
+    "name": "Rialto",
+    "country": "US",
+    "coord": {
+      "lon": -117.370323,
+      "lat": 34.1064
+    }
+  },
+  {
+    "id": 4853423,
+    "name": "Davenport",
+    "country": "US",
+    "coord": {
+      "lon": -90.577637,
+      "lat": 41.52364
+    }
+  },
+  {
+    "id": 4705692,
+    "name": "League City",
+    "country": "US",
+    "coord": {
+      "lon": -95.094933,
+      "lat": 29.50745
+    }
+  },
+  {
+    "id": 5097529,
+    "name": "Edison",
+    "country": "US",
+    "coord": {
+      "lon": -74.412102,
+      "lat": 40.518719
+    }
+  },
+  {
+    "id": 4152820,
+    "name": "Davie",
+    "country": "US",
+    "coord": {
+      "lon": -80.233101,
+      "lat": 26.06287
+    }
+  },
+  {
+    "id": 5475352,
+    "name": "Las Cruces",
+    "country": "US",
+    "coord": {
+      "lon": -106.778343,
+      "lat": 32.312321
+    }
+  },
+  {
+    "id": 4926563,
+    "name": "South Bend",
+    "country": "US",
+    "coord": {
+      "lon": -86.250008,
+      "lat": 41.68338
+    }
+  }
+]
\ No newline at end of file
diff --git a/Test/Weather/Weather/Data/country.list.json b/Test/Weather/Weather/Data/country.list.json
new file mode 100755 (executable)
index 0000000..1287277
--- /dev/null
@@ -0,0 +1,746 @@
+[
+  {
+    "Code": "AD"
+  },
+  {
+    "Code": "AE"
+  },
+  {
+    "Code": "AF"
+  },
+  {
+    "Code": "AG"
+  },
+  {
+    "Code": "AI"
+  },
+  {
+    "Code": "AL"
+  },
+  {
+    "Code": "AM"
+  },
+  {
+    "Code": "AO"
+  },
+  {
+    "Code": "AQ"
+  },
+  {
+    "Code": "AR"
+  },
+  {
+    "Code": "AS"
+  },
+  {
+    "Code": "AT"
+  },
+  {
+    "Code": "AU"
+  },
+  {
+    "Code": "AW"
+  },
+  {
+    "Code": "AX"
+  },
+  {
+    "Code": "AZ"
+  },
+  {
+    "Code": "BA"
+  },
+  {
+    "Code": "BB"
+  },
+  {
+    "Code": "BD"
+  },
+  {
+    "Code": "BE"
+  },
+  {
+    "Code": "BF"
+  },
+  {
+    "Code": "BG"
+  },
+  {
+    "Code": "BH"
+  },
+  {
+    "Code": "BI"
+  },
+  {
+    "Code": "BJ"
+  },
+  {
+    "Code": "BL"
+  },
+  {
+    "Code": "BM"
+  },
+  {
+    "Code": "BN"
+  },
+  {
+    "Code": "BO"
+  },
+  {
+    "Code": "BQ"
+  },
+  {
+    "Code": "BR"
+  },
+  {
+    "Code": "BS"
+  },
+  {
+    "Code": "BT"
+  },
+  {
+    "Code": "BV"
+  },
+  {
+    "Code": "BW"
+  },
+  {
+    "Code": "BY"
+  },
+  {
+    "Code": "BZ"
+  },
+  {
+    "Code": "CA"
+  },
+  {
+    "Code": "CC"
+  },
+  {
+    "Code": "CD"
+  },
+  {
+    "Code": "CF"
+  },
+  {
+    "Code": "CG"
+  },
+  {
+    "Code": "CH"
+  },
+  {
+    "Code": "CI"
+  },
+  {
+    "Code": "CK"
+  },
+  {
+    "Code": "CL"
+  },
+  {
+    "Code": "CM"
+  },
+  {
+    "Code": "CN"
+  },
+  {
+    "Code": "CO"
+  },
+  {
+    "Code": "CR"
+  },
+  {
+    "Code": "CU"
+  },
+  {
+    "Code": "CV"
+  },
+  {
+    "Code": "CW"
+  },
+  {
+    "Code": "CX"
+  },
+  {
+    "Code": "CY"
+  },
+  {
+    "Code": "CZ"
+  },
+  {
+    "Code": "DE"
+  },
+  {
+    "Code": "DJ"
+  },
+  {
+    "Code": "DK"
+  },
+  {
+    "Code": "DM"
+  },
+  {
+    "Code": "DO"
+  },
+  {
+    "Code": "DZ"
+  },
+  {
+    "Code": "EC"
+  },
+  {
+    "Code": "EE"
+  },
+  {
+    "Code": "EG"
+  },
+  {
+    "Code": "EH"
+  },
+  {
+    "Code": "ER"
+  },
+  {
+    "Code": "ES"
+  },
+  {
+    "Code": "ET"
+  },
+  {
+    "Code": "FI"
+  },
+  {
+    "Code": "FJ"
+  },
+  {
+    "Code": "FK"
+  },
+  {
+    "Code": "FM"
+  },
+  {
+    "Code": "FO"
+  },
+  {
+    "Code": "FR"
+  },
+  {
+    "Code": "GA"
+  },
+  {
+    "Code": "GB"
+  },
+  {
+    "Code": "GD"
+  },
+  {
+    "Code": "GE"
+  },
+  {
+    "Code": "GF"
+  },
+  {
+    "Code": "GG"
+  },
+  {
+    "Code": "GH"
+  },
+  {
+    "Code": "GI"
+  },
+  {
+    "Code": "GL"
+  },
+  {
+    "Code": "GM"
+  },
+  {
+    "Code": "GN"
+  },
+  {
+    "Code": "GP"
+  },
+  {
+    "Code": "GQ"
+  },
+  {
+    "Code": "GR"
+  },
+  {
+    "Code": "GS"
+  },
+  {
+    "Code": "GT"
+  },
+  {
+    "Code": "GU"
+  },
+  {
+    "Code": "GW"
+  },
+  {
+    "Code": "GY"
+  },
+  {
+    "Code": "HK"
+  },
+  {
+    "Code": "HM"
+  },
+  {
+    "Code": "HN"
+  },
+  {
+    "Code": "HR"
+  },
+  {
+    "Code": "HT"
+  },
+  {
+    "Code": "HU"
+  },
+  {
+    "Code": "ID"
+  },
+  {
+    "Code": "IE"
+  },
+  {
+    "Code": "IL"
+  },
+  {
+    "Code": "IM"
+  },
+  {
+    "Code": "IN"
+  },
+  {
+    "Code": "IO"
+  },
+  {
+    "Code": "IQ"
+  },
+  {
+    "Code": "IR"
+  },
+  {
+    "Code": "IS"
+  },
+  {
+    "Code": "IT"
+  },
+  {
+    "Code": "JE"
+  },
+  {
+    "Code": "JM"
+  },
+  {
+    "Code": "JO"
+  },
+  {
+    "Code": "JP"
+  },
+  {
+    "Code": "KE"
+  },
+  {
+    "Code": "KG"
+  },
+  {
+    "Code": "KH"
+  },
+  {
+    "Code": "KI"
+  },
+  {
+    "Code": "KM"
+  },
+  {
+    "Code": "KN"
+  },
+  {
+    "Code": "KP"
+  },
+  {
+    "Code": "KR"
+  },
+  {
+    "Code": "KW"
+  },
+  {
+    "Code": "KY"
+  },
+  {
+    "Code": "KZ"
+  },
+  {
+    "Code": "LA"
+  },
+  {
+    "Code": "LB"
+  },
+  {
+    "Code": "LC"
+  },
+  {
+    "Code": "LI"
+  },
+  {
+    "Code": "LK"
+  },
+  {
+    "Code": "LR"
+  },
+  {
+    "Code": "LS"
+  },
+  {
+    "Code": "LT"
+  },
+  {
+    "Code": "LU"
+  },
+  {
+    "Code": "LV"
+  },
+  {
+    "Code": "LY"
+  },
+  {
+    "Code": "MA"
+  },
+  {
+    "Code": "MC"
+  },
+  {
+    "Code": "MD"
+  },
+  {
+    "Code": "ME"
+  },
+  {
+    "Code": "MF"
+  },
+  {
+    "Code": "MG"
+  },
+  {
+    "Code": "MH"
+  },
+  {
+    "Code": "MK"
+  },
+  {
+    "Code": "ML"
+  },
+  {
+    "Code": "MM"
+  },
+  {
+    "Code": "MN"
+  },
+  {
+    "Code": "MO"
+  },
+  {
+    "Code": "MP"
+  },
+  {
+    "Code": "MQ"
+  },
+  {
+    "Code": "MR"
+  },
+  {
+    "Code": "MS"
+  },
+  {
+    "Code": "MT"
+  },
+  {
+    "Code": "MU"
+  },
+  {
+    "Code": "MV"
+  },
+  {
+    "Code": "MW"
+  },
+  {
+    "Code": "MX"
+  },
+  {
+    "Code": "MY"
+  },
+  {
+    "Code": "MZ"
+  },
+  {
+    "Code": "NA"
+  },
+  {
+    "Code": "NC"
+  },
+  {
+    "Code": "NE"
+  },
+  {
+    "Code": "NF"
+  },
+  {
+    "Code": "NG"
+  },
+  {
+    "Code": "NI"
+  },
+  {
+    "Code": "NL"
+  },
+  {
+    "Code": "NO"
+  },
+  {
+    "Code": "NP"
+  },
+  {
+    "Code": "NR"
+  },
+  {
+    "Code": "NU"
+  },
+  {
+    "Code": "NZ"
+  },
+  {
+    "Code": "OM"
+  },
+  {
+    "Code": "PA"
+  },
+  {
+    "Code": "PE"
+  },
+  {
+    "Code": "PF"
+  },
+  {
+    "Code": "PG"
+  },
+  {
+    "Code": "PH"
+  },
+  {
+    "Code": "PK"
+  },
+  {
+    "Code": "PL"
+  },
+  {
+    "Code": "PM"
+  },
+  {
+    "Code": "PN"
+  },
+  {
+    "Code": "PR"
+  },
+  {
+    "Code": "PS"
+  },
+  {
+    "Code": "PT"
+  },
+  {
+    "Code": "PW"
+  },
+  {
+    "Code": "PY"
+  },
+  {
+    "Code": "QA"
+  },
+  {
+    "Code": "RE"
+  },
+  {
+    "Code": "RO"
+  },
+  {
+    "Code": "RS"
+  },
+  {
+    "Code": "RU"
+  },
+  {
+    "Code": "RW"
+  },
+  {
+    "Code": "SA"
+  },
+  {
+    "Code": "SB"
+  },
+  {
+    "Code": "SC"
+  },
+  {
+    "Code": "SD"
+  },
+  {
+    "Code": "SE"
+  },
+  {
+    "Code": "SG"
+  },
+  {
+    "Code": "SH"
+  },
+  {
+    "Code": "SI"
+  },
+  {
+    "Code": "SJ"
+  },
+  {
+    "Code": "SK"
+  },
+  {
+    "Code": "SL"
+  },
+  {
+    "Code": "SM"
+  },
+  {
+    "Code": "SN"
+  },
+  {
+    "Code": "SO"
+  },
+  {
+    "Code": "SR"
+  },
+  {
+    "Code": "ST"
+  },
+  {
+    "Code": "SV"
+  },
+  {
+    "Code": "SX"
+  },
+  {
+    "Code": "SY"
+  },
+  {
+    "Code": "SZ"
+  },
+  {
+    "Code": "TC"
+  },
+  {
+    "Code": "TD"
+  },
+  {
+    "Code": "TF"
+  },
+  {
+    "Code": "TG"
+  },
+  {
+    "Code": "TH"
+  },
+  {
+    "Code": "TJ"
+  },
+  {
+    "Code": "TK"
+  },
+  {
+    "Code": "TL"
+  },
+  {
+    "Code": "TM"
+  },
+  {
+    "Code": "TN"
+  },
+  {
+    "Code": "TO"
+  },
+  {
+    "Code": "TR"
+  },
+  {
+    "Code": "TT"
+  },
+  {
+    "Code": "TV"
+  },
+  {
+    "Code": "TW"
+  },
+  {
+    "Code": "TZ"
+  },
+  {
+    "Code": "UA"
+  },
+  {
+    "Code": "UG"
+  },
+  {
+    "Code": "UM"
+  },
+  {
+    "Code": "US"
+  },
+  {
+    "Code": "UY"
+  },
+  {
+    "Code": "UZ"
+  },
+  {
+    "Code": "VA"
+  },
+  {
+    "Code": "VC"
+  },
+  {
+    "Code": "VE"
+  },
+  {
+    "Code": "VG"
+  },
+  {
+    "Code": "VI"
+  },
+  {
+    "Code": "VN"
+  },
+  {
+    "Code": "VU"
+  },
+  {
+    "Code": "WF"
+  },
+  {
+    "Code": "WS"
+  },
+  {
+    "Code": "YE"
+  },
+  {
+    "Code": "YT"
+  },
+  {
+    "Code": "ZA"
+  },
+  {
+    "Code": "ZM"
+  },
+  {
+    "Code": "ZW"
+  }
+]
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Location/City.cs b/Test/Weather/Weather/Models/Location/City.cs
new file mode 100755 (executable)
index 0000000..7aac36c
--- /dev/null
@@ -0,0 +1,52 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Location
+{
+    /// <summary>
+    /// Single city model.
+    /// </summary>
+    public class City
+    {
+        #region properties
+
+        /// <summary>
+        /// Id of the city.
+        /// </summary>
+        [JsonProperty(PropertyName = "id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Name of the city.
+        /// </summary>
+        [JsonProperty(PropertyName = "name")]
+        public string Name { get; set; }
+
+        /// <summary>
+        /// Country code in ISO 3166 format.
+        /// </summary>
+        [JsonProperty(PropertyName = "country")]
+        public string CountryCode { get; set; }
+
+        /// <summary>
+        /// Coordinates of the city.
+        /// </summary>
+        [JsonProperty(PropertyName = "coord")]
+        public Coordinates Coordinates { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Location/Coordinates.cs b/Test/Weather/Weather/Models/Location/Coordinates.cs
new file mode 100755 (executable)
index 0000000..e9a0109
--- /dev/null
@@ -0,0 +1,40 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Location
+{
+    /// <summary>
+    /// Coordinates of a city.
+    /// </summary>
+    public class Coordinates
+    {
+        #region properties
+
+        /// <summary>
+        /// North-South position of a city on the Earth's surface.
+        /// </summary>
+        [JsonProperty(PropertyName = "lon")]
+        public double Longitude { get; set; }
+
+        /// <summary>
+        /// East-west position of a city on the Earth's surface.
+        /// </summary>
+        [JsonProperty(PropertyName = "lat")]
+        public double Latitude { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Location/Country.cs b/Test/Weather/Weather/Models/Location/Country.cs
new file mode 100755 (executable)
index 0000000..2d35a96
--- /dev/null
@@ -0,0 +1,30 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Location
+{
+    /// <summary>
+    /// Single country model.
+    /// </summary>
+    public class Country
+    {
+        /// <summary>
+        /// Country code in ISO 3166 format.
+        /// </summary>
+        [JsonProperty(PropertyName = "Code")]
+        public string Code { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Location/TimeZone.cs b/Test/Weather/Weather/Models/Location/TimeZone.cs
new file mode 100755 (executable)
index 0000000..ba55fa6
--- /dev/null
@@ -0,0 +1,49 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+using Xamarin.Forms;
+
+namespace Weather.Models.Location
+{
+    /// <summary>
+    /// Time zone model.
+    /// </summary>
+    public class TimeZone : BindableObject
+    {
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set timestamp offset of timezone.
+        /// </summary>
+        public static readonly BindableProperty OffsetProperty =
+            BindableProperty.Create(nameof(Offset), typeof(int), typeof(TimeZone), default(int));
+
+        /// <summary>
+        /// Gets or sets timestamp offset of timezone.
+        /// </summary>
+        [JsonProperty(PropertyName = "rawOffset")]
+        public int Offset
+        {
+            get => (int)GetValue(OffsetProperty);
+            set
+            {
+                SetValue(OffsetProperty, value);
+                OnPropertyChanged();
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/Clouds.cs b/Test/Weather/Weather/Models/Weather/Clouds.cs
new file mode 100755 (executable)
index 0000000..a33934e
--- /dev/null
@@ -0,0 +1,33 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+using Newtonsoft.Json;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Class containing data about cloudiness.
+    /// </summary>
+    public class Clouds
+    {
+        #region properties
+
+        /// <summary>
+        /// Cloudiness in percent.
+        /// </summary>
+        [JsonProperty(PropertyName = "all")]
+        public double Percent { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/CurrentWeather.cs b/Test/Weather/Weather/Models/Weather/CurrentWeather.cs
new file mode 100755 (executable)
index 0000000..21ec22d
--- /dev/null
@@ -0,0 +1,72 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using Weather.Models.Location;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Current weather model.
+    /// </summary>
+    public class CurrentWeather
+    {
+        #region properties
+
+        /// <summary>
+        /// List of base weather properties, e.g. "Clear sky" etc.
+        /// </summary>
+        [JsonProperty(PropertyName = "weather")]
+        public IList<WeatherBase> Weather { get; set; }
+
+        /// <summary>
+        /// Weather data, e.g. temperature, pressure, etc.
+        /// </summary>
+        [JsonProperty(PropertyName = "main")]
+        public WeatherData WeatherData { get; set; }
+
+        /// <summary>
+        /// Wind properties, e.g. speed.
+        /// </summary>
+        [JsonProperty(PropertyName = "wind")]
+        public Wind Wind { get; set; }
+
+        /// <summary>
+        /// Cloudiness data.
+        /// </summary>
+        [JsonProperty(PropertyName = "clouds")]
+        public Clouds Clouds { get; set; }
+
+        /// <summary>
+        /// Time stamp of the weather measurement.
+        /// </summary>
+        [JsonProperty(PropertyName = "dt")]
+        public ulong TimeStamp { get; set; }
+
+        /// <summary>
+        /// Sunrise and sunset times.
+        /// </summary>
+        [JsonProperty(PropertyName = "sys")]
+        public SunData SunData { get; set; }
+
+        /// <summary>
+        /// City name.
+        /// </summary>
+        [JsonProperty(PropertyName = "name")]
+        public string CityName { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/Forecast.cs b/Test/Weather/Weather/Models/Weather/Forecast.cs
new file mode 100755 (executable)
index 0000000..99cd0a5
--- /dev/null
@@ -0,0 +1,32 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Collections.Generic;
+using Newtonsoft.Json;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Forecast model.
+    /// </summary>
+    public class Forecast
+    {
+        /// <summary>
+        /// List of weather data for next days.
+        /// Obtains data from "OpenWeatherMap" API.
+        /// </summary>
+        [JsonProperty(PropertyName = "list")]
+        public IList<CurrentWeather> WeatherList { get; set; }
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/SunData.cs b/Test/Weather/Weather/Models/Weather/SunData.cs
new file mode 100755 (executable)
index 0000000..d7030a0
--- /dev/null
@@ -0,0 +1,40 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Class containing additional weather data.
+    /// </summary>
+    public class SunData
+    {
+        #region properties
+
+        /// <summary>
+        /// Time stamp of sunrise.
+        /// </summary>
+        [JsonProperty(PropertyName = "sunrise")]
+        public ulong SunriseTimeStamp { get; set; }
+
+        /// <summary>
+        /// Time stamp of sunset.
+        /// </summary>
+        [JsonProperty(PropertyName = "sunset")]
+        public ulong SunsetTimeStamp { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/WeatherBase.cs b/Test/Weather/Weather/Models/Weather/WeatherBase.cs
new file mode 100755 (executable)
index 0000000..d286e5b
--- /dev/null
@@ -0,0 +1,52 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Class containing basic weather information.
+    /// </summary>
+    public class WeatherBase
+    {
+        #region properties
+
+        /// <summary>
+        /// Weather condition id.
+        /// </summary>
+        [JsonProperty(PropertyName = "id")]
+        public int Id { get; set; }
+
+        /// <summary>
+        /// Weather condition (e.g. Rain, Snow, Clear).
+        /// </summary>
+        [JsonProperty(PropertyName = "main")]
+        public string Condition { get; set; }
+
+        /// <summary>
+        /// Weather condition within the group.
+        /// </summary>
+        [JsonProperty(PropertyName = "description")]
+        public string Description { get; set; }
+
+        /// <summary>
+        /// Weather icon id.
+        /// </summary>
+        [JsonProperty(PropertyName = "icon")]
+        public string Icon { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/WeatherData.cs b/Test/Weather/Weather/Models/Weather/WeatherData.cs
new file mode 100755 (executable)
index 0000000..3a9db25
--- /dev/null
@@ -0,0 +1,52 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Class containing weather data.
+    /// </summary>
+    public class WeatherData
+    {
+        #region properties
+
+        /// <summary>
+        /// Temperature in degrees Celsius.
+        /// </summary>
+        [JsonProperty(PropertyName = "temp")]
+        public double Temperature { get; set; }
+
+        /// <summary>
+        /// Minimum temperature at the moment. Significant for large cities.
+        /// </summary>
+        [JsonProperty(PropertyName = "temp_min")]
+        public double MinimumTemperature { get; set; }
+
+        /// <summary>
+        /// Maximum temperature at the moment. Significant for large cities.
+        /// </summary>
+        [JsonProperty(PropertyName = "temp_max")]
+        public double MaximumTemperature { get; set; }
+
+        /// <summary>
+        /// Atmospheric pressure in hPa.
+        /// </summary>
+        [JsonProperty(PropertyName = "pressure")]
+        public double Pressure { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Models/Weather/Wind.cs b/Test/Weather/Weather/Models/Weather/Wind.cs
new file mode 100755 (executable)
index 0000000..ab8c223
--- /dev/null
@@ -0,0 +1,40 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Newtonsoft.Json;
+
+namespace Weather.Models.Weather
+{
+    /// <summary>
+    /// Class containing wind data.
+    /// </summary>
+    public class Wind
+    {
+        #region properties
+
+        /// <summary>
+        /// Wind speed in meters per second.
+        /// </summary>
+        [JsonProperty(PropertyName = "speed")]
+        public double Speed { get; set; }
+
+        /// <summary>
+        /// Wind direction in degrees.
+        /// </summary>
+        [JsonProperty(PropertyName = "deg")]
+        public double Degree { get; set; }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Service/CityProvider.cs b/Test/Weather/Weather/Service/CityProvider.cs
new file mode 100755 (executable)
index 0000000..32c6bc1
--- /dev/null
@@ -0,0 +1,92 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Collections.Generic;
+using System.Linq;
+using Weather.Models.Location;
+
+namespace Weather.Service
+{
+    /// <summary>
+    /// Class that manages supported cities.
+    /// </summary>
+    public class CityProvider : ICityProvider
+    {
+        #region properties
+
+        /// <summary>
+        /// List of supported cities with their data.
+        /// </summary>
+        public IQueryable<City> CityList { get; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Class constructor which allows to set supported cities.
+        /// </summary>
+        /// <param name="cityList">Supported city list.</param>
+        public CityProvider(IQueryable<City> cityList)
+        {
+            CityList = cityList;
+        }
+
+        /// <summary>
+        /// Indicates if given cityName is in supported city list.
+        /// </summary>
+        /// <param name="cityName">Name of the city to check.</param>
+        /// <returns>True if city is found in the list, otherwise false is returned.</returns>
+        public bool Validate(string cityName)
+        {
+            return CityList.Any(x => x.Name.Equals(cityName));
+        }
+
+        /// <summary>
+        /// Finds first n cities that start with given text.
+        /// </summary>
+        /// <param name="text">Search condition.</param>
+        /// <param name="n">Maximum number of cities that will be returned.</param>
+        /// <returns>List of cities if found, otherwise null is returned.</returns>
+        public IList<City> FindCity(string text, int n)
+        {
+            return CityList.Where(cityItem => cityItem.Name.ToLower().StartsWith(text.ToLower())).Take(n).ToList();
+        }
+
+        /// <summary>
+        /// Finds first n cities that starts with given text.
+        /// Finds cities only in country specified with country code in ISO-3166 format.
+        /// </summary>
+        /// <param name="text">Search condition.</param>
+        /// <param name="countryCode">Country code in ISO-3166 format.</param>
+        /// <param name="n">Maximum number of cities that will be returned.</param>
+        /// <returns>List of cities if found otherwise returns null.</returns>
+        public IList<City> FindCity(string text, string countryCode, int n)
+        {
+            return CityList
+                .Where(cityItem => cityItem.Name.ToLower().StartsWith(text.ToLower()) && cityItem.CountryCode.Equals(countryCode)).Take(n)
+                .ToList();
+        }
+
+
+        /// <summary>
+        /// Gets first occurrence of city with given name.
+        /// </summary>
+        /// <param name="cityName">Name of the city.</param>
+        /// <returns>City with given name otherwise returns null.</returns>
+        public City GetCiy(string cityName) => CityList.FirstOrDefault(x => x.Name.Equals(cityName));
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Service/CountryProvider.cs b/Test/Weather/Weather/Service/CountryProvider.cs
new file mode 100755 (executable)
index 0000000..639b9f1
--- /dev/null
@@ -0,0 +1,67 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Linq;
+using System.Text.RegularExpressions;
+using Weather.Models.Location;
+
+namespace Weather.Service
+{
+    /// <summary>
+    /// Class that manages supported countries.
+    /// </summary>
+    public class CountryProvider : ICountryProvider
+    {
+        #region fields
+
+        /// <summary>
+        /// Country code validation rule.
+        /// </summary>
+        private const string COUNTRY_REGEX = "^[A-Z]{2}$";
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// Supported country list.
+        /// </summary>
+        public IQueryable<Country> CountryList { get; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Class constructor which allows to set supported country list.
+        /// </summary>
+        /// <param name="countryList">Supported country list.</param>
+        public CountryProvider(IQueryable<Country> countryList)
+        {
+            CountryList = countryList;
+        }
+
+        /// <summary>
+        /// Checks if given countryCode is in accordance with ISO 3166 standard.
+        /// </summary>
+        /// <param name="countryCode">Country Code.</param>
+        /// <returns>True if code is valid, otherwise false is returned.</returns>
+        public bool Validate(string countryCode)
+        {
+            return Regex.IsMatch(countryCode, COUNTRY_REGEX) && CountryList.Any(x => x.Code.Equals(countryCode));
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Service/ICityProvider.cs b/Test/Weather/Weather/Service/ICityProvider.cs
new file mode 100755 (executable)
index 0000000..c249899
--- /dev/null
@@ -0,0 +1,71 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Collections.Generic;
+using System.Linq;
+using Weather.Models.Location;
+
+namespace Weather.Service
+{
+    /// <summary>
+    /// Interface that contains all necessary tools to manage supported cities.
+    /// </summary>
+    public interface ICityProvider
+    {
+        #region properties
+
+        /// <summary>
+        /// List of supported cities with their data.
+        /// </summary>
+        IQueryable<City> CityList { get; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Indicates if given cityName is in supported city list.
+        /// </summary>
+        /// <param name="cityName">Name of the city to check.</param>
+        /// <returns>True if city is found in the list otherwise returns false.</returns>
+        bool Validate(string cityName);
+
+        /// <summary>
+        /// Finds first n cities that starts with given text.
+        /// </summary>
+        /// <param name="text">Search condition.</param>
+        /// <param name="n">Maximum number of cities that will be returned.</param>
+        /// <returns>List of cities if found otherwise returns null.</returns>
+        IList<City> FindCity(string text, int n);
+
+        /// <summary>
+        /// Finds first n cities that starts with given text.
+        /// Finds cities only in country specified with country code in ISO-3166 format.
+        /// </summary>
+        /// <param name="text">Search condition.</param>
+        /// <param name="countryCode">Country code in ISO-3166 format.</param>
+        /// <param name="n">Maximum number of cities that will be returned.</param>
+        /// <returns>List of cities if found otherwise returns null.</returns>
+        IList<City> FindCity(string text, string countryCode, int n);
+
+        /// <summary>
+        /// Gets first occurrence of city with given name.
+        /// </summary>
+        /// <param name="cityName">Name of the city.</param>
+        /// <returns>City with given name otherwise returns null.</returns>
+        City GetCiy(string cityName);
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Service/ICountryProvider.cs b/Test/Weather/Weather/Service/ICountryProvider.cs
new file mode 100755 (executable)
index 0000000..4c29a46
--- /dev/null
@@ -0,0 +1,45 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Linq;
+using Weather.Models.Location;
+
+namespace Weather.Service
+{
+    /// <summary>
+    /// Interface that contains all necessary tools to manage supported countries.
+    /// </summary>
+    public interface ICountryProvider
+    {
+        #region properties
+
+        /// <summary>
+        /// List of codes of all supported countries.
+        /// </summary>
+        IQueryable<Country> CountryList { get; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Checks if given country code is valid.
+        /// </summary>
+        /// <param name="countryCode">Country code.</param>
+        /// <returns>Returns true if code is valid, otherwise returns false.</returns>
+        bool Validate(string countryCode);
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/BindableString.cs b/Test/Weather/Weather/Utils/BindableString.cs
new file mode 100755 (executable)
index 0000000..2ae9421
--- /dev/null
@@ -0,0 +1,56 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Xamarin.Forms;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Helper class that allows to bind string value.
+    /// </summary>
+    public class BindableString : BindableObject
+    {
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set value of string.
+        /// </summary>
+        public static readonly BindableProperty ValueProperty =
+            BindableProperty.Create(nameof(Value), typeof(string), typeof(BindableString), string.Empty);
+
+        /// <summary>
+        /// Gets or sets value of string.
+        /// </summary>
+        public string Value
+        {
+            get => GetValue(ValueProperty).ToString();
+            set => SetValue(ValueProperty, value);
+        }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Returns string value instead of class string representation.
+        /// </summary>
+        /// <returns>String value.</returns>
+        public override string ToString()
+        {
+            return Value;
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/ErrorHandler.cs b/Test/Weather/Weather/Utils/ErrorHandler.cs
new file mode 100755 (executable)
index 0000000..216f9ed
--- /dev/null
@@ -0,0 +1,106 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Linq;
+using System.Threading.Tasks;
+using Xamarin.Forms;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Class responsible for handling HTTP errors and displaying information about them.
+    /// </summary>
+    public static class ErrorHandler
+    {
+        #region fields
+
+        /// <summary>
+        /// Navigation context.
+        /// </summary>
+        private static readonly INavigation _navigation;
+
+        /// <summary>
+        /// Indicates if any error was handled.
+        /// Avoids handling multiple error at once.
+        /// </summary>
+        private static bool _isHandled;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// HTTP status code.
+        /// </summary>
+        public static int Code { get; private set; }
+
+        /// <summary>
+        /// Message provided with exception.
+        /// </summary>
+        public static string Message { get; private set; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default constructor.
+        /// </summary>
+        static ErrorHandler()
+        {
+            _navigation = Application.Current.MainPage.Navigation;
+        }
+
+        /// <summary>
+        /// Handles exception.
+        /// </summary>
+        /// <param name="code">HTTP status code.</param>
+        /// <param name="message">Message provided with exception.</param>
+        /// <returns>Async task.</returns>
+        public static async Task HandleException(int code, string message)
+        {
+            if (_isHandled)
+            {
+                return;
+            }
+
+            Code = code;
+            Message = message;
+
+            await _navigation.PushAsync(new Views.ApiErrorPage());
+
+            RemoveExistingPages();
+
+            _isHandled = true;
+        }
+
+        /// <summary>
+        /// Removes all pages from navigation stack except error page.
+        /// </summary>
+        private static void RemoveExistingPages()
+        {
+            var existingPages = _navigation.NavigationStack.ToList();
+
+            foreach (var page in existingPages)
+            {
+                if (page.GetType() != typeof(Views.ApiErrorPage))
+                {
+                    _navigation.RemovePage(page);
+                }
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/HttpException.cs b/Test/Weather/Weather/Utils/HttpException.cs
new file mode 100755 (executable)
index 0000000..3176f96
--- /dev/null
@@ -0,0 +1,47 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Net;
+using System.Net.Http;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Exception that is thrown on HTTP errors.
+    /// </summary>
+    public class HttpException : HttpRequestException
+    {
+        #region properties
+
+        /// <summary>
+        /// HTTP status code.
+        /// </summary>
+        public HttpStatusCode StatusCode { get; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default constructor.
+        /// </summary>
+        /// <param name="code">HTTP status code of error.</param>
+        public HttpException(HttpStatusCode code)
+        {
+            StatusCode = code;
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/IRequest.cs b/Test/Weather/Weather/Utils/IRequest.cs
new file mode 100755 (executable)
index 0000000..5d21e2d
--- /dev/null
@@ -0,0 +1,51 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Threading.Tasks;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Provides functionality to get response from Web API.
+    /// </summary>
+    /// <typeparam name="T">The type of expected object from API.</typeparam>
+    public interface IRequest<T>
+    {
+        #region properties
+
+        /// <summary>
+        /// URI of the Web service.
+        /// </summary>
+        string RequestUri { get; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Adds parameter to the URI.
+        /// </summary>
+        /// <param name="name">Name of the parameter.</param>
+        /// <param name="value">Value of the parameter.</param>
+        void AddParameter(string name, string value);
+
+        /// <summary>
+        /// Sends HTTP request using GET method.
+        /// </summary>
+        /// <returns>Response from service.</returns>
+        Task<T> Get();
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/JsonFileReader.cs b/Test/Weather/Weather/Utils/JsonFileReader.cs
new file mode 100755 (executable)
index 0000000..1dd53d4
--- /dev/null
@@ -0,0 +1,82 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.IO;
+using System.Reflection;
+using Newtonsoft.Json;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Class that reads JSON file and converts it to given type.
+    /// </summary>
+    /// <typeparam name="T">JSON object type.</typeparam>
+    public class JsonFileReader<T>
+    {
+        #region fields
+
+        /// <summary>
+        /// Namespace of the file.
+        /// </summary>
+        private readonly string _fileNameSpace;
+
+        /// <summary>
+        /// File name.
+        /// </summary>
+        private readonly string _fileName;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// File content in T format.
+        /// </summary>
+        /// <remarks>Before calling Read methods, it is always null.</remarks>
+        public T Result { get; set; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Class constructor, which allows to specify file location and name.
+        /// </summary>
+        /// <param name="fileNameSpace">Namespace of the file.</param>
+        /// <param name="fileName">Name of the file.</param>
+        public JsonFileReader(string fileNameSpace, string fileName)
+        {
+            _fileNameSpace = fileNameSpace;
+            _fileName = fileName;
+        }
+
+        /// <summary>
+        /// Reads the file.
+        /// </summary>
+        public virtual void Read()
+        {
+            var assembly = typeof(JsonFileReader<T>).GetTypeInfo().Assembly;
+
+            using (var stream = assembly.GetManifestResourceStream(_fileNameSpace + _fileName))
+            using (var streamReader = new StreamReader(stream))
+            using (var reader = new JsonTextReader(streamReader))
+            {
+                var serializer = JsonSerializer.Create();
+                Result = serializer.Deserialize<T>(reader);
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/NotificationTask.cs b/Test/Weather/Weather/Utils/NotificationTask.cs
new file mode 100755 (executable)
index 0000000..870b25d
--- /dev/null
@@ -0,0 +1,160 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Class that allows binding to task.
+    /// After task is completed it notify view about it.
+    /// </summary>
+    /// <typeparam name="T">Type of the result of the task.</typeparam>
+    public class NotificationTask<T> : INotifyPropertyChanged
+    {
+        #region properties
+
+        /// <summary>
+        /// Task that will be executed.
+        /// </summary>
+        public Task<T> Task { get; }
+
+        /// <summary>
+        /// Gets result of the task.
+        /// </summary>
+        public T Result => Task.Status == TaskStatus.RanToCompletion ? Task.Result : default(T);
+
+        /// <summary>
+        /// Gets status of the task.
+        /// </summary>
+        public TaskStatus Status => Task.Status;
+
+        /// <summary>
+        /// Indicates if task is completed.
+        /// </summary>
+        public bool IsCompleted => Task.IsCompleted;
+
+        /// <summary>
+        /// Indicates if task is completed successfully.
+        /// </summary>
+        public bool IsSuccessfullyCompleted => Task.Status == TaskStatus.RanToCompletion;
+
+        /// <summary>
+        /// Indicates if task is not completed.
+        /// </summary>
+        public bool IsNotCompleted => !Task.IsCompleted;
+
+        /// <summary>
+        /// Indicates if task is cancelled.
+        /// </summary>
+        public bool IsCanceled => Task.IsCanceled;
+
+        /// <summary>
+        /// Indicates if task is faulted.
+        /// </summary>
+        public bool IsFaulted => Task.IsFaulted;
+
+        /// <summary>
+        /// Gets all exceptions from execution of the task.
+        /// </summary>
+        public AggregateException Exception => Task.Exception;
+
+        /// <summary>
+        /// Gets current exception from execution of the task.
+        /// </summary>
+        public Exception InnerException => Exception?.InnerException;
+
+        /// <summary>
+        /// Event that informs view about property change.
+        /// </summary>
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        /// <param name="task">Task to be executed.</param>
+        public NotificationTask(Task<T> task)
+        {
+            Task = task;
+
+            if (!task.IsCompleted)
+            {
+                var taskAsync = ExecuteTaskAsync(task);
+            }
+        }
+
+        /// <summary>
+        /// Executes task and notifies view about changes of its properties.
+        /// </summary>
+        /// <param name="task">Task to be executed.</param>
+        /// <returns>Task that was executed.</returns>
+        private async Task ExecuteTaskAsync(Task task)
+        {
+            try
+            {
+                await task;
+            }
+            catch (Exception e)
+            {
+                Debug.WriteLine(e);
+            }
+
+            var propertyChanged = PropertyChanged;
+            if (propertyChanged == null)
+            {
+                return;
+            }
+
+            propertyChanged(this, new PropertyChangedEventArgs(nameof(Status)));
+            propertyChanged(this, new PropertyChangedEventArgs(nameof(IsCompleted)));
+            propertyChanged(this, new PropertyChangedEventArgs(nameof(IsNotCompleted)));
+
+            if (Task.IsCanceled)
+            {
+                propertyChanged(this, new PropertyChangedEventArgs(nameof(IsCanceled)));
+            }
+            else if (Task.IsFaulted)
+            {
+                propertyChanged(this, new PropertyChangedEventArgs(nameof(IsFaulted)));
+                propertyChanged(this, new PropertyChangedEventArgs(nameof(Exception)));
+                propertyChanged(this, new PropertyChangedEventArgs(nameof(InnerException)));
+            }
+            else
+            {
+                propertyChanged(this, new PropertyChangedEventArgs(nameof(IsSuccessfullyCompleted)));
+                propertyChanged(this, new PropertyChangedEventArgs(nameof(Result)));
+            }
+        }
+
+        /// <summary>
+        /// PropertyChanged event invoker.
+        /// </summary>
+        /// <param name="propertyName">Property name.</param>
+        protected virtual void OnPropertyChanged(string propertyName)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/Request.cs b/Test/Weather/Weather/Utils/Request.cs
new file mode 100755 (executable)
index 0000000..b16fbbf
--- /dev/null
@@ -0,0 +1,114 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.IO;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Newtonsoft.Json;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Class responsible for sending HTTP requests.
+    /// </summary>
+    /// <typeparam name="T">The type of expected object from API.</typeparam>
+    public class Request<T> : IRequest<T>
+    {
+        #region fields
+
+        /// <summary>
+        /// HTTP client.
+        /// </summary>
+        private readonly HttpClient _httpClient;
+
+        private bool _isFirstParameter = true;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// URI of the Web service.
+        /// </summary>
+        public string RequestUri { get; protected set; }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Class constructor that allows to set API key and address of the server.
+        /// </summary>
+        /// <param name="address">Server address.</param>
+        public Request(string address)
+        {
+            _httpClient = new HttpClient();
+            RequestUri = address;
+        }
+
+        /// <summary>
+        /// Adds parameter to the URI.
+        /// </summary>
+        /// <param name="name">Name of the parameter.</param>
+        /// <param name="value">Value of the parameter.</param>
+        public void AddParameter(string name, string value)
+        {
+            if (_isFirstParameter)
+            {
+                RequestUri += $"?{name}={value}";
+                _isFirstParameter = false;
+            }
+            else
+            {
+                RequestUri += $"&{name}={value}";
+            }
+        }
+
+        /// <summary>
+        /// Sends HTTP request using GET method.
+        /// </summary>
+        /// <returns>Response from service.</returns>
+        public async Task<T> Get()
+        {
+            var response = await _httpClient.GetAsync(RequestUri);
+
+            if (!response.IsSuccessStatusCode)
+            {
+                throw new HttpException(response.StatusCode);
+            }
+
+            return ReadStream(await response.Content.ReadAsStreamAsync());
+        }
+
+        /// <summary>
+        /// Gets stream from HTTP client and deserializes it to the object.
+        /// </summary>
+        /// <param name="stream">Stream from client.</param>
+        /// <returns>
+        /// Returns type T object with response.
+        /// If deserializing was not successful returns default value of type T.
+        /// </returns>
+        private static T ReadStream(Stream stream)
+        {
+            using (var streamReader = new StreamReader(stream))
+            using (var reader = new JsonTextReader(streamReader))
+            {
+                var serializer = JsonSerializer.Create();
+                return serializer.Deserialize<T>(reader);
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/TimeStamp.cs b/Test/Weather/Weather/Utils/TimeStamp.cs
new file mode 100755 (executable)
index 0000000..1144539
--- /dev/null
@@ -0,0 +1,50 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Class that is responsible for converting timestamp.
+    /// </summary>
+    public static class TimeStamp
+    {
+        #region methods
+
+        /// <summary>
+        /// Converts timestamp to "DateTime" object.
+        /// </summary>
+        /// <param name="utcTimeStamp">UTC timestamp.</param>
+        /// <returns>"DateTime" object.</returns>
+        public static DateTime Convert(ulong utcTimeStamp)
+        {
+            var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+            return dateTime.AddSeconds(utcTimeStamp);
+        }
+
+        /// <summary>
+        /// Converts timestamp to "DateTime" object.
+        /// </summary>
+        /// <param name="utcTimeStamp">UTC timestamp.</param>
+        /// <returns>"DateTime" object.</returns>
+        public static DateTime Convert(long utcTimeStamp)
+        {
+            var dateTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+            return dateTime.AddSeconds(utcTimeStamp);
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Utils/UnitFormatter.cs b/Test/Weather/Weather/Utils/UnitFormatter.cs
new file mode 100755 (executable)
index 0000000..3f9da67
--- /dev/null
@@ -0,0 +1,76 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Globalization;
+
+namespace Weather.Utils
+{
+    /// <summary>
+    /// Class that provide custom formatter for string.
+    /// </summary>
+    public class UnitFormatter : IFormatProvider, ICustomFormatter
+    {
+        #region methods
+
+        /// <summary>
+        /// Gets an object that provides formatting services for the specified type.
+        /// </summary>
+        /// <param name="formatType">An object that specifies the type of format object to return.</param>
+        /// <returns>An instance of the object specified by formatType.</returns>
+        public object GetFormat(Type formatType)
+        {
+            return formatType == typeof(ICustomFormatter) ? this : null;
+        }
+
+        /// <summary>
+        /// Converts the value of a specified object to an equivalent string representation.
+        /// </summary>
+        /// <param name="fmt">A format string containing formatting specifications.</param>
+        /// <param name="arg">An object to format.</param>
+        /// <param name="formatProvider">An object that supplies format information about the current instance.</param>
+        /// <returns>
+        /// The string representation of the arg, formatted as specified by format and formatProvider.
+        /// </returns>
+        public string Format(string fmt, object arg, IFormatProvider formatProvider)
+        {
+            if (arg == null)
+            {
+                return string.Empty;
+            }
+
+            switch (fmt)
+            {
+                case "temp":
+                {
+                    var sign = RegionInfo.CurrentRegion.IsMetric ? "°C" : "°F";
+                    return $"{arg:0.0}{sign}";
+                }
+
+                case "speed":
+                {
+                    var sign = RegionInfo.CurrentRegion.IsMetric ? " m/s" : " mph";
+                    return $"{arg:0.00}{sign}";
+                }
+
+                default:
+                {
+                    return arg.ToString();
+                }
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/ViewModels/ApiErrorViewModel.cs b/Test/Weather/Weather/ViewModels/ApiErrorViewModel.cs
new file mode 100755 (executable)
index 0000000..136c97d
--- /dev/null
@@ -0,0 +1,45 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.ViewModels
+{
+    /// <summary>
+    /// ViewModel class for ApiErrorPage.
+    /// </summary>
+    public class ApiErrorViewModel
+    {
+        #region properties
+
+        /// <summary>
+        /// Gets HTTP status code.
+        /// </summary>
+        public int Code => ErrorHandler.Code;
+
+        /// <summary>
+        /// Gets message provided with exception.
+        /// </summary>
+        public string Message => ErrorHandler.Message ?? "None";
+
+        /// <summary>
+        /// Gets command that exits application.
+        /// </summary>
+        public Command ExitAppCommand { get; } = new Command(() => { Xamarin.Forms.Forms.Context.Exit();  });
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/ViewModels/CurrentWeatherViewModel.cs b/Test/Weather/Weather/ViewModels/CurrentWeatherViewModel.cs
new file mode 100755 (executable)
index 0000000..4450885
--- /dev/null
@@ -0,0 +1,325 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Threading.Tasks;
+using Weather.Config;
+using Weather.Models.Location;
+using Weather.Models.Weather;
+using Weather.Utils;
+using Xamarin.Forms;
+
+namespace Weather.ViewModels
+{
+    /// <summary>
+    /// ViewModel class for CurrentWeatherPage.
+    /// </summary>
+    public class CurrentWeatherViewModel : ViewModelBase
+    {
+        #region fields
+
+        /// <summary>
+        /// Local storage of command that initializes weather data.
+        /// </summary>
+        private Command _initializeCommand;
+
+        /// <summary>
+        /// Local storage of task that obtains current weather.
+        /// </summary>
+        private NotificationTask<CurrentWeather> _currentWeather;
+
+        /// <summary>
+        /// Local storage of city time zone.
+        /// </summary>
+        private NotificationTask<Models.Location.TimeZone> _cityTimeZone;
+
+        /// <summary>
+        /// Local storage of command that shows screen with forecast.
+        /// </summary>
+        private Command _checkForecastCommand;
+
+        /// <summary>
+        /// Local storage of forecast data.
+        /// </summary>
+        private NotificationTask<Forecast> _forecast;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set city data.
+        /// </summary>
+        public static readonly BindableProperty CityDataProperty =
+            BindableProperty.Create(nameof(CityData), typeof(City), typeof(CurrentWeatherViewModel), default(City));
+
+        /// <summary>
+        /// Bindable property that allows to set navigation context.
+        /// </summary>
+        public static readonly BindableProperty NavigationProperty =
+            BindableProperty.Create(nameof(Navigation), typeof(INavigation), typeof(MainPageViewModel), default(Type));
+
+        /// <summary>
+        /// Gets or sets city data.
+        /// View model holds weather data for this city.
+        /// </summary>
+        public City CityData
+        {
+            get => (City)GetValue(CityDataProperty);
+            set => SetValue(CityDataProperty, value);
+        }
+
+        /// <summary>
+        /// Gets or sets task that obtains current weather.
+        /// </summary>
+        public NotificationTask<CurrentWeather> CurrentWeather
+        {
+            get => _currentWeather;
+            set => SetProperty(ref _currentWeather, value);
+        }
+
+        /// <summary>
+        /// Gets or sets city time zone.
+        /// </summary>
+        public NotificationTask<Models.Location.TimeZone> CityTimeZone
+        {
+            get => _cityTimeZone;
+            set => SetProperty(ref _cityTimeZone, value);
+        }
+
+        /// <summary>
+        /// Gets or sets command that initializes weather data.
+        /// </summary>
+        public Command InitializeCommand
+        {
+            get => _initializeCommand;
+            set => SetProperty(ref _initializeCommand, value);
+        }
+
+        /// <summary>
+        /// Gets or sets command that shows screen with forecast.
+        /// </summary>
+        public Command CheckForecastCommand
+        {
+            get => _checkForecastCommand;
+            set => SetProperty(ref _checkForecastCommand, value);
+        }
+
+        /// <summary>
+        /// Gets or sets navigation context of application.
+        /// </summary>
+        public INavigation Navigation
+        {
+            get => (INavigation)GetValue(NavigationProperty);
+            set => SetValue(NavigationProperty, value);
+        }
+
+        /// <summary>
+        /// Gets or sets forecast data.
+        /// </summary>
+        public NotificationTask<Forecast> Forecast
+        {
+            get => _forecast;
+            set => SetProperty(ref _forecast, value);
+        }
+
+        /// <summary>
+        /// Indicates if initialization was completed.
+        /// </summary>
+        public bool InitializationCompleted => ((App)Application.Current).IsInitialized =
+            Forecast != null && CurrentWeather != null && CityTimeZone != null &&
+            Forecast.IsSuccessfullyCompleted &&
+            CurrentWeather.IsSuccessfullyCompleted &&
+            CityTimeZone.IsSuccessfullyCompleted;
+
+        public bool InitializationInProgress => !InitializationCompleted;
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public CurrentWeatherViewModel()
+        {
+            InitializeCommand = new Command(o =>
+            {
+                CurrentWeather = null;
+                Forecast = null;
+                OnPropertyChanged(nameof(InitializationCompleted));
+                OnPropertyChanged(nameof(InitializationInProgress));
+
+                CityTimeZone = new NotificationTask<Models.Location.TimeZone>(InitializeTimeZone());
+                CityTimeZone.PropertyChanged += CityTimeZoneOnPropertyChanged;
+            });
+
+            CheckForecastCommand = new Command(CheckForecast);
+        }
+
+        /// <summary>
+        /// Pushes page with forecast data to navigation stack.
+        /// </summary>
+        /// <param name="param">Page to push to navigation stack.</param>
+        private void CheckForecast(object param)
+        {
+            if (param is Page page)
+            {
+                Navigation.PushAsync(page);
+            }
+        }
+
+        /// <summary>
+        /// Initializes current weather class.
+        /// Sends GET request to server.
+        /// </summary>
+        /// <returns>Async task with current weather.</returns>
+        private async Task<CurrentWeather> InitializeWeather()
+        {
+            var request = new Request<CurrentWeather>(ApiConfig.WEATHER_URL);
+
+            request.AddParameter("appid", ApiConfig.API_KEY);
+            request.AddParameter("id", CityData.Id.ToString());
+            request.AddParameter("units", RegionInfo.CurrentRegion.IsMetric ? "metric" : "imperial");
+
+            return await request.Get();
+        }
+
+        /// <summary>
+        /// Initializes forecast class.
+        /// Sends GET request to server.
+        /// </summary>
+        /// <returns>Async task with forecast data.</returns>
+        private async Task<Forecast> InitializeForecast()
+        {
+            var request = new Request<Forecast>(ApiConfig.FORECAST_URL);
+
+            request.AddParameter("appid", ApiConfig.API_KEY);
+            request.AddParameter("id", CityData.Id.ToString());
+            request.AddParameter("units", RegionInfo.CurrentRegion.IsMetric ? "metric" : "imperial");
+
+            return await request.Get();
+        }
+
+        /// <summary>
+        /// Initializes time zone for city.
+        /// </summary>
+        /// <returns>Async task with time zone.</returns>
+        private async Task<Models.Location.TimeZone> InitializeTimeZone()
+        {
+            var request = new Request<Models.Location.TimeZone>(ApiConfig.TIMEZONE_URL);
+
+            request.AddParameter("location", $"{CityData.Coordinates.Latitude},{CityData.Coordinates.Longitude}");
+            request.AddParameter("timestamp",
+                DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalSeconds.ToString());
+            request.AddParameter("sensor", "false");
+
+            return await request.Get();
+        }
+
+        /// <summary>
+        /// Starts request to weather API after time zone request is completed.
+        /// </summary>
+        /// <param name="sender">Object that sent event.</param>
+        /// <param name="propertyChangedEventArgs">Arguments of the event.</param>
+        private void CityTimeZoneOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
+        {
+            if (propertyChangedEventArgs.PropertyName == "Result")
+            {
+                CurrentWeather = new NotificationTask<CurrentWeather>(InitializeWeather());
+                Forecast = new NotificationTask<Forecast>(InitializeForecast());
+
+                CurrentWeather.PropertyChanged += CurrentWeatherOnPropertyChanged;
+                Forecast.PropertyChanged += ForecastOnPropertyChanged;
+            }
+        }
+
+        /// <summary>
+        /// Callback method that is invoked on Forecast property change.
+        /// </summary>
+        /// <param name="sender">Object that sent event.</param>
+        /// <param name="propertyChangedEventArgs">Arguments of the event.</param>
+        private void ForecastOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
+        {
+            var task = ForecastOnPropertyChangedTask(propertyChangedEventArgs.PropertyName);
+        }
+
+        /// <summary>
+        /// Callback method that is invoked on Current Weather property change.
+        /// </summary>
+        /// <param name="sender">Object that sent event.</param>
+        /// <param name="propertyChangedEventArgs">Arguments of the event.</param>
+        private void CurrentWeatherOnPropertyChanged(object sender,
+            PropertyChangedEventArgs propertyChangedEventArgs)
+        {
+            var task = CurrentWeatherOnPropertyChangedTask(propertyChangedEventArgs.PropertyName);
+        }
+
+        /// <summary>
+        /// Method executed when one of Forecast property has changed.
+        /// </summary>
+        /// <param name="propertyName">Name of property that has changed.</param>
+        /// <returns>Task to be executed.</returns>
+        private async Task ForecastOnPropertyChangedTask(string propertyName)
+        {
+            if (propertyName == nameof(NotificationTask<Forecast>.IsFaulted))
+            {
+                if (Forecast.InnerException is HttpException exception)
+                {
+                    await ErrorHandler.HandleException((int)exception.StatusCode, exception.StatusCode.ToString());
+                }
+            }
+
+            if (propertyName == nameof(NotificationTask<Forecast>.IsSuccessfullyCompleted))
+            {
+                foreach (var currentWeather in Forecast.Result.WeatherList)
+                {
+                    if (currentWeather != null)
+                    {
+                        currentWeather.CityName = CityData.Name;
+                    }
+                }
+
+                OnPropertyChanged(nameof(InitializationCompleted));
+                OnPropertyChanged(nameof(InitializationInProgress));
+            }
+        }
+
+        /// <summary>
+        /// Method executed when one of Current Weather property has changed.
+        /// </summary>
+        /// <param name="propertyName">Name of property that has changed.</param>
+        /// <returns>Task to be executed.</returns>
+        private async Task CurrentWeatherOnPropertyChangedTask(string propertyName)
+        {
+            if (propertyName == nameof(NotificationTask<CurrentWeather>.IsFaulted))
+            {
+                if (CurrentWeather.InnerException is HttpException exception)
+                {
+                    await ErrorHandler.HandleException((int)exception.StatusCode, exception.StatusCode.ToString());
+                }
+            }
+
+            if (propertyName == nameof(NotificationTask<CurrentWeather>.IsSuccessfullyCompleted))
+            {
+                OnPropertyChanged(nameof(InitializationCompleted));
+                OnPropertyChanged(nameof(InitializationInProgress));
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/ViewModels/ForecastViewModel.cs b/Test/Weather/Weather/ViewModels/ForecastViewModel.cs
new file mode 100755 (executable)
index 0000000..2c1e875
--- /dev/null
@@ -0,0 +1,270 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Weather.Models.Weather;
+using Weather.Utils;
+using Xamarin.Forms;
+using Tizen.System;
+using Tizen;
+
+namespace Weather.ViewModels
+{
+    /// <summary>
+    /// ViewModel class for forecast root page.
+    /// </summary>
+    public class ForecastViewModel : ViewModelBase
+    {
+        #region fields
+
+        /// <summary>
+        /// Local storage of all the forecasts (in CurrentWeather format)
+        /// </summary>
+        private ObservableCollection<CurrentWeather> _forecastsModels;
+
+        /// <summary>
+        /// Command to handle UI request for a previous forecast display
+        /// </summary>
+        private Command _previousForecastCommand;
+
+        /// <summary>
+        /// Command to handle UI request for next forecast display
+        /// </summary>
+        private Command _nextForecastCommand;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set forecast data.
+        /// </summary>
+        public static readonly BindableProperty ForecastProperty =
+            BindableProperty.Create(nameof(Forecast), typeof(Forecast), typeof(ForecastViewModel), default(Forecast),
+                propertyChanged: ForecastPropertyChanged);
+
+        /// <summary>
+        /// Bindable property that allows to set timezone offset property.
+        /// </summary>
+        public static readonly BindableProperty OffsetProperty =
+            BindableProperty.Create(nameof(Offset), typeof(int), typeof(ForecastViewModel), default(int));
+
+        /// <summary>
+        /// Bindable property that allows to set City Name property.
+        /// </summary>
+        public static readonly BindableProperty CityNameProperty =
+            BindableProperty.Create(nameof(CityName), typeof(string), typeof(ForecastViewModel), "");
+
+        /// <summary>
+        /// Gets or sets timezone offset property.
+        /// </summary>
+        public int Offset
+        {
+            get => (int)GetValue(OffsetProperty);
+            set => SetValue(OffsetProperty, value);
+        }
+
+        /// <summary>
+        /// Identifier of current forecast being presented in UI (id of an element in _forecastsModels table)
+        /// </summary>
+        public int CurrentForecastId { get; private set; } = 0;
+
+        /// <summary>
+        /// Readonly property referencing currently selected forecast
+        /// </summary>
+        public CurrentWeather SelectedForecast
+        {
+            get
+            {
+                if (ForecastsModels != null)
+                {
+                    return ForecastsModels[CurrentForecastId];
+                }
+                else
+                {
+                    return null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Get or set forecast data.
+        /// </summary>
+        public Forecast Forecast
+        {
+            get => (Forecast)GetValue(ForecastProperty);
+            set => SetValue(ForecastProperty, value);
+        }
+
+        /// <summary>
+        /// Get or set CityName property
+        /// </summary>
+        public string CityName
+        {
+            get => GetValue(CityNameProperty).ToString();
+            set => SetValue(CityNameProperty, value);
+        }
+
+        /// <summary>
+        /// Get or set _forecastsModels => Local storage of all the forecasts (in CurrentWeather format)
+        /// </summary>
+        public ObservableCollection<CurrentWeather> ForecastsModels
+        {
+            get => _forecastsModels;
+            set => SetProperty(ref _forecastsModels, value);
+        }
+
+        /// <summary>
+        /// Get or set _nextForecastCommand => Command to handle UI request for next forecast display
+        /// </summary>
+        public Command NextForecastCommand
+        {
+            get => _nextForecastCommand;
+            set => SetProperty(ref _nextForecastCommand, value);
+        }
+
+        /// <summary>
+        /// Get or set _previousForecastCommand => Command to handle UI request for a previous forecast display
+        /// </summary>
+        public Command PreviousForecastCommand
+        {
+            get => _previousForecastCommand;
+            set => SetProperty(ref _previousForecastCommand, value);
+        }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Callback method invoked on Forecast property change.
+        /// </summary>
+        /// <param name="bindable">Object that contains property.</param>
+        /// <param name="oldValue">Old value of the property.</param>
+        /// <param name="newValue">New value of the property.</param>
+        private static void ForecastPropertyChanged(BindableObject bindable, object oldValue, object newValue)
+        {
+            if (newValue != null)
+            {
+                var viewModel = (ForecastViewModel)bindable;
+                viewModel.PrepareViewModels();
+            }
+        }
+
+        /// <summary>
+        /// Prepares view-models for every day of forecast.
+        /// Assigns prev/next forecast handlers
+        /// </summary>
+        private void PrepareViewModels()
+        {
+            ForecastsModels = new ObservableCollection<CurrentWeather>();
+            var dictionary = SortViewModelsByDate();
+            foreach (var list in dictionary.Values)
+            {
+                foreach (CurrentWeather forecast in list)
+                {
+                    ForecastsModels.Add(forecast);
+                }
+            }
+
+            // Previous forecast handler - either navigate down the forecast list or
+            // let the user know that the bottom (0) is reached via a simple vibration
+            PreviousForecastCommand = new Command(o =>
+            {
+                if (ForecastsModels != null)
+                {
+                    if (CurrentForecastId > 0)
+                    {
+                        CurrentForecastId--;
+                        OnPropertyChanged(nameof(SelectedForecast));
+                    }
+                    else
+                    {
+                        Vibrate();
+                    }
+                }
+            });
+
+            // Next forecast handler - either navigate up the forecast list or
+            // let the user know that the top (most distant forecast) is reached via a simple vibration
+            NextForecastCommand = new Command(o =>
+            {
+                if (ForecastsModels != null)
+                {
+                    if (CurrentForecastId < _forecastsModels.Count - 1)
+                    {
+                        CurrentForecastId++;
+                        OnPropertyChanged(nameof(SelectedForecast));
+                    }
+                    else
+                    {
+                        Vibrate();
+                    }
+                }
+            });
+            // Notify all parties interested that the Selected forecast (initially the first one) is
+            // ready and waiting to be presented in the relevant View.
+            OnPropertyChanged(nameof(SelectedForecast));
+        }
+
+        /// <summary>
+        /// Sort forecast data by date.
+        /// </summary>
+        /// <returns>List of sorted forecast data.</returns>
+        private Dictionary<int, List<CurrentWeather>> SortViewModelsByDate()
+        {
+            var dictionary = new Dictionary<int, List<CurrentWeather>>();
+
+            foreach (var weather in Forecast.WeatherList)
+            {
+                var day = TimeStamp.Convert(weather.TimeStamp).AddSeconds(Offset).DayOfYear;
+
+                if (!dictionary.ContainsKey(day))
+                {
+                    dictionary.Add(day, new List<CurrentWeather>());
+                }
+
+                dictionary[day].Add(weather);
+            }
+
+            if (dictionary.Count > 5)
+            {
+                dictionary.Remove(dictionary.Last().Key);
+            }
+
+            return dictionary;
+        }
+
+
+        /// <summary>
+        /// Use Tizen.System.Feedback to let user know something went a bit wrong (vibrate)      
+        /// </summary>
+        private void Vibrate()
+        {
+            try
+            {
+                Feedback feedback = new Feedback();
+                feedback.Play(FeedbackType.All, "General");
+            }
+            catch (System.Exception e)
+            {
+                Log.Debug("WeatherApp", e.Message);
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/ViewModels/MainPageViewModel.cs b/Test/Weather/Weather/ViewModels/MainPageViewModel.cs
new file mode 100755 (executable)
index 0000000..378f6d2
--- /dev/null
@@ -0,0 +1,256 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using Weather.Models.Location;
+using Weather.Service;
+using Weather.Utils;
+using Xamarin.Forms;
+using Xamarin.Forms.Internals;
+
+namespace Weather.ViewModels
+{
+    /// <summary>
+    /// ViewModel class for Main Page.
+    /// </summary>
+    public class MainPageViewModel : ViewModelBase
+    {
+        #region fields
+
+        /// <summary>
+        /// Bindable property that allows to set navigation context.
+        /// </summary>
+        public static readonly BindableProperty NavigationProperty =
+            BindableProperty.Create(nameof(Navigation), typeof(INavigation), typeof(MainPageViewModel), default(Type));
+
+
+        /// <summary>
+        /// Maximum number of items that will be displayed on the list.
+        /// </summary>
+        private const int MAX_ITEMS_ON_LIST = 10;
+
+        /// <summary>
+        /// Contains all supported cities.
+        /// </summary>
+        private CityProvider _provider;
+
+        /// <summary>
+        /// Local storage of collection of displayed cities.
+        /// </summary>
+        private ObservableCollection<City> _cities;
+
+        /// <summary>
+        /// Local storage of city name entered by user.
+        /// </summary>
+        private string _enteredCity = "";
+
+        /// <summary>
+        /// Local storage of city selected by user.
+        /// </summary>
+        private City _selectedCity;
+
+        /// <summary>
+        /// Local storage of command that opens page provided in command parameter.
+        /// </summary>
+        private Command _checkWeatherCommand;
+
+        /// <summary>
+        /// Local storage of country code.
+        /// </summary>
+        private string _enteredCountry;
+
+        /// <summary>
+        /// Local storage of CityEntry text color.
+        /// </summary>
+        private Color _cityEntryTextColor;
+
+        #endregion
+
+        #region properties
+
+        /// <summary>
+        /// Flag used for Watch UI visibility.
+        /// A "helper" UI element (list of cities matching criteria) should be hidden if the right city is entered       
+        /// </summary>
+        public bool InvalidCityEntered => (SelectedCity == null) && (EnteredCity.Length != 0) ? true : false;
+
+        /// <summary>
+        /// Gets or sets collection of available cities.
+        /// </summary>
+        public ObservableCollection<City> Cities
+        {
+            get => _cities;
+            set => SetProperty(ref _cities, value);
+        }
+
+        /// <summary>
+        /// Gets or sets text color for CityEntry.
+        /// </summary>
+        public Color CityEntryTextColor
+        {
+            get => _cityEntryTextColor;
+            set => SetProperty(ref _cityEntryTextColor, value);
+        }
+
+        /// <summary>
+        /// Gets or sets city name entered by user.
+        /// </summary>
+        public string EnteredCity
+        {
+            get => _enteredCity;
+            set
+            {
+                SetProperty(ref _enteredCity, value);
+                OnPropertyChanged(nameof(InvalidCityEntered));
+                FilterCities();
+                ValidateInput();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets city selected by user.
+        /// </summary>
+        public City SelectedCity
+        {
+            get => _selectedCity;
+            set
+            {
+                SetProperty(ref _selectedCity, value);
+                OnPropertyChanged(nameof(InvalidCityEntered));
+                if (value != null)
+                {
+                    ((App)Application.Current).IsInitialized = false;
+                    EnteredCity = value.Name;
+                    CityEntryTextColor = Color.Gray;
+                    CheckWeatherCommand.ChangeCanExecute();
+                }
+                else
+                {
+                    CityEntryTextColor = Color.Red;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets command that opens page provided in command parameter.
+        /// </summary>
+        public Command CheckWeatherCommand
+        {
+            get => _checkWeatherCommand;
+            set => SetProperty(ref _checkWeatherCommand, value);
+        }
+
+        /// <summary>
+        /// Country code in ISO-3166 format.
+        /// </summary>
+        public string EnteredCountry
+        {
+            get => _enteredCountry;
+            set
+            {
+                SetProperty(ref _enteredCountry, value);
+                FilterCities();
+            }
+        }
+
+        /// <summary>
+        /// Gets or sets navigation context.
+        /// </summary>
+        public INavigation Navigation
+        {
+            get => (INavigation)GetValue(NavigationProperty);
+            set => SetValue(NavigationProperty, value);
+        }
+
+        #endregion
+
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public MainPageViewModel()
+        {
+            LoadCityList();
+
+            Cities = new ObservableCollection<City>(_provider.FindCity("", MAX_ITEMS_ON_LIST));
+            CheckWeatherCommand = new Command<Page>(ExecuteCheckWeatherCommand, CanExecuteCheckWeatherCommand);
+            CityEntryTextColor = Color.FromRgb(128, 128, 128);
+
+            // Fill in the country code for better "first run experience"           
+            SetProperty<string>(ref _enteredCountry, "US");
+        }
+
+        /// <summary>
+        /// Loads list of cities from JSON file.
+        /// </summary>
+        private void LoadCityList()
+        {
+            var jsonFileReader = new JsonFileReader<IList<City>>("Weather.Data.", "city.list.json");
+            jsonFileReader.Read();
+            _provider = new CityProvider(jsonFileReader.Result.AsQueryable());
+        }
+
+        /// <summary>
+        /// Filters city list using text entered by user.
+        /// </summary>
+        private void FilterCities()
+        {
+            Cities.Clear();
+            _provider.FindCity(_enteredCity, _enteredCountry, MAX_ITEMS_ON_LIST).ForEach(c => Cities.Add(c));
+        }
+
+        /// <summary>
+        /// Validates city name entered by user.
+        /// </summary>
+        private void ValidateInput()
+        {
+            if (!_provider.Validate(EnteredCity))
+            {
+                SelectedCity = null;
+                CityEntryTextColor = Color.Red;
+                CheckWeatherCommand.ChangeCanExecute();
+            }
+        }
+
+        /// <summary>
+        /// Checks if CheckWeather command could be executed.
+        /// Page parameter and selected city can't be null.
+        /// </summary>
+        /// <param name="page">Page that will be shown.</param>
+        /// <returns>
+        /// Returns true if city is selected.
+        /// If no city is selected, or it is not valid method returns false.
+        /// </returns>
+        private bool CanExecuteCheckWeatherCommand(Page page)
+        {
+            return page != null && SelectedCity != null;
+        }
+
+        /// <summary>
+        /// Executes CheckWeather command.
+        /// Pushes page given as command parameter to navigation stack.
+        /// </summary>
+        /// <param name="page">Page that will be opened.</param>
+        private void ExecuteCheckWeatherCommand(Page page)
+        {
+            Navigation.PushAsync(page);
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/ViewModels/ViewModelBase.cs b/Test/Weather/Weather/ViewModels/ViewModelBase.cs
new file mode 100755 (executable)
index 0000000..a6ba1c7
--- /dev/null
@@ -0,0 +1,47 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.ComponentModel;
+using System.Runtime.CompilerServices;
+using Xamarin.Forms;
+
+namespace Weather.ViewModels
+{
+    /// <summary>
+    /// Base ViewModel class.
+    /// </summary>
+    public class ViewModelBase : BindableObject
+    {
+        /// <summary>
+        /// Generic set property method which also calls OnPropertyChanged() after value modification.
+        /// </summary>
+        /// <param name="storage">Value storage object</param>
+        /// <param name="value">Value to set</param>
+        /// <param name="propertyName">Automatically obtained property name</param>
+        /// <typeparam name="T">Property value type</typeparam>
+        /// <returns>True if value was changed, false if value is not different from current.</returns>
+        protected bool SetProperty<T>(ref T storage, T value,
+            [CallerMemberName] string propertyName = null)
+        {
+            if (Equals(storage, value))
+            {
+                return false;
+            }
+
+            storage = value;
+            OnPropertyChanged(propertyName);
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/ApiErrorPage.xaml b/Test/Weather/Weather/Views/ApiErrorPage.xaml
new file mode 100755 (executable)
index 0000000..09fe601
--- /dev/null
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<w:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:viewModels="clr-namespace:Weather.ViewModels;assembly=Weather"
+             xmlns:converters="clr-namespace:Weather.Converters;assembly=Weather"
+             x:Class="Weather.Views.ApiErrorPage"
+             NavigationPage.HasBackButton="False"        
+             NavigationPage.HasNavigationBar="False"
+             xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+             >
+
+    <ContentPage.BindingContext>
+        <viewModels:ApiErrorViewModel />
+    </ContentPage.BindingContext>
+
+    <ContentPage.Resources>
+        <ResourceDictionary>
+            <converters:TimeStampToDateConverter x:Key="TimeStampToDateConverter" />
+        </ResourceDictionary>
+    </ContentPage.Resources>
+    <w:CircleStackLayout Orientation="Vertical" Spacing="10">
+        <Label Text="Error"
+               FontSize="12"
+               TextColor="OrangeRed"
+               HorizontalTextAlignment="Center"
+               VerticalTextAlignment="Center"/>
+        <Label Text="Error occurred while trying to get response from API."
+               FontSize="8" 
+               HorizontalTextAlignment="Center"
+               VerticalTextAlignment="Center" />
+        <Label Text="{Binding Code, StringFormat='HTTP status code: {0}'}"   
+               FontSize="6" 
+               HorizontalTextAlignment="Center"
+               VerticalTextAlignment="Center" />
+        <Label Text="{Binding Message}"
+               FontSize="6" 
+               HorizontalTextAlignment="Center"
+               VerticalTextAlignment="Center" />
+    </w:CircleStackLayout>
+    <w:CirclePage.ActionButton>
+        <w:ActionButtonItem Command="{Binding ExitAppCommand}" Text="Exit" />
+    </w:CirclePage.ActionButton>
+</w:CirclePage>
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/ApiErrorPage.xaml.cs b/Test/Weather/Weather/Views/ApiErrorPage.xaml.cs
new file mode 100755 (executable)
index 0000000..9b9b217
--- /dev/null
@@ -0,0 +1,36 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Xamarin.Forms;
+
+namespace Weather.Views
+{
+    /// <summary>
+    /// Interaction logic for ApiErrorPage.xaml.
+    /// </summary>
+    public partial class ApiErrorPage
+    {
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public ApiErrorPage()
+        {
+            InitializeComponent();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/CurrentWeatherPage.xaml b/Test/Weather/Weather/Views/CurrentWeatherPage.xaml
new file mode 100755 (executable)
index 0000000..7638034
--- /dev/null
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<w:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:viewModels="clr-namespace:Weather.ViewModels;assembly=Weather"
+             xmlns:behaviors="clr-namespace:Weather.Behaviors;assembly=Weather"
+             xmlns:converters="clr-namespace:Weather.Converters;assembly=Weather"
+             xmlns:location="clr-namespace:Weather.Models.Location;assembly=Weather"
+             xmlns:controls="clr-namespace:Weather.Controls;assembly=Weather"
+             xmlns:views="clr-namespace:Weather.Views;assembly=Weather"
+             xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"            
+             x:Class="Weather.Views.CurrentWeatherPage"
+             x:Name="Root"
+             NavigationPage.HasNavigationBar="False"
+             Title="Current Weather"            
+             RotaryFocusObject="{x:Reference myscroller}">
+
+    <w:CirclePage.BindingContext>
+        <viewModels:CurrentWeatherViewModel x:Name="ViewModel"
+                                            CityData="{Binding Source={x:Reference Name=Root}, Path=CityData}"
+                                            Navigation="{Binding Source={x:Reference Name=Root}, Path=Navigation}" />
+    </w:CirclePage.BindingContext>
+
+    <w:CirclePage.Behaviors>
+        <behaviors:CurrentWeatherPageBehavior
+            AppearingCommand="{Binding Source={x:Reference Name=ViewModel}, Path=InitializeCommand}" />
+    </w:CirclePage.Behaviors>
+
+    <w:CirclePage.Resources>
+        <ResourceDictionary>
+            <converters:TimeStampToDateConverter x:Key="TimeStampToDateConverter" />
+            <converters:TimeStampToTimeConverter x:Key="TimeStampToTimeConverter" />
+            <converters:DegreeToCardinalDirectionConverter x:Key="CardinalDirectionConverter" />
+            <converters:ImageSourceConverter x:Key="ImageSourceConverter" />
+            <converters:MeasurementSystemConverter x:Key="MeasurementSystemConverter" />
+            <location:TimeZone x:Key="TimeZone"
+                               Offset="{Binding Source={x:Reference Name=ViewModel}, Path=CityTimeZone.Result.Offset}" />
+        </ResourceDictionary>
+    </w:CirclePage.Resources>
+
+    <StackLayout Orientation="Vertical">
+        <ActivityIndicator
+            IsVisible="{Binding InitializationInProgress}"
+            IsRunning="{Binding InitializationInProgress}"
+        />
+
+        <w:CircleScrollView x:Name="myscroller">
+            <StackLayout 
+                     Spacing="20"
+                     IsVisible="{Binding InitializationCompleted}">
+
+                <Label 
+                   Text="{Binding CurrentWeather.Result.CityName}"
+                   HeightRequest="120"
+                   MinimumHeightRequest="120"               
+                   FontSize="12"
+                   HorizontalTextAlignment="Center"
+                   VerticalTextAlignment="End"
+            />
+
+                <controls:DoubleLabel
+                    MainText="{Binding CurrentWeather.Result.TimeStamp, Converter={StaticResource TimeStampToDateConverter}}"
+                    SubText="Time of measurement." />
+                <StackLayout Orientation="Horizontal">
+                    <controls:DoubleLabel
+                    MainText="{Binding CurrentWeather.Result.SunData.SunriseTimeStamp,
+                            Converter={StaticResource TimeStampToTimeConverter}, ConverterParameter={StaticResource TimeZone}}"
+                    SubText="Sunrise" />
+                    <controls:DoubleLabel
+                    MainText="{Binding CurrentWeather.Result.SunData.SunsetTimeStamp,
+                            Converter={StaticResource TimeStampToTimeConverter}, ConverterParameter={StaticResource TimeZone}}"
+                    SubText="Sunset" />
+                </StackLayout>
+
+                <Image
+                    Source="{Binding CurrentWeather.Result.Weather[0].Icon, Converter={StaticResource ImageSourceConverter}}"
+                    HeightRequest="100"
+                    WidthRequest="100"
+                    Aspect="AspectFit" />
+                <Label
+                    Text="{Binding CurrentWeather.Result.Weather[0].Description}"                    
+                    HorizontalTextAlignment="Center"
+                    VerticalTextAlignment="Center"
+                    FontSize="8" />
+
+
+                
+                
+                <controls:DoubleLabel
+                        MainText="{Binding CurrentWeather.Result.WeatherData.Temperature, Converter={StaticResource MeasurementSystemConverter}, ConverterParameter='temp'}"
+                        SubText="Temperature" />
+
+
+                <StackLayout Orientation="Horizontal">
+                    <controls:DoubleLabel
+                        MainText="{Binding CurrentWeather.Result.Clouds.Percent, StringFormat=' {0}%'}"
+                        SubText="Clouds percent" />
+                    <controls:DoubleLabel
+                        MainText="{Binding CurrentWeather.Result.WeatherData.Pressure, StringFormat=' {0} hPa'}"
+                        SubText="Pressure" />
+                </StackLayout>
+
+                <StackLayout Orientation="Horizontal">
+                    <controls:DoubleLabel
+                        MainText="{Binding CurrentWeather.Result.Wind.Speed, Converter={StaticResource MeasurementSystemConverter}, ConverterParameter='speed'}"
+                        SubText="Wind speed" />
+                    <controls:DoubleLabel
+                        MainText="{Binding CurrentWeather.Result.Wind.Degree, Converter={StaticResource CardinalDirectionConverter}}"
+                        SubText="Wind direction" />
+                </StackLayout>
+
+                <Button Text="Check Forecast"
+                        BackgroundColor="DarkGray"
+                        TextColor="White"
+                        HeightRequest="90"
+                        MinimumHeightRequest="90"  
+                        Command="{Binding CheckForecastCommand}"
+                        IsVisible="{Binding InitializationCompleted}">
+                    <Button.CommandParameter>
+                        <views:ForecastPage>
+                            <views:ForecastPage.BindingContext>
+                                <viewModels:ForecastViewModel
+                            Forecast="{Binding Source={x:Reference Name=ViewModel}, Path=Forecast.Result}"
+                            Offset="{Binding Source={x:Reference Name=ViewModel}, Path=CityTimeZone.Result.Offset}"
+                            CityName="{Binding Source={x:Reference Name=ViewModel}, Path=CityData.Name}" />
+                            </views:ForecastPage.BindingContext>
+                        </views:ForecastPage>
+                    </Button.CommandParameter>
+                </Button>
+            </StackLayout>
+        </w:CircleScrollView>
+
+
+    </StackLayout>
+</w:CirclePage>
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/CurrentWeatherPage.xaml.cs b/Test/Weather/Weather/Views/CurrentWeatherPage.xaml.cs
new file mode 100755 (executable)
index 0000000..115e0cf
--- /dev/null
@@ -0,0 +1,52 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Weather.Models.Location;
+using Xamarin.Forms;
+
+namespace Weather.Views
+{
+    /// <summary>
+    /// Interaction logic for CurrentWeatherPage.xaml.
+    /// </summary>
+    public partial class CurrentWeatherPage
+    {
+        #region properties
+
+        /// <summary>
+        /// Bindable property that allows to set city data selected by user.
+        /// </summary>
+        public static readonly BindableProperty CityDataProperty =
+            BindableProperty.Create(nameof(CityData), typeof(City), typeof(CurrentWeatherPage), default(City));
+
+        /// <summary>
+        /// Gets or sets city data selected by user.
+        /// </summary>
+        public City CityData
+        {
+            get => (City)GetValue(CityDataProperty);
+            set => SetValue(CityDataProperty, value);
+        }
+
+        #endregion
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public CurrentWeatherPage()
+        {
+            InitializeComponent();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/ForecastPage.xaml b/Test/Weather/Weather/Views/ForecastPage.xaml
new file mode 100755 (executable)
index 0000000..0f75bd9
--- /dev/null
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<w:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:viewModels="clr-namespace:Weather.ViewModels;assembly=Weather"
+             xmlns:behaviors="clr-namespace:Weather.Behaviors;assembly=Weather"
+             xmlns:converters="clr-namespace:Weather.Converters;assembly=Weather"
+             xmlns:location="clr-namespace:Weather.Models.Location;assembly=Weather"
+             xmlns:controls="clr-namespace:Weather.Controls;assembly=Weather"
+             xmlns:views="clr-namespace:Weather.Views;assembly=Weather"
+             xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"            
+             x:Class="Weather.Views.ForecastPage"
+             x:Name="ForecastCirclePage"
+             NavigationPage.HasNavigationBar="False"
+             RotaryFocusObject="{x:Reference ForecastCirclePage}"
+             Title="Weather Forecast">
+
+    <w:CirclePage.Resources>
+        <ResourceDictionary>
+            <converters:TimeStampToDateConverter x:Key="TimeStampToDateConverter" />
+            <converters:TimeStampToTimeConverter x:Key="TimeStampToTimeConverter" />
+            <converters:DegreeToCardinalDirectionConverter x:Key="CardinalDirectionConverter" />
+            <converters:ImageSourceConverter x:Key="ImageSourceConverter" />
+            <converters:MeasurementSystemConverter x:Key="MeasurementSystemConverter" />
+        </ResourceDictionary>
+    </w:CirclePage.Resources>
+
+    <StackLayout Orientation="Vertical" HorizontalOptions="CenterAndExpand" >
+
+        <Label 
+            Text="{Binding SelectedForecast.CityName}"
+            HeightRequest="60"
+            MinimumHeightRequest="60"               
+            FontSize="10"
+            HorizontalTextAlignment="Center"
+            VerticalTextAlignment="End"/>
+        <Label
+            Text="{Binding SelectedForecast.TimeStamp, Converter={StaticResource TimeStampToDateConverter}}"
+            FontSize="8"
+            HorizontalTextAlignment="Center"/>
+        <StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
+            <StackLayout Orientation="Vertical">
+                <Image
+                    Source="{Binding SelectedForecast.Weather[0].Icon, Converter={StaticResource ImageSourceConverter}}"
+                    HeightRequest="100"
+                    WidthRequest="100"
+                    Aspect="AspectFit" />
+                <Label
+                    Text="{Binding SelectedForecast.Weather[0].Description}"                   
+                    HorizontalTextAlignment="Center"
+                    VerticalTextAlignment="Center"
+                    FontSize="5" />
+            </StackLayout>
+            <StackLayout Orientation="Vertical">
+                <controls:DoubleLabel
+                        MainText="{Binding SelectedForecast.WeatherData.Temperature, Converter={StaticResource MeasurementSystemConverter}, ConverterParameter='temp'}"
+                        SubText="Temperature" />
+                <controls:DoubleLabel
+                        MainText="{Binding SelectedForecast.Clouds.Percent, StringFormat=' {0}%'}"
+                        SubText="Clouds percent" />
+            </StackLayout>
+        </StackLayout>
+
+        <StackLayout Orientation="Horizontal">
+            <controls:DoubleLabel
+                        MainText="{Binding SelectedForecast.Wind.Speed, Converter={StaticResource MeasurementSystemConverter}, ConverterParameter='speed'}"
+                        SubText="Wind speed" />
+            <controls:DoubleLabel
+                        MainText="{Binding SelectedForecast.Wind.Degree, Converter={StaticResource CardinalDirectionConverter}}"
+                        SubText="Wind direction" />
+        </StackLayout>
+    </StackLayout>
+</w:CirclePage>
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/ForecastPage.xaml.cs b/Test/Weather/Weather/Views/ForecastPage.xaml.cs
new file mode 100755 (executable)
index 0000000..e2983d4
--- /dev/null
@@ -0,0 +1,85 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System.Linq;
+using Weather.Utils;
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Weather.Views
+{
+    /// <summary>
+    /// Interaction logic for ForecastPage.xaml.
+    /// </summary>
+    public partial class ForecastPage : CirclePage, IRotaryEventReceiver
+    {
+        #region fields
+        private bool _rotating = false;
+
+        #endregion fields
+
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public ForecastPage()
+        {
+            InitializeComponent();
+        }
+
+        /// <summary>
+        /// Handle bezel rotation
+        /// </summary>
+        /// <param name="args">Rotary event arguments</param>
+        public void Rotate(RotaryEventArgs args)
+        {
+            var a = this.BindingContext;
+
+            if (_rotating)
+            {
+                return;
+            }
+
+            _rotating = true;           
+            if (args.IsClockwise)
+            {
+                ((ViewModels.ForecastViewModel)BindingContext).NextForecastCommand.Execute(null);
+                _rotating = false;
+            }
+            else
+            {
+                ((ViewModels.ForecastViewModel)BindingContext).PreviousForecastCommand.Execute(null);
+                _rotating = false;
+            }
+        }
+
+        /// <summary>
+        /// Sets the binding context to page resources.
+        /// </summary>
+        protected override void OnBindingContextChanged()
+        {
+            base.OnBindingContextChanged();
+
+            if (Resources != null)
+            {
+                foreach (var bindableString in Resources.Values.OfType<BindableString>())
+                {
+                    bindableString.BindingContext = BindingContext;
+                }
+            }
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/MainPage.xaml b/Test/Weather/Weather/Views/MainPage.xaml
new file mode 100755 (executable)
index 0000000..4c6e9a5
--- /dev/null
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<w:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:viewModels="clr-namespace:Weather.ViewModels;assembly=Weather"
+             xmlns:behaviors="clr-namespace:Weather.Behaviors;assembly=Weather"
+             xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"            
+             xmlns:views="clr-namespace:Weather.Views;assembly=Weather"
+             x:Class="Weather.Views.MainPage"
+             x:Name="Root"
+             NavigationPage.HasNavigationBar="False"
+             RotaryFocusObject="{x:Reference myscroller}">
+
+
+    <w:CirclePage.BindingContext>
+        <viewModels:MainPageViewModel 
+            x:Name="ViewModel"              
+            Navigation="{Binding Source={x:Reference Name=Root}, Path=Navigation}" />
+    </w:CirclePage.BindingContext>
+
+
+    <w:CircleScrollView  x:Name="myscroller">
+        <StackLayout  
+            Orientation="Vertical"
+            HorizontalOptions="FillAndExpand"
+            VerticalOptions="FillAndExpand"
+            Spacing="5">
+
+            <Label Text="Weather App"
+                   FontSize="12"
+                   HorizontalTextAlignment="Center"
+                   VerticalTextAlignment="End" 
+                   HeightRequest="120"
+                   MinimumHeightRequest="120"/>
+
+            <Label Text="Country code:"
+                   FontSize="8"  
+                   HorizontalTextAlignment="Center"
+                   VerticalTextAlignment="Center" />
+
+            <w:PopupEntry BackgroundColor="White"
+                          HorizontalTextAlignment="Center"
+                          HorizontalOptions="Center"
+                          WidthRequest="280"
+                          Text="{Binding EnteredCountry, Mode=TwoWay}">
+                <w:PopupEntry.Behaviors>
+                    <behaviors:CountryCodeValidatorBehavior MaxLength="2" />
+                </w:PopupEntry.Behaviors>
+            </w:PopupEntry>
+
+            <Label Text="City:"
+                   FontSize="8"
+                   HorizontalOptions="Fill"
+                   VerticalOptions="Fill"
+                   HorizontalTextAlignment="Center"
+                   VerticalTextAlignment="Center" />
+
+            <w:PopupEntry x:Name="CityEntry"
+                   BackgroundColor="White"
+                   HorizontalOptions="Center"
+                   WidthRequest="280"
+                   Text="{Binding EnteredCity, Mode=TwoWay}"
+                   HorizontalTextAlignment="Center"
+                   TextColor="{Binding CityEntryTextColor}">
+            </w:PopupEntry>
+
+
+            <Label Text="Matching Cities:"
+                   FontSize="6"
+                   HorizontalOptions="Fill"
+                   VerticalOptions="Fill"
+                   HorizontalTextAlignment="Center"
+                   VerticalTextAlignment="Center" 
+                   IsVisible="{Binding Source={x:Reference Name=ViewModel}, Path=InvalidCityEntered}"/>
+
+            <w:CircleListView ItemsSource="{Binding Cities}"
+                      SelectedItem="{Binding SelectedCity, Mode=TwoWay}"   
+                      IsVisible="{Binding Source={x:Reference Name=ViewModel}, Path=InvalidCityEntered}"
+                      HeightRequest="150"
+                      MinimumHeightRequest="150"
+                      WidthRequest="260" 
+                      HorizontalOptions="Center"
+                      BackgroundColor="Black">
+                <w:CircleListView.ItemTemplate>
+                    <DataTemplate>
+                        <ViewCell>
+                            <Label Text="{Binding Name}"
+                                   FontSize="10"
+                                   HeightRequest="50"
+                                   HorizontalTextAlignment="Center"
+                                   VerticalTextAlignment="Center"
+                                   TextColor="LightGray"/>   
+                        </ViewCell>
+                    </DataTemplate>
+                </w:CircleListView.ItemTemplate>
+            </w:CircleListView>
+
+            <StackLayout VerticalOptions="Fill" MinimumHeightRequest="20" HeightRequest="20"> </StackLayout>
+            <Button                     
+                    Text="Check Weather"
+                    BackgroundColor="DarkGray"
+                    TextColor="White"
+                    Command="{Binding CheckWeatherCommand}"
+                    HeightRequest="90"
+                    MinimumHeightRequest="90">
+                <Button.CommandParameter>
+                    <views:CurrentWeatherPage
+                        CityData="{Binding Source={x:Reference Name=ViewModel}, Path=SelectedCity}" />
+                </Button.CommandParameter>
+            </Button>
+
+        </StackLayout>
+    </w:CircleScrollView>
+</w:CirclePage>
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/MainPage.xaml.cs b/Test/Weather/Weather/Views/MainPage.xaml.cs
new file mode 100755 (executable)
index 0000000..903b384
--- /dev/null
@@ -0,0 +1,34 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+namespace Weather.Views
+{
+    /// <summary>
+    /// Interaction logic for CurrentWeatherPage.xaml
+    /// </summary>
+    public partial class MainPage
+    {
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public MainPage()
+        {
+            InitializeComponent();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/MissingKeyErrorPage.xaml b/Test/Weather/Weather/Views/MissingKeyErrorPage.xaml
new file mode 100755 (executable)
index 0000000..907e199
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<w:CirclePage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+             xmlns:w="clr-namespace:Tizen.Wearable.CircularUI.Forms;assembly=XSF.CircularUI.Forms"
+             xmlns:viewModels="clr-namespace:Weather.ViewModels;assembly=Weather"
+             x:Class="Weather.Views.MissingKeyErrorPage"
+             NavigationPage.HasNavigationBar="False">
+
+    <w:CirclePage.BindingContext>
+        <viewModels:ApiErrorViewModel />
+    </w:CirclePage.BindingContext>
+
+    <w:CirclePage.ActionButton>
+        <w:ActionButtonItem Command="{Binding ExitAppCommand}" Text="Exit app" />
+    </w:CirclePage.ActionButton>
+    
+    <w:CirclePage.Content>
+        <StackLayout 
+            VerticalOptions="CenterAndExpand"
+            HorizontalOptions="CenterAndExpand"
+            Orientation="Vertical">
+            <Label
+                Text="Configuration error"
+                FontSize="Medium"              
+                HorizontalTextAlignment="Center"
+                VerticalTextAlignment="Center"
+                TextColor="OrangeRed"/>
+            <Label
+                Text="API key is not set. Please, define the key in &quot;ApiConfig.cs&quot; file and rebuild application."
+                FontSize="8"              
+                HorizontalTextAlignment="Center"
+                VerticalTextAlignment="Center" />
+        </StackLayout>
+    </w:CirclePage.Content>
+
+</w:CirclePage>
\ No newline at end of file
diff --git a/Test/Weather/Weather/Views/MissingKeyErrorPage.xaml.cs b/Test/Weather/Weather/Views/MissingKeyErrorPage.xaml.cs
new file mode 100755 (executable)
index 0000000..3fe7fe0
--- /dev/null
@@ -0,0 +1,36 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using Tizen.Wearable.CircularUI.Forms;
+
+namespace Weather.Views
+{
+    /// <summary>
+    /// Interaction logic for MissingKeyErrorPage.xaml
+    /// </summary>
+    public partial class MissingKeyErrorPage : CirclePage
+    {
+        #region methods
+
+        /// <summary>
+        /// Default class constructor.
+        /// </summary>
+        public MissingKeyErrorPage()
+        {
+            InitializeComponent();
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file
diff --git a/Test/Weather/Weather/Weather.cs b/Test/Weather/Weather/Weather.cs
new file mode 100755 (executable)
index 0000000..7fb490c
--- /dev/null
@@ -0,0 +1,69 @@
+//Copyright 2018 Samsung Electronics Co., Ltd
+//
+//Licensed under the Apache License, Version 2.0 (the "License");
+//you may not use this file except in compliance with the License.
+//You may obtain a copy of the License at
+//
+//    http://www.apache.org/licenses/LICENSE-2.0
+//
+//Unless required by applicable law or agreed to in writing, software
+//distributed under the License is distributed on an "AS IS" BASIS,
+//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//See the License for the specific language governing permissions and
+//limitations under the License.
+
+using System;
+using System.Collections.Generic;
+using Tizen.Wearable.CircularUI.Forms;
+using Tizen.Wearable.CircularUI.Forms.Renderer;
+using Xamarin.Forms;
+
+namespace Weather
+{
+    class Program : global::Xamarin.Forms.Platform.Tizen.ApplicationLifecycle
+    {
+        //protected override void OnCreate()
+        //{
+        //    base.OnCreate();
+
+        //    LoadApplication(new App());
+        //}
+
+        /// <summary>
+        /// Called when this application is launched.
+        /// </summary>
+        protected override void OnCreate()
+        {
+            var weather = new App();
+            FormsApplication.LoadApplication(weather);
+        }
+
+        static void Main(string[] args)
+        {
+            var app = new Program();
+            // define your custom handlers
+            var customRenderers = new Dictionary<Type, Func<IRegisterable>>()
+            {
+                { typeof(CirclePage), ()=> new CirclePageRenderer() },
+                { typeof(global:: Tizen.Wearable.CircularUI.Forms.CircleListView), () => new CircleListViewRenderer() },
+                { typeof(global:: Tizen.Wearable.CircularUI.Forms.CircleScrollView), ()=> new global::Tizen.Wearable.CircularUI.Forms.Renderer.CircleScrollViewRenderer() },
+            };
+            var option = new InitializationOptions(app)
+            {
+                UseMessagingCenter = false,
+                UseStyle = false,
+                UseShell = false,
+                UseVisual = false,
+                StaticRegistarStrategy = StaticRegistrarStrategy.StaticRegistrarOnly,
+                CustomHandlers = customRenderers,
+                Flags = InitializationFlags.DisableCss
+            };
+
+            Forms.Init(option);
+
+            // It's mandatory to initialize Circular UI for using Tizen Wearable Circular UI API
+            global::Tizen.Wearable.CircularUI.Forms.Renderer.FormsCircularUI.Init();
+            app.FormsApplication.Run(args);
+        }
+    }
+}
diff --git a/Test/Weather/Weather/Weather.csproj b/Test/Weather/Weather/Weather.csproj
new file mode 100755 (executable)
index 0000000..a0339f8
--- /dev/null
@@ -0,0 +1,47 @@
+<Project Sdk="Tizen.NET.Sdk/1.0.8">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>tizen40</TargetFramework>
+  </PropertyGroup>
+
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugType>portable</DebugType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>None</DebugType>
+  </PropertyGroup>
+  <ItemGroup>
+    <None Remove="Data\city.list.json" />
+    <None Remove="Data\country.list.json" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Data\city.list.json">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Data\country.list.json">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </EmbeddedResource>
+  </ItemGroup>
+
+  <ItemGroup>
+    <Folder Include="lib\" />
+    <Folder Include="Config\" />
+    <Folder Include="Views\" />
+    <Folder Include="res\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\Tizen.CircularUI\Tizen.Wearable.CircularUI.Forms.Renderer\XSF.CircularUI.Forms.Renderer.csproj" />
+    <!--<ProjectReference Include="..\..\..\Tizen.CircularUI\Tizen.Wearable.CircularUI.Forms\XSF.CircularUI.Forms.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Core\XSF.Core.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Platform.Tizen\XSF.Platform.Tizen.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Platform\XSF.Platform.csproj" />
+    <ProjectReference Include="..\..\..\Xamarin.Forms\Xamarin.Forms.Xaml\XSF.Xaml.csproj" />-->
+  </ItemGroup>
+
+</Project>
diff --git a/Test/Weather/Weather/shared/res/Weather.png b/Test/Weather/Weather/shared/res/Weather.png
new file mode 100755 (executable)
index 0000000..57fa097
Binary files /dev/null and b/Test/Weather/Weather/shared/res/Weather.png differ
diff --git a/Test/Weather/Weather/tizen-manifest.xml b/Test/Weather/Weather/tizen-manifest.xml
new file mode 100755 (executable)
index 0000000..4da1de5
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest package="org.tizen.example.Weather" version="1.0.0" api-version="4" xmlns="http://tizen.org/ns/packages">
+    <author href="https://github.com/Samsung/Tizen-CSharp-Samples">Michał Kołodziejski &amp; @Piotr12</author>
+    <description>
+        Mobile sample app made by Michał Kołodziejski.
+        Wearable port by @Piotr12.
+
+        Icon sourced from https://openclipart.org/detail/30073/tango-weather-few-clouds
+    </description>
+    <profile name="wearable" />
+    <ui-application appid="org.tizen.example.Weather" exec="Weather.dll" multiple="false" nodisplay="false" taskmanage="true" splash-screen-display="true" type="dotnet" launch_mode="single">
+        <label>Weather</label>
+        <icon>Weather.png</icon>
+        <metadata key="http://tizen.org/metadata/prefer_dotnet_aot" value="true" />
+        <splash-screens />
+    </ui-application>
+    <shortcut-list />
+    <privileges>
+        <privilege>http://tizen.org/privilege/haptic</privilege>
+        <privilege>http://tizen.org/privilege/internet</privilege>
+        <privilege>http://tizen.org/privilege/ime</privilege>
+        <privilege>http://tizen.org/privilege/imemanager</privilege>
+    </privileges>
+    <provides-appdefined-privileges />
+</manifest>
diff --git a/XSF.sln b/XSF.sln
index f693549..3541059 100755 (executable)
--- a/XSF.sln
+++ b/XSF.sln
@@ -41,6 +41,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "VoiceMemo", "VoiceMemo", "{
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VoiceMemo", "Test\Voicememo2020\VoiceMemo\VoiceMemo.csproj", "{6DADDF43-87F3-43C6-822D-12DE155CCF86}"
 EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Weather", "Weather", "{F167380D-C156-45D1-A0BA-DB3A5AE34E98}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Weather", "Test\Weather\Weather\Weather.csproj", "{076A3B6E-64FE-422C-9D54-845BA6036DF7}"
+EndProject
 Global
        GlobalSection(SolutionConfigurationPlatforms) = preSolution
                Debug|Any CPU = Debug|Any CPU