diff --git a/The Dark Sky Forecast API Docs.html b/The Dark Sky Forecast API Docs.html
new file mode 100644
index 0000000..09a4220
--- /dev/null
+++ b/The Dark Sky Forecast API Docs.html
@@ -0,0 +1,666 @@
+The Dark Sky Forecast API >
+
+
+ v2 Forecast API
+
+The Forecast API lets you query for most locations on the globe, and
+returns:
+
+ * Current conditions
+ * Minute-by-minute forecasts out to 1 hour (where available)
+ * Hour-by-hour forecasts out to 48 hours
+ * Day-by-day forecasts out to 7 days
+
+There are two main API calls. The first <#forecast_call> returns the
+current forecast (for the next week):
+
+|https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE|
+
+The second <#time_call> lets one query for a specific time, past or
+future (for many places, 60 years in the past to 10 years in the future):
+
+|https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME|
+
+*Note to Dark Sky API users*: The old docs can be found here .
+Details on migrating to the new API can be found at the bottom of the
+page <#migration>.
+
+
+ Changelog
+
+ * *3 Dec 2014:* Added Russian to the list of supported languages.
+ * *23 Sep 2014:* Added Portuguese and Bosnian to the list of supported
+ languages.
+ * *14 Aug 2014:* Added Polish and Pig Latin (!?) to the list of
+ supported languages.
+ * *29 Jul 2014:* Added Italian to the list of supported languages.
+ * *11 Jun 2014:* Added Spanish to the list of supported languages.
+ * *29 May 2014:* Added the |lang| option <#options>.
+ * *7 Jan 2014:* Added the |moonPhase| property to data points.
+ * *10 Dec 2013:* Added the MADIS <#data-sources> data source.
+ * *5 Dec 2013:* Added the |nearestStormDistance| and
+ |nearestStormBearing| properties to data points.
+ * *15 Aug 2013:* Added the |apparentTemperature| properties to data
+ points.
+ * *17 Jul 2013:* Added the |description| property to severe weather
+ alerts <#alerts>.
+ * *15 Jul 2013:* Added the RTMA and SREF weather models
+ <#data-sources>, and the |X-Forecast-API-Calls| response header
+ <#response-headers>.
+ * *22 May 2013:* Added the |extend| option.
+ * *6 May 2013:* Added string date format to time machine requests.
+ * *17 Apr 2013:* Added |dewPoint| and |ozone| properties to data points.
+ * *9 Apr 2013:* Added the |ca| and |auto| unit options, and added
+ |precipIntensityMax| and |precipIntensityMaxTime| properties on
+ daily data points.
+ * *1 Apr 2013:* Added the |exclude| option.
+ * *29 Mar 2013:* Deprecated the |si| option, replacing it with the
+ |units| option. When upgrading, be advised that |windSpeed| is now
+ in meters per second, rather than in kilometers per hour. (*Edit 9
+ Apr 2013:* one can now use |?units=ca| to precisely emulate the
+ functionality of |?si|. Please update any code using the deprecated
+ functionality at your earliest convenience.)
+ * *26 Mar 2013:* Initial version.
+
+
+ API Libraries
+
+Looking to include Forecast in your app? These wrapper libraries should
+make it quick and easy to do so:
+
+ * Official Ruby Wrapper Library
+ by David Czarnecki
+
+ * Android Client Wrapper Library
+ by Christopher Brown
+
+ * C++ Wrapper Library
+ by Todd Shore
+
+ * C# Wrapper Library by
+ Charl Cilliers
+ * Portable C# Wrapper Library
+ by Jerome Cheng
+
+ * CFML Wrapper Library by
+ Danny Cork
+ * Clojure Wrapper Library
+ by J. D. Hollis
+
+ * Erlang Wrapper Library by
+ Derek Brown
+ * Go Wrapper Library by
+ Martin-Louis Bright
+ * Java Wrapper Library
+ by David Ervideira
+ * Java Wrapper Library
+ by Kushan Jayatilleke
+ * JavaScript Wrapper Library
+ (with a
+ PHP-based proxy) by Ian Tearle
+ * Node.JS Wrapper Library
+ by Matt Walters
+
+ * Node.JS Wrapper Library by Chris
+ Jones
+ * Node.JS Wrapper Library
+ by Serhiy
+ Oplakanets
+ * Objective-C Wrapper Library
+ by Rob Phillips
+
+ * Objective-C Wrapper Library by
+ Carl Jahn
+ * iOS XCode Project Template
+ by Brandon Emrich
+
+ * Perl Wrapper Library
+
+ by Martin-Louis Bright
+ * PHP Wrapper Library
+ by Tobias
+ Redmann
+ * PHP Wrapper Library by
+ Guilherm Uhelski
+ * PHP Wrapper Library
+ (supporting multiple, simultaneous calls) by Charlie Gorichanaz
+
+ * Python Wrapper Library
+ by Ze'ev Gilovitz
+ * R Wrapper Library by Bob
+ Rudis
+ * Unofficial Ruby Wrapper Library
+ by Vicent Gozalbes
+
+ * Scala Wrapper Library
+ by Garrett Thornburg
+
+Additionally, Gerard Davison has
+provided a JSON Schema of
+the API, and Alex Handy has provided a CodeEnvy IDE
+ for a Java API wrapper
+of our API.
+
+Finally, please note that all of the above API wrappers (except for the
+official Ruby wrapper) are unofficial: we cannot provide support for
+them! If you have any questions about them, please contact the library's
+author.
+
+
+ The Forecast Call
+
+|https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE|
+
+|APIKEY| should be your Dark Sky API key. |LATITUDE| and |LONGITUDE|
+should be the geographic coordinates of a location in decimal degrees.
+/(Please note that the base domain for this API request is
+|api.forecast.io|, not |api.darkskyapp.com|.)/
+
+The response will be a JSON-formatted object with the following
+properties defined:
+
+ * |latitude|: The requested latitude.
+ * |longitude|: The requested longitude.
+ * |timezone|: The IANA timezone name for the requested location (e.g.
+ |America/New_York|). This is the timezone used for text forecast
+ summaries and for determining the exact start time of daily data
+ points. /(Developers are advised to rely on local system settings
+ rather than this value if at all possible: users may deliberately
+ set an unusual timezone, and furthermore are likely to know what
+ they actually want better than our timezone database does.)/
+ * |offset|: The current timezone offset in hours from GMT.
+ * |currently|: A /data point/ (see below) containing the current
+ weather conditions at the requested location.
+ * |minutely|: A /data block/ (see below) containing the weather
+ conditions minute-by-minute for the next hour. /(This property’s
+ name should be read as an adjective—analogously to “hourly” or
+ “daily” and meaning “reckoned by the minute”—rather than as an
+ adverb meaning “meticulously.” Yes, we know that this is not proper
+ English. No, we will not change it. Complaints to this effect will
+ be deleted with utmost prejudice.)/
+ * |hourly|: A /data block/ (see below) containing the weather
+ conditions hour-by-hour for the next two days.
+ * |daily|: A /data block/ (see below) containing the weather
+ conditions day-by-day for the next week.
+ * |alerts|: An array of /alert objects/ (see below), which, if
+ present, contains any severe weather alerts, issued by a
+ governmental weather authority, pertinent to the requested location.
+ * |flags|: An object containing miscellaneous metadata concerning this
+ request. (See /flags object/, below.)
+
+In general, to determine the weather at a given point in time, one
+should examine the highest-precision data block defined (|minutely|,
+|hourly|, and |daily| respectively), taking any data available from from
+it and falling back to the next-highest precision data block for any
+properties that are missing for the point in time desired.
+
+
+ Data Points
+
+A /data point/ object represents the various weather phenomena occurring
+at a specific instant of time, and has many varied properties. All of
+these properties (except |time|) are /optional/, and will only be set if
+we have that type of information for that location and time. Please note
+that |minutely| data points are always aligned to the nearest minute
+boundary, |hourly| points to the top of the hour, and |daily| points to
+midnight of that day.
+
+Data points in the |daily| /data block/ (see below) are special: instead
+of representing the weather phenomena at a given instant of time, they
+are an aggregate point representing the weather phenomena that will
+occur over the entire day. For precipitation fields, this aggregate is a
+maximum; for other fields, it is an average.
+
+Data point objects may contain the following properties:
+
+ * |time|: The UNIX time (that is, seconds since midnight GMT on 1 Jan
+ 1970) at which this data point occurs.
+ * |summary|: A human-readable text summary of this data point.
+ * |icon|: A machine-readable text summary of this data point, suitable
+ for selecting an icon for display. If defined, this property will
+ have one of the following values: |clear-day|, |clear-night|,
+ |rain|, |snow|, |sleet|, |wind|, |fog|, |cloudy|,
+ |partly-cloudy-day|, or |partly-cloudy-night|. (Developers should
+ ensure that a sensible default is defined, as additional values,
+ such as |hail|, |thunderstorm|, or |tornado|, may be defined in the
+ future.)
+ * |sunriseTime| and |sunsetTime| (only defined on |daily| data
+ points): The UNIX time (that is, seconds since midnight GMT on 1 Jan
+ 1970) of the last sunrise before and first sunset after the solar
+ noon closest to local noon on the given day. (Note: near the poles,
+ these may occur on a different day entirely!)
+ * |moonPhase| (only defined on |daily| data points): A number
+ representing the fractional part of the lunation number
+ of the given day.
+ This can be thought of as the “percentage complete” of the current
+ lunar month: a value of |0| represents a new moon, a value of |0.25|
+ represents a first quarter moon, a value of |0.5| represents a full
+ moon, and a value of |0.75| represents a last quarter moon. (The
+ ranges in between these represent waxing crescent, waxing gibbous,
+ waning gibbous, and waning crescent moons, respectively.)
+ * |nearestStormDistance| (only defined on |currently| data points): A
+ numerical value representing the distance to the nearest storm in
+ miles. (This value is /very approximate/ and should not be used in
+ scenarios requiring accurate results. In particular, a storm
+ distance of zero doesn’t necessarily refer to a storm at the
+ requested location, but rather a storm in the vicinity of that
+ location.)
+ * |nearestStormBearing| (only defined on |currently| data points): A
+ numerical value representing the direction of the nearest storm in
+ degrees, with true north at 0° and progressing clockwise. (If
+ |nearestStormDistance| is zero, then this value will not be defined.
+ The caveats that apply to |nearestStormDistance| also apply to this
+ value.)
+ * |precipIntensity|: A numerical value representing the average
+ expected intensity (in inches of liquid water per hour) of
+ precipitation occurring at the given time /conditional on
+ probability/ (that is, assuming any precipitation occurs at all). A
+ /very/ rough guide is that a value of |0| in./hr. corresponds to no
+ precipitation, |0.002| in./hr. corresponds to very light
+ precipitation, |0.017| in./hr. corresponds to light precipitation,
+ |0.1| in./hr. corresponds to moderate precipitation, and |0.4|
+ in./hr. corresponds to heavy precipitation.
+ * |precipIntensityMax|, and |precipIntensityMaxTime| (only defined on
+ |daily| data points): numerical values representing the maximumum
+ expected intensity of precipitation (and the UNIX time at which it
+ occurs) on the given day in inches of liquid water per hour.
+ * |precipProbability|: A numerical value between 0 and 1 (inclusive)
+ representing the probability of precipitation occuring at the given
+ time.
+ * |precipType|: A string representing the type of precipitation
+ occurring at the given time. If defined, this property will have one
+ of the following values: |rain|, |snow|, |sleet| (which applies to
+ each of freezing rain, ice pellets, and “wintery mix”), or |hail|.
+ (If |precipIntensity| is zero, then this property will not be defined.)
+ * |precipAccumulation| (only defined on |hourly| and |daily| data
+ points): the amount of snowfall accumulation expected to occur on
+ the given day. (If no accumulation is expected, this property will
+ not be defined.)
+ * |temperature| (not defined on |daily| data points): A numerical
+ value representing the temperature at the given time in degrees
+ Fahrenheit.
+ * |temperatureMin|, |temperatureMinTime|, |temperatureMax|, and
+ |temperatureMaxTime| (only defined on |daily| data points):
+ numerical values representing the minimum and maximumum temperatures
+ (and the UNIX times at which they occur) on the given day in degrees
+ Fahrenheit.
+ * |apparentTemperature| (not defined on |daily| data points): A
+ numerical value representing the apparent (or “feels like”)
+ temperature at the given time in degrees Fahrenheit.
+ * |apparentTemperatureMin|, |apparentTemperatureMinTime|,
+ |apparentTemperatureMax|, and |apparentTemperatureMaxTime| (only
+ defined on |daily| data points): numerical values representing the
+ minimum and maximumum apparent temperatures (and the UNIX times at
+ which they occur) on the given day in degrees Fahrenheit.
+ * |dewPoint|: A numerical value representing the dew point at the
+ given time in degrees Fahrenheit.
+ * |windSpeed|: A numerical value representing the wind speed in miles
+ per hour.
+ * |windBearing|: A numerical value representing the direction that the
+ wind is coming /from/ in degrees, with true north at 0° and
+ progressing clockwise. (If |windSpeed| is zero, then this value will
+ not be defined.)
+ * |cloudCover|: A numerical value between 0 and 1 (inclusive)
+ representing the percentage of sky occluded by clouds. A value of
+ |0| corresponds to clear sky, |0.4| to scattered clouds, |0.75| to
+ broken cloud cover, and |1| to completely overcast skies.
+ * |humidity|: A numerical value between 0 and 1 (inclusive)
+ representing the relative humidity.
+ * |pressure|: A numerical value representing the sea-level air
+ pressure in millibars.
+ * |visibility|: A numerical value representing the average visibility
+ in miles, capped at 10 miles.
+ * |ozone|: A numerical value representing the columnar density of
+ total atmospheric ozone at the given time in Dobson units.
+
+All of the above numeric, non-time fields may, optionally, have an
+associated |Error| value defined (with the property
+|precipIntensityError|, |windSpeedError|, |pressureError|, etc.),
+representing our system’s confidence in its prediction. Such properties
+represent standard deviations of the value of their associated property;
+small error values therefore represent a strong confidence, while large
+error values represent a weak confidence. These properties are omitted
+where the confidence is not precisely known (though generally considered
+to be adequate).
+
+
+ Data Blocks
+
+A /data block/ object represents the various weather phenomena occurring
+over a period of time. Such objects contain the following properties:
+
+ * |summary|: A human-readable text summary of this data block.
+ * |icon|: A machine-readable text summary of this data block (see
+ /data point/, above, for an enumeration of possible values that this
+ property may take on).
+ * |data|: An array of /data point/ objects (see above), ordered by
+ time, which together describe the weather conditions at the
+ requested location over time.
+
+Ideally, the |minutely| data block will contain data for the next hour,
+the |hourly| data block for the next two days, and the |daily| data
+block for the next week; however, if we are lacking data for a given
+time period, the data point sequence may contain gaps or terminate
+early. Furthermore, if no data points for a time period are known, then
+the data block will be omitted from the response in its entirety.
+Developers are strongly encouraged, therefore, to check for the presence
+of data before attempting to read it.
+
+
+ Alert Objects
+
+An /alert object/ represents a severe weather warning issued for the
+requested location by a governmental authority (for a list of which
+authorities we currently support, please see /data sources/, below).
+Such objects contain the following properties:
+
+ * |title|: A short text summary of the alert.
+ * |expires|: The UNIX time (that is, seconds since midnight GMT on 1
+ Jan 1970) at which the alert will cease to be valid.
+ * |description|: A detailed text description of the alert from the
+ appropriate weather service.
+ * |uri|: An HTTP(S) URI that contains detailed information about the
+ alert.
+
+
+ Flags Objects
+
+The /flags object/ contains various metadata information related to the
+request. Such objects may optionally contain any of the following
+properties:
+
+ * |darksky-unavailable|: The presence of this property indicates that
+ the Dark Sky data source supports the given location, but a
+ temporary error (such as a radar station being down for maintenace)
+ has made the data unavailable.
+ * |darksky-stations|: This property contains an array of IDs for each
+ radar station utilized in servicing this request.
+ * |datapoint-stations|: This property contains an array of IDs for
+ each DataPoint station utilized in servicing this request.
+ * |isd-stations|: This property contains an array of IDs for each ISD
+ station utilized in servicing this request.
+ * |lamp-stations|: This property contains an array of IDs for each
+ LAMP station utilized in servicing this request.
+ * |metar-stations|: This property contains an array of IDs for each
+ METAR station utilized in servicing this request.
+ * |metno-license|: The presence of this property indicates that data
+ from api.met.no was utilized in order to
+ facilitate this request (as per their license agreement).
+ * |sources|: This property contains an array of IDs for each data
+ source utilized in servicing this request. (For more information,
+ see /data sources/, below.)
+ * |units|: The presence of this property indicates which units were
+ used for the data in this request. (For more information, see
+ /options/, below.)
+
+
+ Forecast at a Given Time
+
+It is also possible to request a forecast for an arbitrary point in time:
+
+|https://api.forecast.io/forecast/APIKEY/LATITUDE,LONGITUDE,TIME|
+
+|TIME| should either be a UNIX time (that is, seconds since midnight GMT
+on 1 Jan 1970) or a string formatted as follows:
+|[YYYY]-[MM]-[DD]T[HH]:[MM]:[SS]| (with an optional time zone formatted
+as |Z| for GMT time or |{+,-}[HH][MM]| for an offset in hours or
+minutes). For the latter format, if no timezone is present, local time
+(at the provided latitude and longitude) is assumed. (This string format
+is a subset of ISO 8601
+
+time. An as example, |2013-05-06T12:00:00-0400|.)
+
+If a time is provided in this way, only the conditions for the day on
+which that time occurred (or will occur), midnight-to-midnight, are
+provided; in all other ways, making such a request is equivalent to
+getting in a time machine, going back or forward in time to the given
+moment, and making a normal forecast request. (In fact, this is how it
+is implemented behind-the-scenes.) Generally speaking, forecasted data
+is more accurate the nearer you query to the present moment. (That is,
+the present moment if you don’t have a time machine.)
+
+
+ Options
+
+The API request may optionally be modified through the use of query
+parameters. It will respond to the following:
+
+ * |callback=[callback]|: Return the API response as JSONP
+ . /Please use caution when
+ using this,/ since exposing your API key to the public is a security
+ hazard and, if abused, will result in the revokation of your API
+ key. However, if developing a personal- or internal-use app, this is
+ a convenient method of doing so.
+ * |units=[setting]|: Return the API response in units other than the
+ default Imperial units. In particular, the following settings are
+ possible:
+ o |us|: The default, as outlined above.
+ o |si|: Returns results in SI units. In particular, properties now
+ have the following units:
+ + |summary|: Any summaries containing temperature or snow
+ accumulation units will have their values in degrees Celsius
+ or in centimeters (respectively).
+ + |nearestStormDistance|: Kilometers.
+ + |precipIntensity|: Millimeters per hour.
+ + |precipIntensityMax|: Millimeters per hour.
+ + |precipAccumulation|: Centimeters.
+ + |temperature|: Degrees Celsius.
+ + |temperatureMin|: Degrees Celsius.
+ + |temperatureMax|: Degrees Celsius.
+ + |apparentTemperature|: Degrees Celsius.
+ + |dewPoint|: Degrees Celsius.
+ + |windSpeed|: Meters per second.
+ + |pressure|: Hectopascals (which are, conveniently,
+ equivalent to the default millibars).
+ + |visibility|: Kilometers.
+ o |ca|: Identical to |si|, except that |windSpeed| is in
+ kilometers per hour.
+ o |uk|: Identical to |si|, except that |windSpeed| is in miles per
+ hour, as in the US. (This option is provided because adoption of
+ SI in the UK has been inconsistent.)
+ o |auto|: Selects the relevant units automatically, based on
+ geographic location.
+ * |exclude=[blocks]|: Exclude some number of data blocks from the API
+ response. This is useful for reducing latency and saving cache
+ space. |[blocks]| should be a comma-delimeted list (without spaces)
+ of any of the following: |currently|, |minutely|, |hourly|, |daily|,
+ |alerts|, |flags|. (Crafting a request with /all/ of the above
+ blocks excluded is exceedingly silly and not recommended.)
+ * |extend=hourly|: When present on a forecast request, return hourly
+ data for the next seven days, rather than the next two. (This option
+ is ignored on time machine requests. When using this option, we
+ strongly recommend ensuring that your HTTP client supports compression.)
+ * |lang=[language]|: Return text summaries in the desired language.
+ (Please be advised that units in the summary will be set according
+ to the |units| option, above, so be sure to set both options as
+ needed.) |[language]| may be |bs| (Bosnian), |de| (German), |en|
+ (English, which is the default), |es| (Spanish), |fr| (French), |it|
+ (Italian), |nl| (Dutch), |pl| (Polish), |pt| (Portuguese), |ru|
+ (Russian), |tet| (Tetum), or |x-pig-latin| (Igpay Atinlay). (If a
+ different language is desired, please consider contributing to our
+ API translation module
+ on Github.)
+
+
+ Response Headers
+
+The API will set the following HTTP response headers to values useful to
+developers:
+
+ * |Cache-Control| and |Expires|: These headers are set to conservative
+ values for data caching purposes based on the data present in the
+ response body.
+ * |X-Forecast-API-Calls|: The number of API calls made by the given
+ API key for today.
+ * |X-Response-Time|: The server-side response time of the request.
+
+
+ Notes
+
+ * Just about every object property in the response is optional. In
+ fact, a request with no data to return will return a nearly empty
+ object, rather than a failure. Robust code will check for the
+ presence of required parameters before using them, and will fail
+ gracefully if they are not present (or return an error if a minimum
+ functional set of data is not available).
+ * All numeric properties are real numbers, except for UNIX timestamps,
+ which are (signed) integers.
+ * Summaries on the |hourly| data block actually only cover up to a
+ maximum of 24 hours, rather than the full time period in the data
+ block. We found that covering the full 48 hours could be, in a
+ number of circumstances, far too wordy to be practical.
+ * Summaries and icons on |daily| data points actually cover the period
+ from 4AM to 4AM, rather than the stated time period of midnight to
+ midnight. We found that the summaries so generated were less awkward.
+ * The Forecast Data API supports HTTP compression. We heartily
+ recommend using it, as it will make responses much smaller over the
+ wire. To enable it, simply add an |Accept-Encoding: gzip| header to
+ your request. (Most HTTP client libraries wrap this functionality
+ for you, please consult your library’s documentation for details. Be
+ advised that we do not support such compression over HTTP/1.0
+ connections.)
+ * JSON responses are in UTF-8 format (due to text summaries, which can
+ contain Unicode characters). Please ensure that your JSON parser
+ acts accordingly.
+
+
+ Data Sources
+
+This API is backed by a wide range of data sources, which are aggregated
+together statistically to provide the most accurate forecast possible
+for a given location. Any data sources used to service a given request
+will be noted in the |flags| section of a forecast response. These
+sources include:
+
+ 1. Dark Sky’s own hyperlocal precipitation forecasting system
+ (id
+ |darksky|), backed by radar data from the following systems:
+ * The USA NOAA’s NEXRAD system (USA).
+ * The UK Met Office’s NIMROD system (UK, Ireland).
+ * (More coming soon.)
+ 2. The USA NOAA’s LAMP system
+ (USA, id |lamp|).
+ 3. The UK Met Office’s Datapoint API
+ (UK, id |datapoint|).
+ 4. The Norwegian Meteorological Institute’s meteorological forecast API
+ (global, id |metno|).
+ 5. The USA NOAA’s Global Forecast System
+ (global, id
+ |gfs|).
+ 6. The USA NOAA’s Integrated Surface Database
+ (global, id |isd|).
+ 7. The USA NOAA’s Public Alert system
+ (USA, id |nwspa|).
+ 8. The UK Met Office’s Severe Weather Warning system
+ (UK, id
+ |metwarn|).
+ 9. Environment Canada’s Canadian Meteorological Center ensemble model
+
+ (global, id |cmc|).
+10. The US Navy’s Fleet Numerical Meteorology and Oceanography Ensemble
+ Forecast System
+
+ (global, id |fnmoc|).
+11. The USA NOAA and Environment Canada’s North American Ensemble
+ Forecast System
+
+ (global, id |naefs|).
+12. The USA NOAA’s North American Mesoscale Model
+ (North
+ America, id |nam|).
+13. The USA NOAA’s Rapid Refresh Model
+ (North America, id |rap|).
+14. The Norwegian Meteorological Institute’s GRIB file forecast for
+ Central Europe
+ (Europe,
+ id |metno_ce|).
+15. The Norwegian Meteorological Institute’s GRIB file forecast for
+ Northern Europe
+ (Europe,
+ id |metno_ne|).
+16. Worldwide METAR weather reports
+ (global, id |metar|).
+17. The USA NOAA/NCEP’s Short-Range Ensemble Forecast
+ (North America, id
+ |sref|).
+18. The USA NOAA/NCEP’s Real-Time Mesoscale Analysis
+ model (North America, id |rtma|).
+19. The USA NOAA/ESRL’s Meteorological Assimilation Data Ingest System
+ (global, id |madis|).
+
+
+ v1-to-v2 Migration Guide
+
+The v2 Forecast API is designed to be as close to a pure superset of the
+v1 Forecast API as
+possible, allowing for a straightforward upgrade path if you’re
+currently using the v1 API and wish to upgrade. Below is a mapping of
+all v1 response properties and how they map to v2 properties.
+
+v1 Property v2 Property Notes
+|timezone| |timezone| and |offset| In v1, |timezone| was a string
+containing the IANA timezone name, the timezone abbrevation, and the
+timezone offset in hours. In v2, |timezone| contains the IANA timezone
+name, while |offset| contains the timezone offset in hours. The timezone
+abbreviation has no analogue in v2.
+|currentSummary| |currently.summary|
+|currentIntensity| |currently.precipIntensity| In v1,
+|currentIntensity| was in dBZ. In v2, |precipIntensity| is in inches of
+liquid water per hour. An equation for converting between the two is
+available from the Wikipedia page for dBZ
+.
+|currentTemp| |currently.temperature|
+|hourSummary| |minutely.summary|
+|hourPrecipitation| |minutely.data| In v2, |minutely| may be omitted
+entirely given a lack of data.
+|hourPrecipitation[x].time| |minutely.data[x].time|
+|hourPrecipitation[x].probability| |minutely.data[x].precipProbability|
+|hourPrecipitation[x].intensity| |minutely.data[x].precipIntensity| In
+v1, |intensity| was in dBZ. In v2, |precipIntensity| is in inches of
+liquid water per hour. An equation for converting between the two is
+available from the Wikipedia page for dBZ
+.
+|hourPrecipitation[x].error| |minutely.data[x].precipIntensityError|
+Note the change in |precipIntensity| units outlined above. Additionally,
+in v2, this value is a one-sigma value rather than a three-sigma value,
+and if |precipIntensity| is zero, then this property will be omitted
+entirely.
+|hourPrecipitation[x].type| |minutely.data[x].precipType| In v2, there
+is an additional type of precipitation: |hail|. Additionally, in v2, if
+|precipIntensity| is zero, then this property will be omitted.
+|daySummary| |hourly.summary|
+|dayPrecipitation| |hourly.data| In v2, |hourly| may be omitted
+entirely given a lack of data.
+|dayPrecipitation[x].time| |hourly.data[x].time|
+|dayPrecipitation[x].probability| |hourly.data[x].precipProbability|
+In v2, |precipProbability| will be omitted if |precipIntensity| is zero.
+It is also very uncommonly provided by our data sources; developers are
+encouraged to use rely on |precipIntensity| whenever possible.
+|dayPrecipitation[x].type| |hourly.data[x].precipType| In v2, there is
+an additional type of precipitation: |hail|. Additionally, in v2, if
+|precipIntensity| is zero, then this property will be omitted.
+|dayPrecipitation[x].temp| |hourly.data[x].temperature|
+|dayPrecipitation[x].cloudCover| |hourly.data[x].cloudCover|
+|dayPrecipitation[x].relHumidity| |hourly.data[x].humidity|
+|radarStation| |flags["darksky-stations"]| In v2, this property will
+be omitted if we do not have radar coverage of the given location.
+Additionally, v2 makes use of multiple radar sources, so this property
+contains an array of station IDs, rather than a single ID. Finally, in
+v1, radar stations were lower case and would have their first letter
+omitted if they began with a "K". In v2, radar station IDs are always
+four letters long and upper case.
+|isPrecipitating| /not present/ In v2, simply check if
+|currently.precipIntensity| is nonzero.
+|minutesUntilChange| /not present/ In v2, iterate over |minutely.data|
+and |hourly.data| in order, finding the first data point for which
+|currently.precipIntensity !== 0| does not equal
+|datapoint.precipIntensity !== 0|. Once that data point is found,
+|minutesUntilChange| may be calculated as follows: |(datapoint.time -
+currently.time) / 60|.
+|checkTimeout| /not present/ Use either the |Cache-Control| or
+|Expires| HTTP response headers.
+
+© 2013 The Dark Sky Company, LLC
+Email Us Terms of Use
+Privacy Policy
+
diff --git a/config/compile b/config/compile
new file mode 100755
index 0000000..531136b
--- /dev/null
+++ b/config/compile
@@ -0,0 +1,347 @@
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey .
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to or send patches to
+# .
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to .
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/data/#weather-settings_2.ui# b/data/#weather-settings_2.ui#
new file mode 100644
index 0000000..0c6f164
--- /dev/null
+++ b/data/#weather-settings_2.ui#
@@ -0,0 +1,1185 @@
+
+
+
+
+
+
+
diff --git a/data/metadata.json.in b/data/metadata.json.in
index b038896..4159225 100644
--- a/data/metadata.json.in
+++ b/data/metadata.json.in
@@ -2,7 +2,7 @@
"uuid": "@uuid@",
"name": "OpenWeather",
"description": "Weather extension to display weather information from https://openweathermap.org/ or https://forecast.io for almost all locations in the world.\nTo use the weather-data of forecast.io, you have to register on their site (https://developer.forecast.io/register) and get a personal API-key.\n\nSince version 29 this extensions uses coordinates to store the locations and makes the names editable to support multiple weather-providers!\nIf you update from versions prior to 29 to 29 or greater (with forecast.io - support) you have to recreate your locations.",
-"shell-version": [ "3.12", "3.14", "3.16", "3.17.4", "3.17.90", "3.17.91" ],
+"shell-version": [ "3.12", "3.14", "3.16", "3.17.4", "3.17.90", "3.17.91", "3.17.92" ],
"localedir": "@LOCALEDIR@",
"url": "@url@",
"version": "@version@"
diff --git a/data/weather-settings_2.ui b/data/weather-settings_2.ui
new file mode 100644
index 0000000..7d157c8
--- /dev/null
+++ b/data/weather-settings_2.ui
@@ -0,0 +1,1100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ 14
+
+
+ True
+ False
+ True
+
+
+ True
+ True
+ center
+ True
+ True
+ in
+
+
+ True
+ True
+ liststore
+ False
+ 0
+ False
+ 12
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+ 1
+
+
+
+
+ True
+ False
+
+
+ False
+ True
+ False
+ list-add-symbolic
+
+
+ False
+ True
+
+
+
+
+ False
+ True
+ False
+ list-remove-symbolic
+
+
+ False
+ True
+
+
+
+
+
+ 0
+ 1
+ 1
+ 1
+
+
+
+
+ False
+ True
+ 0
+
+
+
+
+ True
+ False
+
+
+ True
+ False
+ 36
+ 14
+ 2
+ 36
+ 12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ 0
+
+
+
+
+ False
+ True
+ 1
+
+
+
+
diff --git a/gnome-shell-extension-openweather.bmarks b/gnome-shell-extension-openweather.bmarks
new file mode 100644
index 0000000..2608b85
--- /dev/null
+++ b/gnome-shell-extension-openweather.bmarks
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/gnome-shell-extension-openweather.cscope_file_list b/gnome-shell-extension-openweather.cscope_file_list
new file mode 100644
index 0000000..c90f732
--- /dev/null
+++ b/gnome-shell-extension-openweather.cscope_file_list
@@ -0,0 +1,53 @@
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/cs.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/zh_CN.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/ca.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/src/prefs.js"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/ChangeLog"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/sk.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/el.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/zh_TW.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/vi.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/aclocal.m4"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/COPYING"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/uk.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/Screenshot.jpg"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/configure.ac"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/AUTHORS"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/lt.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/it.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/src/convenience.js"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/openweather-search.ui"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/nl.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/org.gnome.shell.extensions.openweather.gschema.xml.in"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/fr.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/de.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/pl.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/NEWS"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/Makefile.am"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/Makefile.am"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/update.js"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/src/Makefile.am"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/da.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/pt.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/POTFILES.in"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/gnome-shell-extension-openweather.spec"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/sv.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/weather-settings.gif"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/LINGUAS"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/nb.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/gnome-shell-extension-weather.pot"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/bg.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/ru.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/README.md"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/ja.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/autogen.sh"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/fi.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/pt_BR.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/weather-settings.ui"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/metadata.json.in"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/he.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/data/stylesheet.css"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/hu.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/es.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/po/ro.po"
+"/home/jens/sources/w/weather/gnome-shell-extension-openweather/src/extension.js"
diff --git a/gnome-shell-extension-openweather.layout b/gnome-shell-extension-openweather.layout
new file mode 100644
index 0000000..45c39dc
--- /dev/null
+++ b/gnome-shell-extension-openweather.layout
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/search.txt b/search.txt
new file mode 100644
index 0000000..560014c
--- /dev/null
+++ b/search.txt
@@ -0,0 +1,104 @@
+https://open.mapquestapi.com/nominatim/v1/search.php?format=json&q=Sommerweg+2,+Neu-Eichenberg&addressdetails=1
+
+[
+ {
+ "place_id":"57218283",
+ "licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
+ "osm_type":"way",
+ "osm_id":"26124984",
+ "boundingbox":
+ [
+ "51.3747137",
+ "51.3755891",
+ "9.9164565",
+ "9.9192863"
+ ],
+ "lat":"51.3750768",
+ "lon":"9.9175961",
+ "display_name":"Sommerweg, Neu-Eichenberg, Werra-Mei\u00dfner-Kreis, Regierungsbezirk Kassel, Hessen, 37249, Deutschland, Europa",
+ "class":"highway",
+ "type":"residential",
+ "importance":0.51,
+ "address":
+ {
+ "road":"Sommerweg",
+ "village":"Neu-Eichenberg",
+ "county":"Werra-Mei\u00dfner-Kreis",
+ "state_district":"Regierungsbezirk Kassel",
+ "state":"Hessen",
+ "postcode":"37249",
+ "country":"Deutschland",
+ "country_code":"de",
+ "continent":"Europa"
+ }
+ }
+]
+
+
+[
+ {
+ "place_id":"151244439",
+ "licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
+ "osm_type":"relation",
+ "osm_id":"549411",
+ "boundingbox":
+ [
+ "51.3462395",
+ "51.4210337",
+ "9.8500839",
+ "9.9327238"
+ ],
+ "lat":"51.3835891",
+ "lon":"9.8833684",
+ "display_name":"Neu-Eichenberg, Werra-Mei\u00dfner-Kreis, Regierungsbezirk Kassel, Hessen, Deutschland, Europa",
+ "class":"boundary",
+ "type":"administrative",
+ "importance":0.57579531509901,
+ "icon":"http:\/\/open.mapquestapi.com\/nominatim\/v1\/images\/mapicons\/poi_boundary_administrative.p.20.png",
+ "address":
+ {
+ "city":"Neu-Eichenberg",
+ "county":"Werra-Mei\u00dfner-Kreis",
+ "state_district":"Regierungsbezirk Kassel",
+ "state":"Hessen",
+ "country":"Deutschland",
+ "country_code":"de",
+ "continent":"Europa"
+ }
+ }
+]
+
+http://open.mapquestapi.com/nominatim/v1/reverse.php?format=json&lat=51.3750768&lon=+9.9175961
+
+[
+ {
+ "place_id":"151244439",
+ "licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
+ "osm_type":"relation",
+ "osm_id":"549411",
+ "boundingbox":
+ [
+ "51.3462395",
+ "51.4210337",
+ "9.8500839",
+ "9.9327238"
+ ],
+ "lat":"51.3835891",
+ "lon":"9.8833684",
+ "display_name":"Neu-Eichenberg, Werra-Mei\u00dfner-Kreis, Regierungsbezirk Kassel, Hessen, Deutschland, Europa",
+ "class":"boundary",
+ "type":"administrative",
+ "importance":0.57579531509901,
+ "icon":"http:\/\/open.mapquestapi.com\/nominatim\/v1\/images\/mapicons\/poi_boundary_administrative.p.20.png",
+ "address":
+ {
+ "city":"Neu-Eichenberg",
+ "county":"Werra-Mei\u00dfner-Kreis",
+ "state_district":"Regierungsbezirk Kassel",
+ "state":"Hessen",
+ "country":"Deutschland",
+ "country_code":"de",
+ "continent":"Europa"
+ }
+ }
+]
diff --git a/src/extension_test.js b/src/extension_test.js
new file mode 100644
index 0000000..f822f00
--- /dev/null
+++ b/src/extension_test.js
@@ -0,0 +1,1426 @@
+/* jshint esnext:true */
+/*
+ *
+ * Weather extension for GNOME Shell
+ * - Displays a small weather information on the top panel.
+ * - On click, gives a popup with details about the weather.
+ *
+ * Copyright (C) 2011 - 2015
+ * ecyrbe ,
+ * Timur Kristof ,
+ * Elad Alfassa ,
+ * Simon Legner ,
+ * Christian METZLER ,
+ * Mark Benjamin weather.gnome.Markie1@dfgh.net,
+ * Mattia Meneguzzo odysseus@fedoraproject.org,
+ * Meng Zhuo ,
+ * Jens Lody
+ *
+ *
+ * This file is part of gnome-shell-extension-openweather.
+ *
+ * gnome-shell-extension-openweather is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-shell-extension-openweather is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gnome-shell-extension-openweather. If not, see .
+ *
+ */
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+const Config = imports.misc.config;
+const Convenience = Me.imports.convenience;
+const ForecastIo = Me.imports.forecast_io;
+const OpenweathermapOrg = Me.imports.openweathermap_org;
+const Clutter = imports.gi.Clutter;
+const Gettext = imports.gettext.domain('gnome-shell-extension-openweather');
+const Gio = imports.gi.Gio;
+const Gtk = imports.gi.Gtk;
+const GLib = imports.gi.GLib;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Soup = imports.gi.Soup;
+const St = imports.gi.St;
+const Util = imports.misc.util;
+const _ = Gettext.gettext;
+
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+// Settings
+const OPENWEATHER_SETTINGS_SCHEMA = 'org.gnome.shell.extensions.openweather';
+const OPENWEATHER_DESKTOP_INTERFACE = 'org.gnome.desktop.interface';
+const OPENWEATHER_PROVIDER_KEY = 'weather-provider';
+const OPENWEATHER_UNIT_KEY = 'unit';
+const OPENWEATHER_WIND_SPEED_UNIT_KEY = 'wind-speed-unit';
+const OPENWEATHER_WIND_DIRECTION_KEY = 'wind-direction';
+const OPENWEATHER_PRESSURE_UNIT_KEY = 'pressure-unit';
+const OPENWEATHER_CITY_KEY = 'city';
+const OPENWEATHER_ACTUAL_CITY_KEY = 'actual-city';
+const OPENWEATHER_TRANSLATE_CONDITION_KEY = 'translate-condition';
+const OPENWEATHER_USE_SYMBOLIC_ICONS_KEY = 'use-symbolic-icons';
+const OPENWEATHER_USE_TEXT_ON_BUTTONS_KEY = 'use-text-on-buttons';
+const OPENWEATHER_SHOW_TEXT_IN_PANEL_KEY = 'show-text-in-panel';
+const OPENWEATHER_POSITION_IN_PANEL_KEY = 'position-in-panel';
+const OPENWEATHER_SHOW_COMMENT_IN_PANEL_KEY = 'show-comment-in-panel';
+const OPENWEATHER_SHOW_COMMENT_IN_FORECAST_KEY = 'show-comment-in-forecast';
+const OPENWEATHER_REFRESH_INTERVAL_CURRENT = 'refresh-interval-current';
+const OPENWEATHER_REFRESH_INTERVAL_FORECAST = 'refresh-interval-forecast';
+const OPENWEATHER_CENTER_FORECAST_KEY = 'center-forecast';
+const OPENWEATHER_DAYS_FORECAST = 'days-forecast';
+const OPENWEATHER_DECIMAL_PLACES = 'decimal-places';
+const OPENWEATHER_OWM_API_KEY = 'appid';
+const OPENWEATHER_FC_API_KEY = 'appid-fc';
+
+// Keep enums in sync with GSettings schemas
+const WeatherProvider = {
+ DEFAULT: -1,
+ OPENWEATHERMAP: 0,
+ FORECAST_IO: 1
+};
+
+const WeatherUnits = {
+ CELSIUS: 0,
+ FAHRENHEIT: 1,
+ KELVIN: 2,
+ RANKINE: 3,
+ REAUMUR: 4,
+ ROEMER: 5,
+ DELISLE: 6,
+ NEWTON: 7
+};
+
+const WeatherWindSpeedUnits = {
+ KPH: 0,
+ MPH: 1,
+ MPS: 2,
+ KNOTS: 3,
+ FPS: 4,
+ BEAUFORT: 5
+};
+
+const WeatherPressureUnits = {
+ HPA: 0,
+ INHG: 1,
+ BAR: 2,
+ PA: 3,
+ KPA: 4,
+ ATM: 5,
+ AT: 6,
+ TORR: 7,
+ PSI: 8,
+ MMHG: 9
+};
+
+const WeatherPosition = {
+ CENTER: 0,
+ RIGHT: 1,
+ LEFT: 2
+};
+
+const OPENWEATHER_CONV_MPS_IN_MPH = 2.23693629;
+const OPENWEATHER_CONV_MPS_IN_KPH = 3.6;
+const OPENWEATHER_CONV_MPS_IN_KNOTS = 1.94384449;
+const OPENWEATHER_CONV_MPS_IN_FPS = 3.2808399;
+
+let _httpSession;
+
+const OpenweatherMenuButton = new Lang.Class({
+ Name: 'OpenweatherMenuButton',
+
+ Extends: PanelMenu.Button,
+
+ _init: function() {
+ log(new Error().fileName+':'+new Error().lineNumber+'11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111');
+ log(new Error().fileName+':'+new Error().lineNumber+' => Gio.NetworkConnectivity = '+Gio.NetworkConnectivity.toString());
+ log(new Error().fileName+':'+new Error().lineNumber+' => Gio.NetworkConnectivity.full = '+Gio.NetworkConnectivity.full);
+ for (let i = 0; i < Gio.NetworkConnectivity.length; ++i)
+ {
+ log(new Error().fileName+':'+new Error().lineNumber+' => Gio.network_monitor_get_default()['+i+'] = '+Gio.network_monitor_get_default()[i]);
+ }
+// log(new Error().fileName+':'+new Error().lineNumber+' => Gio.network_monitor_get_default().NETWORK_CONNECTIVITY_FULL = '+Gio.network_monitor_get_default().NetworkConnectivity.G_NETWORK_CONNECTIVITY_FULL);
+ log(new Error().fileName+':'+new Error().lineNumber+'22222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222');
+ this.owmCityId = 0;
+
+ this.oldProvider = this._weather_provider;
+ this.oldTranslateCondition = this._translate_condition;
+ this.switchProvider();
+
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ // Load settings
+ this.loadConfig();
+
+ // Label
+ this._weatherInfo = new St.Label({
+ y_align: Clutter.ActorAlign.CENTER,
+ text: _('...')
+ });
+
+ this._weatherIcon = new St.Icon({
+ icon_name: 'view-refresh' + this.getIconType(),
+ style_class: 'system-status-icon openweather-icon'
+ });
+
+ // Panel menu item - the current class
+ let menuAlignment = 0.25;
+ if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
+ menuAlignment = 1.0 - menuAlignment;
+ this.parent(menuAlignment);
+
+ // Putting the panel item together
+ let topBox = new St.BoxLayout();
+ topBox.add_actor(this._weatherIcon);
+ topBox.add_actor(this._weatherInfo);
+ this.actor.add_actor(topBox);
+
+ let dummyBox = new St.BoxLayout();
+ this.actor.reparent(dummyBox);
+ dummyBox.remove_actor(this.actor);
+ dummyBox.destroy();
+
+ let children = null;
+ switch (this._position_in_panel) {
+ case WeatherPosition.LEFT:
+ children = Main.panel._leftBox.get_children();
+ Main.panel._leftBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.CENTER:
+ children = Main.panel._centerBox.get_children();
+ Main.panel._centerBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.RIGHT:
+ children = Main.panel._rightBox.get_children();
+ Main.panel._rightBox.insert_child_at_index(this.actor, 0);
+ break;
+ }
+ if (Main.panel._menus === undefined)
+ Main.panel.menuManager.addMenu(this.menu);
+ else
+ Main.panel._menus.addMenu(this.menu);
+
+ this._old_position_in_panel = this._position_in_panel;
+
+ // Current weather
+ this._currentWeather = new St.Bin();
+ // Future weather
+ this._futureWeather = new St.Bin();
+
+ // Putting the popup item together
+ let _itemCurrent = new PopupMenu.PopupBaseMenuItem({
+ reactive: false
+ });
+ let _itemFuture = new PopupMenu.PopupBaseMenuItem({
+ reactive: false
+ });
+
+ _itemCurrent.actor.add_actor(this._currentWeather);
+ _itemFuture.actor.add_actor(this._futureWeather);
+
+ this.menu.addMenuItem(_itemCurrent);
+
+ this._separatorItem = new PopupMenu.PopupSeparatorMenuItem();
+ this.menu.addMenuItem(this._separatorItem);
+
+ this.menu.addMenuItem(_itemFuture);
+
+ let item = new PopupMenu.PopupSeparatorMenuItem();
+ this.menu.addMenuItem(item);
+
+ this._selectCity = new PopupMenu.PopupSubMenuMenuItem("");
+ this._selectCity.actor.set_height(0);
+ this._selectCity._triangle.set_height(0);
+
+ this._buttonMenu = new PopupMenu.PopupBaseMenuItem({
+ reactive: false,
+ style_class: 'openweather-menu-button-container'
+ });
+
+ this.rebuildButtonMenu();
+
+ this.menu.addMenuItem(this._buttonMenu);
+ this.menu.addMenuItem(this._selectCity);
+ this.rebuildSelectCityItem();
+ this._selectCity.menu.connect('open-state-changed', Lang.bind(this, function() {
+ this._selectCity.actor.remove_style_pseudo_class('open');
+ }));
+
+ this.rebuildCurrentWeatherUi();
+ this.rebuildFutureWeatherUi();
+
+ this._network_monitor = Gio.network_monitor_get_default();
+
+ this._connected = false;
+ this._network_monitor_connection = this._network_monitor.connect('network-changed', Lang.bind(this, this._onNetworkStateChanged));
+ this._checkConnectionState();
+
+ this.menu.connect('open-state-changed', Lang.bind(this, this.recalcLayout));
+ },
+
+ stop: function() {
+ if (_httpSession !== undefined)
+ _httpSession.abort();
+
+ _httpSession = undefined;
+
+ if (this._timeoutCurrent)
+ Mainloop.source_remove(this._timeoutCurrent);
+
+ this._timeoutCurrent = undefined;
+
+ if (this._timeoutForecast)
+ Mainloop.source_remove(this._timeoutForecast);
+
+ this._timeoutForecast = undefined;
+
+ if (this._network_monitor_connection) {
+ this._network_monitor.disconnect(this._network_monitor_connection);
+ this._network_monitor_connection = undefined;
+ }
+
+ if (this._settingsC) {
+ this._settings.disconnect(this._settingsC);
+ this._settingsC = undefined;
+ }
+
+ if (this._settingsInterfaceC) {
+ this._settingsInterface.disconnect(this._settingsInterfaceC);
+ this._settingsInterfaceC = undefined;
+ }
+
+ if (this._globalThemeChangedId) {
+ let context = St.ThemeContext.get_for_stage(global.stage);
+ context.disconnect(this._globalThemeChangedId);
+ this._globalThemeChangedId = undefined;
+ }
+ },
+
+ switchProvider: function() {
+ if (this._weather_provider == WeatherProvider.FORECAST_IO)
+ this.useForecastIo();
+ else
+ this.useOpenweathermapOrg();
+ },
+
+ useOpenweathermapOrg: function() {
+ this.parseWeatherForecast = OpenweathermapOrg.parseWeatherForecast;
+ this.parseWeatherCurrent = OpenweathermapOrg.parseWeatherCurrent;
+ this.getWeatherIcon = OpenweathermapOrg.getWeatherIcon;
+ this.refreshWeatherCurrent = OpenweathermapOrg.refreshWeatherCurrent;
+ this.refreshWeatherForecast = OpenweathermapOrg.refreshWeatherForecast;
+
+ this.weatherProvider = "https://openweathermap.org/";
+ },
+
+ useForecastIo: function() {
+ this.parseWeatherCurrent = ForecastIo.parseWeatherCurrent;
+ this.parseWeatherForecast = ForecastIo.parseWeatherForecast;
+ this.getWeatherIcon = ForecastIo.getWeatherIcon;
+ this.refreshWeatherCurrent = ForecastIo.refreshWeatherCurrent;
+ this.refreshWeatherForecast = function() {};
+
+ this.weatherProvider = "https://forecast.io/";
+
+ this.fc_locale = 'en';
+
+ if (this._translate_condition) {
+ let fc_locales = ['bs', 'de', 'en', 'es', 'fr', 'it', 'nl', 'pl', 'pt', 'ru', 'tet', 'x-pig-latin'];
+ let locale = GLib.get_language_names()[0];
+
+ if (locale.indexOf('_') != -1)
+ locale = locale.split("_")[0];
+
+ if (fc_locales.indexOf(locale) != -1)
+ this.fc_locale = locale;
+ }
+ },
+
+ getWeatherProviderURL: function() {
+ let url = "";
+ if (this._weather_provider == WeatherProvider.FORECAST_IO) {
+ url = "https://forecast.io/#/f/";
+ url += this.extractCoord(this._city);
+ } else {
+ url = "https://openweathermap.org";
+ url += "/city/" + this.owmCityId;
+ if (this._appid)
+ url += "?APPID=" + this._appid;
+ }
+ return url;
+ },
+
+ loadConfig: function() {
+ this._settings = Convenience.getSettings(OPENWEATHER_SETTINGS_SCHEMA);
+
+ if (this._cities.length === 0)
+ this._cities = "-8.5211767,179.1976747>Vaiaku, Tuvalu>-1";
+
+ this._settingsC = this._settings.connect("changed", Lang.bind(this, function() {
+ if (this._cities.length === 0)
+ this._cities = "-8.5211767,179.1976747>Vaiaku, Tuvalu>-1";
+ this.rebuildCurrentWeatherUi();
+ this.rebuildFutureWeatherUi();
+ if (this.providerChanged()) {
+ this.switchProvider();
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ }
+ if (this.locationChanged()) {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ }
+ this.rebuildButtonMenu();
+ this.parseWeatherCurrent();
+ }));
+ },
+
+ loadConfigInterface: function() {
+ this._settingsInterface = Convenience.getSettings(OPENWEATHER_DESKTOP_INTERFACE);
+ this._settingsInterfaceC = this._settingsInterface.connect("changed", Lang.bind(this, function() {
+ this.rebuildCurrentWeatherUi();
+ this.rebuildFutureWeatherUi();
+ if (this.providerChanged()) {
+ this.switchProvider();
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ }
+ if (this.locationChanged()) {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ }
+ this.parseWeatherCurrent();
+ }));
+ },
+
+ _onNetworkStateChanged: function() {
+ this._checkConnectionState();
+ },
+
+ _checkConnectionState: function() {
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._network_monitor.connectivity = '+this._network_monitor.connectivity);
+ this._connected = this._network_monitor.network_available;
+
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._connected = '+this._connected);
+
+ if (this._connected) {
+ if (!this._timeoutForecast)
+ this.forecastWeatherCache = undefined;
+ if (!this._timeoutCurrent)
+ this.currentWeatherCache = undefined;
+ this.parseWeatherCurrent();
+ }
+ },
+
+ locationChanged: function() {
+ let location = this.extractCoord(this._city);
+ if (this.oldLocation != location) {
+ return true;
+ }
+ return false;
+ },
+
+ providerChanged: function() {
+ let provider = this._weather_provider;
+ if (this.oldProvider != provider) {
+ this.oldProvider = provider;
+ return true;
+ }
+ if (provider == WeatherProvider.FORECAST_IO) {
+ let translateCondition = this._translate_condition;
+ if (this.oldTranslateCondition != translateCondition) {
+ this.oldTranslateCondition = translateCondition;
+ return true;
+ }
+ }
+ return false;
+ },
+
+ get _clockFormat() {
+ if (!this._settingsInterface)
+ this.loadConfigInterface();
+ return this._settingsInterface.get_string("clock-format");
+ },
+
+ get _weather_provider() {
+ if (!this._settings)
+ this.loadConfig();
+
+ let provider = this.extractProvider(this._city);
+
+ if (provider == WeatherProvider.DEFAULT)
+ provider = this._settings.get_enum(OPENWEATHER_PROVIDER_KEY);
+
+ return provider;
+ },
+
+ get _units() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(OPENWEATHER_UNIT_KEY);
+ },
+
+ get _wind_speed_units() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(OPENWEATHER_WIND_SPEED_UNIT_KEY);
+ },
+
+ get _wind_direction() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_WIND_DIRECTION_KEY);
+ },
+
+ get _pressure_units() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(OPENWEATHER_PRESSURE_UNIT_KEY);
+ },
+
+ get _cities() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_string(OPENWEATHER_CITY_KEY);
+ },
+
+ get _actual_city() {
+ if (!this._settings)
+ this.loadConfig();
+ var a = this._settings.get_int(OPENWEATHER_ACTUAL_CITY_KEY);
+ var b = a;
+ var cities = this._cities.split(" && ");
+
+ if (typeof cities != "object")
+ cities = [cities];
+
+ var l = cities.length - 1;
+
+ if (a < 0)
+ a = 0;
+
+ if (l < 0)
+ l = 0;
+
+ if (a > l)
+ a = l;
+
+ return a;
+ },
+
+ set _actual_city(a) {
+ if (!this._settings)
+ this.loadConfig();
+ var cities = this._cities.split(" && ");
+
+ if (typeof cities != "object")
+ cities = [cities];
+
+ var l = cities.length - 1;
+
+ if (a < 0)
+ a = 0;
+
+ if (l < 0)
+ l = 0;
+
+ if (a > l)
+ a = l;
+
+ this._settings.set_int(OPENWEATHER_ACTUAL_CITY_KEY, a);
+ },
+
+ get _city() {
+ let cities = this._cities;
+ let cities = cities.split(" && ");
+ if (cities && typeof cities == "string")
+ cities = [cities];
+ if (!cities[0])
+ return "";
+ cities = cities[this._actual_city];
+ return cities;
+ },
+
+ get _translate_condition() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_TRANSLATE_CONDITION_KEY);
+ },
+
+ get _getIconType() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_USE_SYMBOLIC_ICONS_KEY) ? 1 : 0;
+ },
+
+ get _use_text_on_buttons() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_USE_TEXT_ON_BUTTONS_KEY) ? 1 : 0;
+ },
+
+ get _text_in_panel() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_SHOW_TEXT_IN_PANEL_KEY);
+ },
+
+ get _position_in_panel() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(OPENWEATHER_POSITION_IN_PANEL_KEY);
+ },
+
+ get _comment_in_panel() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_SHOW_COMMENT_IN_PANEL_KEY);
+ },
+
+ get _comment_in_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_SHOW_COMMENT_IN_FORECAST_KEY);
+ },
+
+ get _refresh_interval_current() {
+ if (!this._settings)
+ this.loadConfig();
+ let v = this._settings.get_int(OPENWEATHER_REFRESH_INTERVAL_CURRENT);
+// return ((v >= 600) ? v : 600);
+ return 30;
+ },
+
+ get _refresh_interval_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ let v = this._settings.get_int(OPENWEATHER_REFRESH_INTERVAL_FORECAST);
+// return ((v >= 600) ? v : 600);
+ return 30;
+ },
+
+ get _center_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(OPENWEATHER_CENTER_FORECAST_KEY);
+ },
+
+ get _days_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_int(OPENWEATHER_DAYS_FORECAST);
+ },
+
+ get _decimal_places() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_int(OPENWEATHER_DECIMAL_PLACES);
+ },
+
+ get _appid() {
+ if (!this._settings)
+ this.loadConfig();
+ let key = this._settings.get_string(OPENWEATHER_OWM_API_KEY);
+ return (key.length == 32) ? key : '';
+ },
+
+ get _appid_fc() {
+ if (!this._settings)
+ this.loadConfig();
+ let key = this._settings.get_string(OPENWEATHER_FC_API_KEY);
+ return (key.length == 32) ? key : '';
+ },
+
+ rebuildButtonMenu: function() {
+ if (this._buttonBox) {
+ if (this._buttonBox1) {
+ this._buttonBox1.destroy();
+ this._buttonBox1 = undefined;
+
+ }
+ if (this._buttonBox2) {
+ this._buttonBox2.destroy();
+ this._buttonBox2 = undefined;
+ }
+ this._buttonMenu.removeActor(this._buttonBox);
+ this._buttonBox.destroy();
+ this._buttonBox = undefined;
+ }
+
+ if (this._buttonBox1) {
+ this._buttonBox1.destroy();
+ this._buttonBox1 = undefined;
+ }
+ if (this._buttonBox2) {
+ this._buttonBox2.destroy();
+ this._buttonBox2 = undefined;
+ }
+
+ this._locationButton = Main.panel.statusArea.aggregateMenu._system._createActionButton('find-location-symbolic', _("Locations"));
+ if (this._use_text_on_buttons)
+ this._locationButton.set_label(this._locationButton.get_accessible_name());
+
+ this._locationButton.connect('clicked', Lang.bind(this, function() {
+ this._selectCity._setOpenState(!this._selectCity._getOpenState());
+ }));
+ this._buttonBox1 = new St.BoxLayout({
+ style_class: 'openweather-button-box'
+ });
+ this._buttonBox1.add_actor(this._locationButton);
+
+ this._reloadButton = Main.panel.statusArea.aggregateMenu._system._createActionButton('view-refresh-symbolic', _("Reload Weather Information"));
+ if (this._use_text_on_buttons)
+ this._reloadButton.set_label(this._reloadButton.get_accessible_name());
+ this._reloadButton.connect('clicked', Lang.bind(this, function() {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ this.parseWeatherCurrent();
+ this.recalcLayout();
+ }));
+ this._buttonBox1.add_actor(this._reloadButton);
+
+ this._buttonBox2 = new St.BoxLayout({
+ style_class: 'openweather-button-box'
+ });
+
+ this._urlButton = Main.panel.statusArea.aggregateMenu._system._createActionButton('', _("Weather data provided by:") + (this._use_text_on_buttons ? "\n" : " ") + this.weatherProvider);
+ this._urlButton.set_label(this._urlButton.get_accessible_name());
+ this._urlButton.style_class += ' openweather-provider';
+
+ this._urlButton.connect('clicked', Lang.bind(this, function() {
+ this.menu.actor.hide();
+ let url = this.getWeatherProviderURL();
+
+ try {
+ Gtk.show_uri(null, url, global.get_current_time());
+ } catch (err) {
+ let title = _("Can not open %s").format(url);
+ Main.notifyError(title, err.message);
+ }
+ }));
+
+ this._buttonBox2.add_actor(this._urlButton);
+
+ this._prefsButton = Main.panel.statusArea.aggregateMenu._system._createActionButton('preferences-system-symbolic', _("Weather Settings"));
+ if (this._use_text_on_buttons)
+ this._prefsButton.set_label(this._prefsButton.get_accessible_name());
+ this._prefsButton.connect('clicked', Lang.bind(this, this._onPreferencesActivate));
+ this._buttonBox2.add_actor(this._prefsButton);
+
+ this._buttonMenu.actor.add_actor(this._buttonBox1);
+ this._buttonMenu.actor.add_actor(this._buttonBox2);
+
+ this._buttonBox1MinWidth = undefined;
+ },
+
+ rebuildSelectCityItem: function() {
+ this._selectCity.menu.removeAll();
+ let item = null;
+
+ let cities = this._cities;
+ cities = cities.split(" && ");
+ if (cities && typeof cities == "string")
+ cities = [cities];
+ if (!cities[0])
+ return;
+
+ for (let i = 0; cities.length > i; i++) {
+ item = new PopupMenu.PopupMenuItem(this.extractLocation(cities[i]));
+ item.location = i;
+ if (i == this._actual_city) {
+ item.setOrnament(PopupMenu.Ornament.DOT);
+ }
+
+ this._selectCity.menu.addMenuItem(item);
+ // override the items default onActivate-handler, to keep the ui open while chosing the location
+ item.activate = this._onActivate;
+ }
+
+ if (cities.length == 1)
+ this._selectCity.actor.hide();
+ else
+ this._selectCity.actor.show();
+
+ },
+
+ _onActivate: function() {
+ openweatherMenu._actual_city = this.location;
+ },
+
+ extractLocation: function() {
+ if (!arguments[0])
+ return "";
+
+ if (arguments[0].search(">") == -1)
+ return _("Invalid city");
+ return arguments[0].split(">")[1];
+ },
+
+ extractCoord: function() {
+ let coords = 0;
+
+ if (arguments[0] && (arguments[0].search(">") != -1))
+ coords = arguments[0].split(">")[0];
+
+ if ((coords.search(",") == -1) || isNaN(coords.split(",")[0]) || isNaN(coords.split(",")[1])) {
+ Main.notify("Openweathermap", _("Invalid location! Please try to recreate it."));
+ return 0;
+ }
+
+ return coords;
+ },
+
+ extractProvider: function() {
+ if (!arguments[0])
+ return -1;
+ if (arguments[0].split(">")[2] === undefined)
+ return -1;
+ if (isNaN(parseInt(arguments[0].split(">")[2])))
+ return -1;
+ return parseInt(arguments[0].split(">")[2]);
+ },
+
+ _onPreferencesActivate: function() {
+ this.menu.actor.hide();
+ Util.spawn(["gnome-shell-extension-prefs", "openweather-extension@jenslody.de"]);
+ return 0;
+ },
+
+ recalcLayout: function() {
+ if (!this.menu.isOpen)
+ return;
+ if (this._buttonBox1MinWidth === undefined)
+ this._buttonBox1MinWidth = this._buttonBox1.get_width();
+ this._buttonBox1.set_width(Math.max(this._buttonBox1MinWidth, this._currentWeather.get_width() - this._buttonBox2.get_width()));
+ if (this._forecastScrollBox !== undefined && this._forecastBox !== undefined && this._currentWeather !== undefined) {
+ this._forecastScrollBox.set_width(Math.max(this._currentWeather.get_width(), (this._buttonBox1.get_width() + this._buttonBox2.get_width())));
+ this._forecastScrollBox.show();
+ if (this._forecastBox.get_preferred_width(this._forecastBox.get_height())[0] > this._currentWeather.get_width()) {
+ this._forecastScrollBox.hscroll.margin_top = 10;
+ this._forecastScrollBox.hscroll.show();
+ } else {
+ this._forecastScrollBox.hscroll.margin_top = 0;
+ this._forecastScrollBox.hscroll.hide();
+ }
+ }
+ },
+
+ unit_to_unicode: function() {
+ if (this._units == WeatherUnits.FAHRENHEIT)
+ return '\u00B0F';
+ else if (this._units == WeatherUnits.KELVIN)
+ return 'K';
+ else if (this._units == WeatherUnits.RANKINE)
+ return '\u00B0Ra';
+ else if (this._units == WeatherUnits.REAUMUR)
+ return '\u00B0R\u00E9';
+ else if (this._units == WeatherUnits.ROEMER)
+ return '\u00B0R\u00F8';
+ else if (this._units == WeatherUnits.DELISLE)
+ return '\u00B0De';
+ else if (this._units == WeatherUnits.NEWTON)
+ return '\u00B0N';
+ else
+ return '\u00B0C';
+ },
+
+ hasIcon: function(icon) {
+ return Gtk.IconTheme.get_default().has_icon(icon + this.getIconType());
+ },
+
+ toFahrenheit: function(t) {
+ return ((Number(t) * 1.8) + 32).toFixed(this._decimal_places);
+ },
+
+ toKelvin: function(t) {
+ return (Number(t) + 273.15).toFixed(this._decimal_places);
+ },
+
+ toRankine: function(t) {
+ return ((Number(t) * 1.8) + 491.67).toFixed(this._decimal_places);
+ },
+
+ toReaumur: function(t) {
+ return (Number(t) * 0.8).toFixed(this._decimal_places);
+ },
+
+ toRoemer: function(t) {
+ return ((Number(t) * 21 / 40) + 7.5).toFixed(this._decimal_places);
+ },
+
+ toDelisle: function(t) {
+ return ((100 - Number(t)) * 1.5).toFixed(this._decimal_places);
+ },
+
+ toNewton: function(t) {
+ return (Number(t) - 0.33).toFixed(this._decimal_places);
+ },
+
+ toInHg: function(p /*, t*/ ) {
+ return (p / 33.86530749).toFixed(this._decimal_places);
+ },
+
+ toBeaufort: function(w, t) {
+ if (w < 0.3)
+ return (!t) ? "0" : "(" + _("Calm") + ")";
+
+ else if (w >= 0.3 && w <= 1.5)
+ return (!t) ? "1" : "(" + _("Light air") + ")";
+
+ else if (w > 1.5 && w <= 3.4)
+ return (!t) ? "2" : "(" + _("Light breeze") + ")";
+
+ else if (w > 3.4 && w <= 5.4)
+ return (!t) ? "3" : "(" + _("Gentle breeze") + ")";
+
+ else if (w > 5, 4 && w <= 7.9)
+ return (!t) ? "4" : "(" + _("Moderate breeze") + ")";
+
+ else if (w > 7.9 && w <= 10.7)
+ return (!t) ? "5" : "(" + _("Fresh breeze") + ")";
+
+ else if (w > 10.7 && w <= 13.8)
+ return (!t) ? "6" : "(" + _("Strong breeze") + ")";
+
+ else if (w > 13.8 && w <= 17.1)
+ return (!t) ? "7" : "(" + _("Moderate gale") + ")";
+
+ else if (w > 17.1 && w <= 20.7)
+ return (!t) ? "8" : "(" + _("Fresh gale") + ")";
+
+ else if (w > 20.7 && w <= 24.4)
+ return (!t) ? "9" : "(" + _("Strong gale") + ")";
+
+ else if (w > 24.4 && w <= 28.4)
+ return (!t) ? "10" : "(" + _("Storm") + ")";
+
+ else if (w > 28.4 && w <= 32.6)
+ return (!t) ? "11" : "(" + _("Violent storm") + ")";
+
+ else
+ return (!t) ? "12" : "(" + _("Hurricane") + ")";
+ },
+
+ getLocaleDay: function(abr) {
+ let days = [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')];
+ return days[abr];
+ },
+
+ getWindDirection: function(deg) {
+ let arrows = ["\u2193", "\u2199", "\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198"];
+ let letters = [_('N'), _('NE'), _('E'), _('SE'), _('S'), _('SW'), _('W'), _('NW')];
+ let idx = Math.round(deg / 45) % arrows.length;
+ return (this._wind_direction) ? arrows[idx] : letters[idx];
+ },
+
+ getIconType: function(icon_name) {
+ if (!icon_name)
+ if (this._getIconType)
+ return "-symbolic";
+ else
+ return "";
+
+ if (this._getIconType)
+ if (String(icon_name).search("-symbolic") != -1)
+ return icon_name;
+ else
+ return icon_name + "-symbolic";
+ else
+ if (String(icon_name).search("-symbolic") != -1)
+ return String(icon_name).replace("-symbolic", "");
+ else
+ return icon_name;
+ },
+
+ load_json_async: function(url, params, fun) {
+ if (_httpSession === undefined) {
+ _httpSession = new Soup.Session();
+ }
+
+ let message = Soup.form_request_new_from_hash('GET', url, params);
+
+ _httpSession.queue_message(message, Lang.bind(this, function(_httpSession, message) {
+
+ try {
+ if (!message.response_body.data) {
+ fun.call(this, 0);
+ return;
+ }
+ let jp = JSON.parse(message.response_body.data);
+ fun.call(this, jp);
+ } catch (e) {
+ fun.call(this, 0);
+ return;
+ }
+ }));
+ return;
+ },
+
+ checkPositionInPanel: function() {
+ if (this._old_position_in_panel != this._position_in_panel) {
+ switch (this._old_position_in_panel) {
+ case WeatherPosition.LEFT:
+ Main.panel._leftBox.remove_actor(this.actor);
+ break;
+ case WeatherPosition.CENTER:
+ Main.panel._centerBox.remove_actor(this.actor);
+ break;
+ case WeatherPosition.RIGHT:
+ Main.panel._rightBox.remove_actor(this.actor);
+ break;
+ }
+
+ let children = null;
+ switch (this._position_in_panel) {
+ case WeatherPosition.LEFT:
+ children = Main.panel._leftBox.get_children();
+ Main.panel._leftBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.CENTER:
+ children = Main.panel._centerBox.get_children();
+ Main.panel._centerBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.RIGHT:
+ children = Main.panel._rightBox.get_children();
+ Main.panel._rightBox.insert_child_at_index(this.actor, 0);
+ break;
+ }
+ this._old_position_in_panel = this._position_in_panel;
+ }
+
+ },
+
+ formatPressure: function(pressure) {
+ let pressure_unit = 'hPa';
+ switch (this._pressure_units) {
+ case WeatherPressureUnits.INHG:
+ pressure = this.toInHg(pressure);
+ pressure_unit = "inHg";
+ break;
+
+ case WeatherPressureUnits.HPA:
+ pressure = pressure.toFixed(this._decimal_places);
+ pressure_unit = "hPa";
+ break;
+
+ case WeatherPressureUnits.BAR:
+ pressure = (pressure / 1000).toFixed(this._decimal_places);
+ pressure_unit = "bar";
+ break;
+
+ case WeatherPressureUnits.PA:
+ pressure = (pressure * 100).toFixed(this._decimal_places);
+ pressure_unit = "Pa";
+ break;
+
+ case WeatherPressureUnits.KPA:
+ pressure = (pressure / 10).toFixed(this._decimal_places);
+ pressure_unit = "kPa";
+ break;
+
+ case WeatherPressureUnits.ATM:
+ pressure = (pressure * 0.000986923267).toFixed(this._decimal_places);
+ pressure_unit = "atm";
+ break;
+
+ case WeatherPressureUnits.AT:
+ pressure = (pressure * 0.00101971621298).toFixed(this._decimal_places);
+ pressure_unit = "at";
+ break;
+
+ case WeatherPressureUnits.TORR:
+ pressure = (pressure * 0.750061683).toFixed(this._decimal_places);
+ pressure_unit = "Torr";
+ break;
+
+ case WeatherPressureUnits.PSI:
+ pressure = (pressure * 0.0145037738).toFixed(this._decimal_places);
+ pressure_unit = "psi";
+ break;
+
+ case WeatherPressureUnits.MMHG:
+ pressure = (pressure * 0.750061683).toFixed(this._decimal_places);
+ pressure_unit = "mmHg";
+ break;
+ }
+ return parseFloat(pressure).toLocaleString() + ' ' + pressure_unit;
+ },
+
+ formatTemperature: function(temperature) {
+ switch (this._units) {
+ case WeatherUnits.FAHRENHEIT:
+ temperature = this.toFahrenheit(temperature);
+ break;
+
+ case WeatherUnits.CELSIUS:
+ temperature = temperature.toFixed(this._decimal_places);
+ break;
+
+ case WeatherUnits.KELVIN:
+ temperature = this.toKelvin(temperature);
+ break;
+
+ case WeatherUnits.RANKINE:
+ temperature = this.toRankine(temperature);
+ break;
+
+ case WeatherUnits.REAUMUR:
+ temperature = this.toReaumur(temperature);
+ break;
+
+ case WeatherUnits.ROEMER:
+ temperature = this.toRoemer(temperature);
+ break;
+
+ case WeatherUnits.DELISLE:
+ temperature = this.toDelisle(temperature);
+ break;
+
+ case WeatherUnits.NEWTON:
+ temperature = this.toNewton(temperature);
+ break;
+ }
+ return parseFloat(temperature).toLocaleString() + ' ' + this.unit_to_unicode();
+ },
+
+ formatWind: function(speed, direction) {
+ let unit = 'm/s';
+ switch (this._wind_speed_units) {
+ case WeatherWindSpeedUnits.MPH:
+ speed = (speed * OPENWEATHER_CONV_MPS_IN_MPH).toFixed(this._decimal_places);
+ unit = 'mph';
+ break;
+
+ case WeatherWindSpeedUnits.KPH:
+ speed = (speed * OPENWEATHER_CONV_MPS_IN_KPH).toFixed(this._decimal_places);
+ unit = 'km/h';
+ break;
+
+ case WeatherWindSpeedUnits.MPS:
+ speed = speed.toFixed(this._decimal_places);
+ break;
+
+ case WeatherWindSpeedUnits.KNOTS:
+ speed = (speed * OPENWEATHER_CONV_MPS_IN_KNOTS).toFixed(this._decimal_places);
+ unit = 'kn';
+ break;
+
+ case WeatherWindSpeedUnits.FPS:
+ speed = (speed * OPENWEATHER_CONV_MPS_IN_FPS).toFixed(this._decimal_places);
+ unit = 'ft/s';
+ break;
+
+ case WeatherWindSpeedUnits.BEAUFORT:
+ speed = this.toBeaufort(speed);
+ unit = this.toBeaufort(speed, true);
+ break;
+
+ }
+
+ if (!speed)
+ return '\u2013';
+ else if (speed === 0 || !direction)
+ return parseFloat(speed).toLocaleString() + ' ' + unit;
+ else // i.e. speed > 0 && direction
+ return direction + ' ' + parseFloat(speed).toLocaleString() + ' ' + unit;
+ },
+
+ reloadWeatherCurrent: function(interval) {
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._timeoutCurrent = '+this._timeoutCurrent);
+ if (this._timeoutCurrent) {
+ Mainloop.source_remove(this._timeoutCurrent);
+ this._timeoutCurrent = undefined;
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._timeoutCurrent = '+this._timeoutCurrent);
+ }
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._timeoutCurrent = '+this._timeoutCurrent);
+ if (this._connected) {
+ this._timeoutCurrent = Mainloop.timeout_add_seconds(interval, Lang.bind(this, function() {
+ this.currentWeatherCache = undefined;
+ this.parseWeatherCurrent();
+ return true;
+ }));
+ }
+ },
+
+ reloadWeatherForecast: function(interval) {
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._timeoutForecast = '+this._timeoutForecast);
+ if (this._timeoutForecast) {
+ Mainloop.source_remove(this._timeoutForecast);
+ this._timeoutForecast = undefined;
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._timeoutForecast = '+this._timeoutForecast);
+ }
+ log(new Error().fileName+':'+new Error().lineNumber+' => this._timeoutForecast = '+this._timeoutForecast);
+ if (this._connected) {
+ this._timeoutForecast = Mainloop.timeout_add_seconds(interval, Lang.bind(this, function() {
+ this.forecastWeatherCache = undefined;
+ this.parseWeatherForecast();
+ return true;
+ }));
+ }
+ },
+
+ destroyCurrentWeather: function() {
+ if (this._currentWeather.get_child() !== null)
+ this._currentWeather.get_child().destroy();
+ },
+
+ destroyFutureWeather: function() {
+ if (this._futureWeather.get_child() !== null)
+ this._futureWeather.get_child().destroy();
+ },
+
+ rebuildCurrentWeatherUi: function() {
+ this._weatherInfo.text = _(' ');
+ this._weatherIcon.icon_name = 'view-refresh' + this.getIconType();
+
+ this.destroyCurrentWeather();
+
+ // This will hold the icon for the current weather
+ this._currentWeatherIcon = new St.Icon({
+ icon_size: 72,
+ icon_name: 'view-refresh' + this.getIconType(),
+ style_class: 'system-menu-action openweather-current-icon'
+ });
+
+ this._sunriseIcon = new St.Icon({
+ icon_size: 15,
+ icon_name: 'weather-clear' + this.getIconType(),
+ style_class: 'openweather-sunrise-icon'
+ });
+
+ this._sunsetIcon = new St.Icon({
+ icon_size: 15,
+ icon_name: 'weather-clear-night' + this.getIconType(),
+ style_class: 'openweather-sunset-icon'
+ });
+
+ this._buildIcon = new St.Icon({
+ icon_size: 15,
+ icon_name: 'view-refresh' + this.getIconType(),
+ style_class: 'openweather-build-icon'
+ });
+
+ // The summary of the current weather
+ this._currentWeatherSummary = new St.Label({
+ text: _('Loading ...'),
+ style_class: 'openweather-current-summary'
+ });
+ this._currentWeatherLocation = new St.Label({
+ text: _('Please wait')
+ });
+
+ let bb = new St.BoxLayout({
+ vertical: true,
+ style_class: 'system-menu-action openweather-current-summarybox'
+ });
+ bb.add_actor(this._currentWeatherLocation);
+ bb.add_actor(this._currentWeatherSummary);
+
+ this._currentWeatherSunrise = new St.Label({
+ text: '-'
+ });
+ this._currentWeatherSunset = new St.Label({
+ text: '-'
+ });
+ this._currentWeatherBuild = new St.Label({
+ text: '-'
+ });
+
+ let ab = new St.BoxLayout({
+ style_class: 'openweather-current-infobox'
+ });
+
+ ab.add_actor(this._sunriseIcon);
+ ab.add_actor(this._currentWeatherSunrise);
+ ab.add_actor(this._sunsetIcon);
+ ab.add_actor(this._currentWeatherSunset);
+ ab.add_actor(this._buildIcon);
+ ab.add_actor(this._currentWeatherBuild);
+ bb.add_actor(ab);
+
+ // Other labels
+ this._currentWeatherCloudiness = new St.Label({
+ text: '...'
+ });
+ this._currentWeatherHumidity = new St.Label({
+ text: '...'
+ });
+ this._currentWeatherPressure = new St.Label({
+ text: '...'
+ });
+ this._currentWeatherWind = new St.Label({
+ text: '...'
+ });
+
+ let rb = new St.BoxLayout({
+ style_class: 'openweather-current-databox'
+ });
+ let rb_captions = new St.BoxLayout({
+ vertical: true,
+ style_class: 'popup-status-menu-item openweather-current-databox-captions'
+ });
+ let rb_values = new St.BoxLayout({
+ vertical: true,
+ style_class: 'system-menu-action openweather-current-databox-values'
+ });
+ rb.add_actor(rb_captions);
+ rb.add_actor(rb_values);
+
+ rb_captions.add_actor(new St.Label({
+ text: _('Cloudiness:')
+ }));
+ rb_values.add_actor(this._currentWeatherCloudiness);
+ rb_captions.add_actor(new St.Label({
+ text: _('Humidity:')
+ }));
+ rb_values.add_actor(this._currentWeatherHumidity);
+ rb_captions.add_actor(new St.Label({
+ text: _('Pressure:')
+ }));
+ rb_values.add_actor(this._currentWeatherPressure);
+ rb_captions.add_actor(new St.Label({
+ text: _('Wind:')
+ }));
+ rb_values.add_actor(this._currentWeatherWind);
+
+ let xb = new St.BoxLayout();
+ xb.add_actor(bb);
+ xb.add_actor(rb);
+
+ let box = new St.BoxLayout({
+ style_class: 'openweather-current-iconbox'
+ });
+ box.add_actor(this._currentWeatherIcon);
+ box.add_actor(xb);
+ this._currentWeather.set_child(box);
+ },
+
+ scrollForecastBy: function(delta) {
+ if (this._forecastScrollBox === undefined)
+ return;
+ this._forecastScrollBox.hscroll.adjustment.value += delta;
+ },
+
+ rebuildFutureWeatherUi: function(cnt) {
+ this.destroyFutureWeather();
+
+ this._forecast = [];
+ this._forecastBox = new St.BoxLayout({
+ x_align: this._center_forecast ? St.Align.END : St.Align.START,
+ style_class: 'openweather-forecast-box'
+ });
+
+ this._forecastScrollBox = new St.ScrollView({
+ style_class: 'openweather-forecasts'
+ });
+
+ let pan = new Clutter.PanAction({
+ interpolate: true
+ });
+ pan.connect('pan', Lang.bind(this, function(action) {
+
+ let[dist, dx, dy] = action.get_motion_delta(0);
+
+ this.scrollForecastBy(-1 * (dx / this._forecastScrollBox.width) * this._forecastScrollBox.hscroll.adjustment.page_size);
+ return false;
+ }));
+ this._forecastScrollBox.add_action(pan);
+
+ this._forecastScrollBox.connect('scroll-event', Lang.bind(this, this._onScroll));
+ this._forecastScrollBox.hscroll.connect('scroll-event', Lang.bind(this, this._onScroll));
+
+ this._forecastScrollBox.hscroll.margin_right = 25;
+ this._forecastScrollBox.hscroll.margin_left = 25;
+ this._forecastScrollBox.hscroll.hide();
+ this._forecastScrollBox.vscrollbar_policy = Gtk.PolicyType.NEVER;
+ this._forecastScrollBox.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
+ this._forecastScrollBox.enable_mouse_scrolling = true;
+ this._forecastScrollBox.hide();
+
+ this._futureWeather.set_child(this._forecastScrollBox);
+
+ if (cnt === undefined)
+ cnt = this._days_forecast;
+ for (let i = 0; i < cnt; i++) {
+ let forecastWeather = {};
+
+ forecastWeather.Icon = new St.Icon({
+ icon_size: 48,
+ icon_name: 'view-refresh' + this.getIconType(),
+ style_class: 'system-menu-action openweather-forecast-icon'
+ });
+ forecastWeather.Day = new St.Label({
+ style_class: 'popup-status-menu-item openweather-forecast-day'
+ });
+ forecastWeather.Summary = new St.Label({
+ style_class: 'system-menu-action openweather-forecast-summary'
+ });
+ forecastWeather.Summary.clutter_text.line_wrap = true;
+ forecastWeather.Temperature = new St.Label({
+ style_class: 'system-menu-action openweather-forecast-temperature'
+ });
+
+ let by = new St.BoxLayout({
+ vertical: true,
+ style_class: 'openweather-forecast-databox'
+ });
+ by.add_actor(forecastWeather.Day);
+ if (this._comment_in_forecast)
+ by.add_actor(forecastWeather.Summary);
+ by.add_actor(forecastWeather.Temperature);
+
+ let bb = new St.BoxLayout({
+ style_class: 'openweather-forecast-iconbox'
+ });
+ bb.add_actor(forecastWeather.Icon);
+ bb.add_actor(by);
+
+ this._forecast[i] = forecastWeather;
+ this._forecastBox.add_actor(bb);
+ }
+ this._forecastScrollBox.add_actor(this._forecastBox);
+ },
+
+ _onScroll: function(actor, event) {
+ let dx = 0;
+ let dy = 0;
+ switch (event.get_scroll_direction()) {
+ case Clutter.ScrollDirection.UP:
+ dy = -1;
+ break;
+ case Clutter.ScrollDirection.DOWN:
+ dy = 1;
+ break;
+ // horizontal scrolling will be handled by the control itself
+ default:
+ return true;
+ }
+
+ this.scrollForecastBy(dy * this._forecastScrollBox.hscroll.adjustment.stepIncrement);
+ return false;
+ }
+});
+
+let openweatherMenu;
+
+function init() {
+ Convenience.initTranslations('gnome-shell-extension-openweather');
+}
+
+function enable() {
+ openweatherMenu = new OpenweatherMenuButton();
+ Main.panel.addToStatusArea('openweatherMenu', openweatherMenu);
+}
+
+function disable() {
+ openweatherMenu.stop();
+ openweatherMenu.destroy();
+}
diff --git a/src/fetch_data_base.js b/src/fetch_data_base.js
new file mode 100644
index 0000000..b8eeedd
--- /dev/null
+++ b/src/fetch_data_base.js
@@ -0,0 +1,1979 @@
+/* jshint esnext:true */
+/*
+ *
+ * Weather extension for GNOME Shell
+ * - Displays a small weather information on the top panel.
+ * - On click, gives a popup with details about the weather.
+ *
+ * Copyright (C) 2011 - 2015
+ * ecyrbe ,
+ * Timur Kristof ,
+ * Elad Alfassa ,
+ * Simon Legner ,
+ * Christian METZLER ,
+ * Mark Benjamin weather.gnome.Markie1@dfgh.net,
+ * Mattia Meneguzzo odysseus@fedoraproject.org,
+ * Meng Zhuo ,
+ * Jens Lody
+ *
+ *
+ * This file is part of gnome-shell-extension-openweather.
+ *
+ * gnome-shell-extension-openweather is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * gnome-shell-extension-openweather is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with gnome-shell-extension-openweather. If not, see .
+ *
+ */
+
+const ExtensionUtils = imports.misc.extensionUtils;
+const Me = ExtensionUtils.getCurrentExtension();
+const Config = imports.misc.config;
+const Convenience = Me.imports.convenience;
+const Clutter = imports.gi.Clutter;
+const Gettext = imports.gettext.domain('gnome-shell-extension-openweather');
+const Gio = imports.gi.Gio;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Soup = imports.gi.Soup;
+const St = imports.gi.St;
+const Util = imports.misc.util;
+const _ = Gettext.gettext;
+
+const Main = imports.ui.main;
+const PanelMenu = imports.ui.panelMenu;
+const PopupMenu = imports.ui.popupMenu;
+
+// Settings
+const WEATHER_SETTINGS_SCHEMA = 'org.gnome.shell.extensions.openweather';
+const WEATHER_UNIT_KEY = 'unit';
+const WEATHER_WIND_SPEED_UNIT_KEY = 'wind-speed-unit';
+const WEATHER_WIND_DIRECTION_KEY = 'wind-direction';
+const WEATHER_PRESSURE_UNIT_KEY = 'pressure-unit';
+const WEATHER_CITY_KEY = 'city';
+const WEATHER_ACTUAL_CITY_KEY = 'actual-city';
+const WEATHER_TRANSLATE_CONDITION_KEY = 'translate-condition';
+const WEATHER_USE_SYMBOLIC_ICONS_KEY = 'use-symbolic-icons';
+const WEATHER_USE_TEXT_ON_BUTTONS_KEY = 'use-text-on-buttons';
+const WEATHER_SHOW_TEXT_IN_PANEL_KEY = 'show-text-in-panel';
+const WEATHER_POSITION_IN_PANEL_KEY = 'position-in-panel';
+const WEATHER_SHOW_COMMENT_IN_PANEL_KEY = 'show-comment-in-panel';
+const WEATHER_REFRESH_INTERVAL_CURRENT = 'refresh-interval-current';
+const WEATHER_REFRESH_INTERVAL_FORECAST = 'refresh-interval-forecast';
+const WEATHER_CENTER_FORECAST_KEY = 'center-forecast';
+const WEATHER_DAYS_FORECAST = 'days-forecast';
+const WEATHER_DECIMAL_PLACES = 'decimal-places';
+const WEATHER_OWM_API_KEY = 'appid';
+
+//URL
+const WEATHER_URL_HOST = '';
+const WEATHER_URL_PORT = 80;
+const WEATHER_URL_BASE = 'http://' + WEATHER_URL_HOST;
+const WEATHER_URL_CURRENT = WEATHER_URL_BASE + '';
+const WEATHER_URL_FORECAST = WEATHER_URL_BASE + '';
+
+// Keep enums in sync with GSettings schemas
+const WeatherUnits = {
+ CELSIUS: 0,
+ FAHRENHEIT: 1,
+ KELVIN: 2,
+ RANKINE: 3,
+ REAUMUR: 4,
+ ROEMER: 5,
+ DELISLE: 6,
+ NEWTON: 7
+};
+
+const WeatherWindSpeedUnits = {
+ KPH: 0,
+ MPH: 1,
+ MPS: 2,
+ KNOTS: 3,
+ FPS: 4,
+ BEAUFORT: 5
+};
+
+const WeatherPressureUnits = {
+ hPa: 0,
+ inHg: 1,
+ bar: 2,
+ Pa: 3,
+ kPa: 4,
+ atm: 5,
+ at: 6,
+ Torr: 7,
+ psi: 8,
+ mmHg: 9
+};
+
+const WeatherPosition = {
+ CENTER: 0,
+ RIGHT: 1,
+ LEFT: 2
+};
+
+const WEATHER_CONV_MPS_IN_MPH = 2.23693629;
+const WEATHER_CONV_MPS_IN_KPH = 3.6;
+const WEATHER_CONV_MPS_IN_KNOTS = 1.94384449;
+const WEATHER_CONV_MPS_IN_FPS = 3.2808399;
+
+let _httpSession;
+
+const OpenweatherProviderBase = new Lang.Class({
+ Name: 'OpenweatherProviderBase',
+
+ _init: function() {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ // Load settings
+ this.loadConfig();
+
+ // Label
+ this._weatherInfo = new St.Label({
+ y_align: Clutter.ActorAlign.CENTER,
+ text: _('...')
+ });
+
+ this._weatherIcon = new St.Icon({
+ icon_name: 'view-refresh' + this.icon_type(),
+ style_class: 'system-status-icon openweather-icon'
+ });
+
+ // Panel menu item - the current class
+ let menuAlignment = 0.25;
+ if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
+ menuAlignment = 1.0 - menuAlignment;
+ this.parent(menuAlignment);
+
+ // Putting the panel item together
+ let topBox = new St.BoxLayout();
+ topBox.add_actor(this._weatherIcon);
+ topBox.add_actor(this._weatherInfo);
+ this.actor.add_actor(topBox);
+
+ let dummyBox = new St.BoxLayout();
+ this.actor.reparent(dummyBox);
+ dummyBox.remove_actor(this.actor);
+ dummyBox.destroy();
+
+ let children = null;
+ switch (this._position_in_panel) {
+ case WeatherPosition.LEFT:
+ children = Main.panel._leftBox.get_children();
+ Main.panel._leftBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.CENTER:
+ children = Main.panel._centerBox.get_children();
+ Main.panel._centerBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.RIGHT:
+ children = Main.panel._rightBox.get_children();
+ Main.panel._rightBox.insert_child_at_index(this.actor, 0);
+ break;
+ }
+ if (Main.panel._menus === undefined)
+ Main.panel.menuManager.addMenu(this.menu);
+ else
+ Main.panel._menus.addMenu(this.menu);
+
+ this._old_position_in_panel = this._position_in_panel;
+
+ // Current weather
+ this._currentWeather = new St.Bin();
+ // Future weather
+ this._futureWeather = new St.Bin();
+
+ // Putting the popup item together
+ let _itemCurrent = new PopupMenu.PopupBaseMenuItem({
+ reactive: false
+ });
+ let _itemFuture = new PopupMenu.PopupBaseMenuItem({
+ reactive: false
+ });
+
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION)) {
+ _itemCurrent.addActor(this._currentWeather);
+ _itemFuture.addActor(this._futureWeather);
+ } else {
+ _itemCurrent.actor.add_actor(this._currentWeather);
+ _itemFuture.actor.add_actor(this._futureWeather);
+ }
+
+ this.menu.addMenuItem(_itemCurrent);
+
+ this._separatorItem = new PopupMenu.PopupSeparatorMenuItem();
+ this.menu.addMenuItem(this._separatorItem);
+
+ this.menu.addMenuItem(_itemFuture);
+
+ let item = new PopupMenu.PopupSeparatorMenuItem();
+ this.menu.addMenuItem(item);
+
+ this._selectCity = new PopupMenu.PopupSubMenuMenuItem("");
+ this._selectCity.actor.set_height(0);
+ this._selectCity._triangle.set_height(0);
+
+ this._buttonMenu = new PopupMenu.PopupBaseMenuItem({
+ reactive: false,
+ style_class: 'openweather-menu-button-container'
+ });
+
+ this.rebuildButtonMenu();
+
+ this.menu.addMenuItem(this._buttonMenu);
+ this.menu.addMenuItem(this._selectCity);
+ this.rebuildSelectCityItem();
+ this._selectCity.menu.connect('open-state-changed', Lang.bind(this, function() {
+ this._selectCity.actor.remove_style_pseudo_class('open');
+ }));
+
+ this.rebuildCurrentWeatherUi();
+ this.rebuildFutureWeatherUi();
+
+ this._network_monitor = Gio.network_monitor_get_default();
+
+ this._connected = false;
+ this._network_monitor_connection = this._network_monitor.connect('network-changed', Lang.bind(this, this._onNetworkStateChanged));
+ this._checkConnectionState();
+
+ this.menu.connect('open-state-changed', Lang.bind(this, this.recalcLayout));
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION)) {
+ this._needsColorUpdate = true;
+ let context = St.ThemeContext.get_for_stage(global.stage);
+ this._globalThemeChangedId = context.connect('changed', Lang.bind(this, function(){this._needsColorUpdate = true;}));
+ }
+ },
+
+ stop: function() {
+ if (_httpSession !== undefined)
+ _httpSession.abort();
+
+ _httpSession = undefined;
+
+ if (this._timeoutCurrent)
+ Mainloop.source_remove(this._timeoutCurrent);
+
+ this._timeoutCurrent = undefined;
+
+ if (this._timeoutForecast)
+ Mainloop.source_remove(this._timeoutForecast);
+
+ this._timeoutForecast = undefined;
+
+ if (this._network_monitor_connection) {
+ this._network_monitor.disconnect(this._network_monitor_connection);
+ this._network_monitor_connection = undefined;
+ }
+
+ if (this._settingsC) {
+ this._settings.disconnect(this._settingsC);
+ this._settingsC = undefined;
+ }
+
+ if (this._settingsInterfaceC) {
+ this._settingsInterface.disconnect(this._settingsInterfaceC);
+ this._settingsInterfaceC = undefined;
+ }
+
+ if (this._globalThemeChangedId) {
+ let context = St.ThemeContext.get_for_stage(global.stage);
+ context.disconnect(this._globalThemeChangedId);
+ this._globalThemeChangedId = undefined;
+ }
+ },
+
+ loadConfig: function() {
+ this._settings = Convenience.getSettings(WEATHER_SETTINGS_SCHEMA);
+ this._settingsC = this._settings.connect("changed", Lang.bind(this, function() {
+ this.rebuildCurrentWeatherUi();
+ this.rebuildFutureWeatherUi();
+ this.rebuildButtonMenu();
+ if (this.locationChanged()) {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ }
+ this.parseWeatherCurrent();
+ }));
+ },
+
+ loadConfigInterface: function() {
+ let schemaInterface = "org.gnome.desktop.interface";
+ if (Gio.Settings.list_schemas().indexOf(schemaInterface) == -1)
+ throw _("Schema \"%s\" not found.").replace("%s", schemaInterface);
+ this._settingsInterface = new Gio.Settings({
+ schema: schemaInterface
+ });
+ this._settingsInterfaceC = this._settingsInterface.connect("changed", Lang.bind(this, function() {
+ this.rebuildCurrentWeatherUi();
+ this.rebuildFutureWeatherUi();
+ if (this.locationChanged()) {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ }
+ this.parseWeatherCurrent();
+ }));
+ },
+
+ _onNetworkStateChanged: function() {
+ this._checkConnectionState();
+ },
+
+ _checkConnectionState: function() {
+ this._connected = this._network_monitor.network_available;
+ if (this._connected)
+ this.parseWeatherCurrent();
+ },
+
+ locationChanged: function() {
+ let location = this.extractId(this._city);
+ if (this.oldLocation != location) {
+ return true;
+ }
+ return false;
+ },
+
+ get _clockFormat() {
+ if (!this._settingsInterface)
+ this.loadConfigInterface();
+ return this._settingsInterface.get_string("clock-format");
+ },
+
+ get _units() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(WEATHER_UNIT_KEY);
+ },
+
+ set _units(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_enum(WEATHER_UNIT_KEY, v);
+ },
+
+ get _wind_speed_units() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(WEATHER_WIND_SPEED_UNIT_KEY);
+ },
+
+ set _wind_speed_units(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_enum(WEATHER_WIND_SPEED_UNIT_KEY, v);
+ },
+
+ get _wind_direction() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_WIND_DIRECTION_KEY);
+ },
+
+ set _wind_direction(v) {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.set_boolean(WEATHER_WIND_DIRECTION_KEY, v);
+ },
+
+ get _pressure_units() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(WEATHER_PRESSURE_UNIT_KEY);
+ },
+
+ set _pressure_units(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_enum(WEATHER_PRESSURE_UNIT_KEY, v);
+ },
+
+ get _cities() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_string(WEATHER_CITY_KEY);
+ },
+
+ set _cities(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_string(WEATHER_CITY_KEY, v);
+ },
+
+ get _actual_city() {
+ if (!this._settings)
+ this.loadConfig();
+ var a = this._settings.get_int(WEATHER_ACTUAL_CITY_KEY);
+ var b = a;
+ var cities = this._cities.split(" && ");
+
+ if (typeof cities != "object")
+ cities = [cities];
+
+ var l = cities.length - 1;
+
+ if (a < 0)
+ a = 0;
+
+ if (l < 0)
+ l = 0;
+
+ if (a > l)
+ a = l;
+
+ return a;
+ },
+
+ set _actual_city(a) {
+ if (!this._settings)
+ this.loadConfig();
+ var cities = this._cities.split(" && ");
+
+ if (typeof cities != "object")
+ cities = [cities];
+
+ var l = cities.length - 1;
+
+ if (a < 0)
+ a = 0;
+
+ if (l < 0)
+ l = 0;
+
+ if (a > l)
+ a = l;
+
+ this._settings.set_int(WEATHER_ACTUAL_CITY_KEY, a);
+ },
+
+ get _city() {
+ let cities = this._cities;
+ let cities = cities.split(" && ");
+ if (cities && typeof cities == "string")
+ cities = [cities];
+ if (!cities[0])
+ return "";
+ cities = cities[this._actual_city];
+ return cities;
+ },
+
+ set _city(v) {
+ let cities = this._cities;
+ cities = cities.split(" && ");
+ if (cities && typeof cities == "string")
+ cities = [cities];
+ if (!cities[0])
+ cities = [];
+ cities.splice(this.actual_city, 1, v);
+ cities = cities.join(" && ");
+ if (typeof cities != "string")
+ cities = cities[0];
+ this._cities = cities;
+ },
+
+ get _translate_condition() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_TRANSLATE_CONDITION_KEY);
+ },
+
+ set _translate_condition(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_boolean(WEATHER_TRANSLATE_CONDITION_KEY, v);
+ },
+
+ get _icon_type() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_USE_SYMBOLIC_ICONS_KEY) ? 1 : 0;
+ },
+
+ set _icon_type(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_boolean(WEATHER_USE_SYMBOLIC_ICONS_KEY, v);
+ },
+
+ get _use_text_on_buttons() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_USE_TEXT_ON_BUTTONS_KEY) ? 1 : 0;
+ },
+
+ set _use_text_on_buttons(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_boolean(WEATHER_USE_TEXT_ON_BUTTONS_KEY, v);
+ },
+
+ get _text_in_panel() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_SHOW_TEXT_IN_PANEL_KEY);
+ },
+
+ set _text_in_panel(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_boolean(WEATHER_SHOW_TEXT_IN_PANEL_KEY, v);
+ },
+
+ get _position_in_panel() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_enum(WEATHER_POSITION_IN_PANEL_KEY);
+ },
+
+ set _position_in_panel(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_enum(WEATHER_POSITION_IN_PANEL_KEY, v);
+ },
+
+ get _comment_in_panel() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_SHOW_COMMENT_IN_PANEL_KEY);
+ },
+
+ set _comment_in_panel(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_boolean(WEATHER_SHOW_COMMENT_IN_PANEL_KEY, v);
+ },
+
+ get _refresh_interval_current() {
+ if (!this._settings)
+ this.loadConfig();
+ let v = this._settings.get_int(WEATHER_REFRESH_INTERVAL_CURRENT);
+ return ((v >= 600) ? v : 600);
+ },
+
+ set _refresh_interval_current(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_int(WEATHER_REFRESH_INTERVAL_CURRENT, ((v >= 600) ? v : 600));
+ },
+
+ get _refresh_interval_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ let v = this._settings.get_int(WEATHER_REFRESH_INTERVAL_FORECAST);
+ return ((v >= 600) ? v : 600);
+ },
+
+ set _refresh_interval_forecast(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_int(WEATHER_REFRESH_INTERVAL_FORECAST, ((v >= 600) ? v : 600));
+ },
+
+ get _center_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_boolean(WEATHER_CENTER_FORECAST_KEY);
+ },
+
+ set _center_forecast(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_boolean(WEATHER_CENTER_FORECAST_KEY, v);
+ },
+
+ get _days_forecast() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_int(WEATHER_DAYS_FORECAST);
+ },
+
+ set _days_forecast(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_int(WEATHER_DAYS_FORECAST, v);
+ },
+
+ get _decimal_places() {
+ if (!this._settings)
+ this.loadConfig();
+ return this._settings.get_int(WEATHER_DECIMAL_PLACES);
+ },
+
+ set _decimal_places(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_int(WEATHER_DECIMAL_PLACES, v);
+ },
+
+ get _appid() {
+ if (!this._settings)
+ this.loadConfig();
+ let key = this._settings.get_string(WEATHER_OWM_API_KEY);
+ return (key.length == 32) ? key : '';
+ },
+
+ set _appid(v) {
+ if (!this._settings)
+ this.loadConfig();
+ this._settings.set_string(WEATHER_OWM_API_KEY, v);
+ },
+
+ createButton: function(iconName, accessibleName) {
+ let button;
+
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION)) {
+ button = new St.Button({
+ reactive: true,
+ can_focus: true,
+ track_hover: true,
+ accessible_name: accessibleName,
+ style_class: 'popup-menu-item openweather-button'
+ });
+ button.child = new St.Icon({
+ icon_name: iconName
+ });
+ button.connect('notify::hover', Lang.bind(this, this._onButtonHoverChanged));
+ } else
+ button = Main.panel.statusArea.aggregateMenu._system._createActionButton(iconName, accessibleName);
+
+ return button;
+ },
+
+ _onButtonHoverChanged: function(actor, event) {
+ if (actor.hover) {
+ actor.add_style_pseudo_class('hover');
+ actor.set_style(this._button_background_style);
+ } else {
+ actor.remove_style_pseudo_class('hover');
+ actor.set_style('background-color:;');
+ if (actor != this._urlButton)
+ actor.set_style(this._button_border_style);
+ }
+ },
+
+ _updateButtonColors: function() {
+ if (!this._needsColorUpdate)
+ return;
+ this._needsColorUpdate = false;
+ let color;
+ if (ExtensionUtils.versionCheck(['3.6'], Config.PACKAGE_VERSION))
+ color = this._separatorItem._drawingArea.get_theme_node().get_color('-gradient-end');
+ else
+ color = this._separatorItem._separator.actor.get_theme_node().get_color('-gradient-end');
+
+ let alpha = (Math.round(color.alpha / 2.55) / 100);
+
+ if (color.red > 0 && color.green > 0 && color.blue > 0)
+ this._button_border_style = 'border:1px solid rgb(' + Math.round(alpha * color.red) + ',' + Math.round(alpha * color.green) + ',' + Math.round(alpha * color.blue) + ');';
+ else
+ this._button_border_style = 'border:1px solid rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + alpha + ');';
+
+ this._locationButton.set_style(this._button_border_style);
+ this._reloadButton.set_style(this._button_border_style);
+ this._prefsButton.set_style(this._button_border_style);
+
+ this._buttonMenu.actor.add_style_pseudo_class('active');
+ color = this._buttonMenu.actor.get_theme_node().get_background_color();
+ this._button_background_style = 'background-color:rgba(' + color.red + ',' + color.green + ',' + color.blue + ',' + (Math.round(color.alpha / 2.55) / 100) + ');';
+ this._buttonMenu.actor.remove_style_pseudo_class('active');
+ },
+
+ rebuildButtonMenu: function() {
+ if (this._buttonBox) {
+ if (this._buttonBox1) {
+ this._buttonBox1.destroy();
+ this._buttonBox1 = undefined;
+
+ }
+ if (this._buttonBox2) {
+ this._buttonBox2.destroy();
+ this._buttonBox2 = undefined;
+ }
+ this._buttonMenu.removeActor(this._buttonBox);
+ this._buttonBox.destroy();
+ this._buttonBox = undefined;
+ }
+
+ if (this._buttonBox1) {
+ this._buttonBox1.destroy();
+ this._buttonBox1 = undefined;
+ }
+ if (this._buttonBox2) {
+ this._buttonBox2.destroy();
+ this._buttonBox2 = undefined;
+ }
+
+ this._locationButton = this.createButton('find-location-symbolic', _("Locations"));
+ if (this._use_text_on_buttons)
+ this._locationButton.set_label(this._locationButton.get_accessible_name());
+
+ this._locationButton.connect('clicked', Lang.bind(this, function() {
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION))
+ this._selectCity.menu.toggle();
+ else
+ this._selectCity._setOpenState(!this._selectCity._getOpenState());
+ }));
+ this._buttonBox1 = new St.BoxLayout({
+ style_class: 'openweather-button-box'
+ });
+ this._buttonBox1.add_actor(this._locationButton);
+
+ this._reloadButton = this.createButton('view-refresh-symbolic', _("Reload Weather Information"));
+ if (this._use_text_on_buttons)
+ this._reloadButton.set_label(this._reloadButton.get_accessible_name());
+ this._reloadButton.connect('clicked', Lang.bind(this, function() {
+ this.currentWeatherCache = undefined;
+ this.forecastWeatherCache = undefined;
+ this.parseWeatherCurrent();
+ this.recalcLayout();
+ }));
+ this._buttonBox1.add_actor(this._reloadButton);
+
+
+ this._buttonBox2 = new St.BoxLayout({
+ style_class: 'openweather-button-box'
+ });
+
+ this._urlButton = new St.Button({
+ label: _("Weather data provided by:") + (this._use_text_on_buttons ? "\n" : " ") + WEATHER_URL_BASE,
+ style_class: 'system-menu-action openweather-provider'
+ });
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION)) {
+ this._urlButton.connect('notify::hover', Lang.bind(this, this._onButtonHoverChanged));
+ }
+ this._urlButton.connect('clicked', Lang.bind(this, function() {
+ this.menu.actor.hide();
+ let title = ;
+ Main.notifyError(_("Not implemented"),
+ _("Opening the website of the weatherprovider is not (yet) implemeted !"));
+ }));
+
+ this._buttonBox2.add_actor(this._urlButton);
+
+
+ this._prefsButton = this.createButton('preferences-system-symbolic', _("Weather Settings"));
+ if (this._use_text_on_buttons)
+ this._prefsButton.set_label(this._prefsButton.get_accessible_name());
+ this._prefsButton.connect('clicked', Lang.bind(this, this._onPreferencesActivate));
+ this._buttonBox2.add_actor(this._prefsButton);
+
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION)) {
+ this._buttonBox = new St.BoxLayout();
+ this._buttonBox1.add_style_class_name('openweather-button-box-38');
+ this._buttonBox2.add_style_class_name('openweather-button-box-38');
+ this._buttonBox.add_actor(this._buttonBox1);
+ this._buttonBox.add_actor(this._buttonBox2);
+
+ this._buttonMenu.addActor(this._buttonBox);
+ this._needsColorUpdate = true;
+ } else {
+ this._buttonMenu.actor.add_actor(this._buttonBox1);
+ this._buttonMenu.actor.add_actor(this._buttonBox2);
+ }
+ this._buttonBox1MinWidth = undefined;
+ },
+ rebuildSelectCityItem: function() {
+ this._selectCity.menu.removeAll();
+ let item = null;
+
+ let cities = this._cities;
+ cities = cities.split(" && ");
+ if (cities && typeof cities == "string")
+ cities = [cities];
+ if (!cities[0])
+ return;
+
+ for (let i = 0; cities.length > i; i++) {
+ item = new PopupMenu.PopupMenuItem(this.extractLocation(cities[i]));
+ item.location = i;
+ if (i == this._actual_city) {
+ if (ExtensionUtils.versionCheck(['3.6', '3.8'], Config.PACKAGE_VERSION))
+ item.setShowDot(true);
+ else
+ item.setOrnament(PopupMenu.Ornament.DOT);
+ }
+
+ this._selectCity.menu.addMenuItem(item);
+ // override the items default onActivate-handler, to keep the ui open while chosing the location
+ item.activate = this._onActivate;
+ }
+
+ if (cities.length == 1)
+ this._selectCity.actor.hide();
+ else
+ this._selectCity.actor.show();
+
+ },
+
+ _onActivate: function() {
+ openweatherMenu._actual_city = this.location;
+ },
+
+ extractLocation: function() {
+ if (!arguments[0])
+ return "";
+
+ if (arguments[0].search(">") == -1)
+ return _("Invalid city");
+ return arguments[0].split(">")[1];
+ },
+
+ extractCity: function() {
+ if (!arguments[0])
+ return "";
+ let city = this.extractLocation(arguments[0]);
+ if (city.indexOf("(") == -1)
+ return _("Invalid city");
+ return city.split("(")[0].trim();
+ },
+
+ extractId: function() {
+ if (!arguments[0])
+ return 0;
+
+ if (arguments[0].search(">") == -1)
+ return 0;
+ return arguments[0].split(">")[0];
+ },
+
+ updateCities: function() {
+ let cities = this._cities;
+
+ cities = cities.split(" && ");
+ if (cities && typeof cities == "string")
+ cities = [cities];
+ if (!cities[0])
+ cities = [];
+
+ if (cities.length === 0) {
+ this._cities = "2516479>Eivissa (CA)";
+ this.updateCities();
+ return;
+ }
+
+ for (let a in cities) {
+ if (!this.extractCity(cities[a])) {
+ let params = {
+ q: cities[a],
+ type: 'like'
+ };
+ if (this._appid)
+ params.APPID = this._appid;
+
+ this.load_json_async(WEATHER_URL_CURRENT, params, Lang.bind(this, this._updateCitiesCallback));
+ return;
+ } else
+ continue;
+ }
+ },
+
+ _updateCitiesCallback: function() {
+ let city = arguments[0];
+
+ if (Number(city.cod) != 200)
+ return;
+
+ let cityText = city.coord + ">" + city.name;
+
+ if (city.sys)
+ cityText += " (" + city.sys.country + ")";
+
+ cities.splice(a, 1, cityText);
+
+ cities = cities.join(" && ");
+ if (typeof cities != "string")
+ cities = cities[0];
+ this._cities = cities;
+// this.updateCities();
+ },
+
+ _onPreferencesActivate: function() {
+ this.menu.actor.hide();
+ Util.spawn(["gnome-shell-extension-prefs", "openweather-extension@jenslody.de"]);
+ return 0;
+ },
+
+ recalcLayout: function() {
+ if (!this.menu.isOpen)
+ return;
+ this._updateButtonColors();
+ if(this._buttonBox1MinWidth === undefined)
+ this._buttonBox1MinWidth = this._buttonBox1.get_width();
+ this._buttonBox1.set_width(Math.max(this._buttonBox1MinWidth, this._currentWeather.get_width() - this._buttonBox2.get_width()));
+ if (this._forecastScrollBox !== undefined && this._forecastBox !== undefined && this._currentWeather !== undefined) {
+ this._forecastScrollBox.set_width(Math.max(this._currentWeather.get_width(), (this._buttonBox1.get_width() + this._buttonBox2.get_width())));
+ this._forecastScrollBox.show();
+ if (this._forecastBox.get_preferred_width(this._forecastBox.get_height())[0] > this._currentWeather.get_width()) {
+ this._forecastScrollBox.hscroll.margin_top = 10;
+ this._forecastScrollBox.hscroll.show();
+ } else {
+ this._forecastScrollBox.hscroll.margin_top = 0;
+ this._forecastScrollBox.hscroll.hide();
+ }
+ }
+ },
+
+ unit_to_unicode: function() {
+ if (this._units == WeatherUnits.FAHRENHEIT)
+ return '\u00B0F';
+ else if (this._units == WeatherUnits.KELVIN)
+ return 'K';
+ else if (this._units == WeatherUnits.RANKINE)
+ return '\u00B0Ra';
+ else if (this._units == WeatherUnits.REAUMUR)
+ return '\u00B0R\u00E9';
+ else if (this._units == WeatherUnits.ROEMER)
+ return '\u00B0R\u00F8';
+ else if (this._units == WeatherUnits.DELISLE)
+ return '\u00B0De';
+ else if (this._units == WeatherUnits.NEWTON)
+ return '\u00B0N';
+ else
+ return '\u00B0C';
+ },
+
+ get_weather_icon: function(code) {
+ // see http://bugs.openweathermap.org/projects/api/wiki/Weather_Condition_Codes
+ // fallback icons are: weather-clear-night weather-clear weather-few-clouds-night weather-few-clouds weather-fog weather-overcast weather-severe-alert weather-showers weather-showers-scattered weather-snow weather-storm
+ /*
+weather-clouds-night.png
+weather-freezing-rain.png
+weather-hail.png
+weather-many-clouds.png
+weather-showers-day.png
+weather-showers-night.png
+weather-showers-scattered-day.png
+weather-showers-scattered-night.png
+weather-snow-rain.png
+weather-snow-scattered-day.png
+weather-snow-scattered-night.png
+weather-snow-scattered.png
+weather-storm-day.png
+weather-storm-night.png
+
+weather-severe-alert-symbolic.svg
+
+
+weather-clear-night.png = weather-clear-night-symbolic.svg
+weather-clear.png = weather-clear-symbolic.svg
+weather-clouds.png = weather-overcast-symbolic.svg
+weather-few-clouds-night.png = weather-few-clouds-night-symbolic.svg
+weather-few-clouds.png = weather-few-clouds-symbolic.svg
+weather-mist.png = weather-fog-symbolic.svg
+weather-showers-scattered.png = weather-showers-scattered-symbolic.svg
+weather-showers.png = weather-showers-symbolic.svg
+weather-snow.png = weather-snow-symbolic.svg
+weather-storm.png = weather-storm-symbolic.svg
+
+*/
+ switch (parseInt(code, 10)) {
+ case 200: //thunderstorm with light rain
+ case 201: //thunderstorm with rain
+ case 202: //thunderstorm with heavy rain
+ case 210: //light thunderstorm
+ case 211: //thunderstorm
+ case 212: //heavy thunderstorm
+ case 221: //ragged thunderstorm
+ case 230: //thunderstorm with light drizzle
+ case 231: //thunderstorm with drizzle
+ case 232: //thunderstorm with heavy drizzle
+ return ['weather-storm'];
+ case 300: //light intensity drizzle
+ case 301: //drizzle
+ case 302: //heavy intensity drizzle
+ case 310: //light intensity drizzle rain
+ case 311: //drizzle rain
+ case 312: //heavy intensity drizzle rain
+ case 313: //shower rain and drizzle
+ case 314: //heavy shower rain and drizzle
+ case 321: //shower drizzle
+ return ['weather-showers'];
+ case 500: //light rain
+ case 501: //moderate rain
+ case 502: //heavy intensity rain
+ case 503: //very heavy rain
+ case 504: //extreme rain
+ return ['weather-showers-scattered', 'weather-showers'];
+ case 511: //freezing rain
+ return ['weather-freezing-rain', 'weather-showers'];
+ case 520: //light intensity shower rain
+ case 521: //shower rain
+ case 522: //heavy intensity shower rain
+ case 531: //ragged shower rain
+ return ['weather-showers'];
+ case 600: //light snow
+ case 601: //snow
+ case 602: //heavy snow
+ case 611: //sleet
+ case 612: //shower sleet
+ case 615: //light rain and snow
+ case 616: //rain and snow
+ case 620: //light shower snow
+ case 621: //shower snow
+ case 622: //heavy shower snow
+ return ['weather-snow'];
+ case 701: //mist
+ case 711: //smoke
+ case 721: //haze
+ case 741: //Fog
+ return ['weather-fog'];
+ case 731: //Sand/Dust Whirls
+ case 751: //sand
+ case 761: //dust
+ case 762: //VOLCANIC ASH
+ case 771: //SQUALLS
+ case 781: //TORNADO
+ return ['weather-severe-alert'];
+ case 800: //sky is clear
+ return ['weather-clear'];
+ case 801: //few clouds
+ case 802: //scattered clouds
+ return ['weather-few-clouds'];
+ case 803: //broken clouds
+ return ['weather-many-clouds', 'weather-overcast'];
+ case 804: //overcast clouds
+ return ['weather-overcast'];
+ default:
+ return ['weather-severe-alert'];
+ }
+ },
+
+ get_weather_icon_safely: function(code, night) {
+ let iconname = this.get_weather_icon(code);
+ for (let i = 0; i < iconname.length; i++) {
+ if (night && this.has_icon(iconname[i] + '-night'))
+ return iconname[i] + '-night' + this.icon_type();
+ if (this.has_icon(iconname[i]))
+ return iconname[i] + this.icon_type();
+ }
+ return 'weather-severe-alert' + this.icon_type();
+ },
+
+ has_icon: function(icon) {
+ return Gtk.IconTheme.get_default().has_icon(icon + this.icon_type());
+ },
+
+ get_weather_condition: function(code) {
+ switch (parseInt(code, 10)) {
+ case 200: //thunderstorm with light rain
+ return _('thunderstorm with light rain');
+ case 201: //thunderstorm with rain
+ return _('thunderstorm with rain');
+ case 202: //thunderstorm with heavy rain
+ return _('thunderstorm with heavy rain');
+ case 210: //light thunderstorm
+ return _('light thunderstorm');
+ case 211: //thunderstorm
+ return _('thunderstorm');
+ case 212: //heavy thunderstorm
+ return _('heavy thunderstorm');
+ case 221: //ragged thunderstorm
+ return _('ragged thunderstorm');
+ case 230: //thunderstorm with light drizzle
+ return _('thunderstorm with light drizzle');
+ case 231: //thunderstorm with drizzle
+ return _('thunderstorm with drizzle');
+ case 232: //thunderstorm with heavy drizzle
+ return _('thunderstorm with heavy drizzle');
+ case 300: //light intensity drizzle
+ return _('light intensity drizzle');
+ case 301: //drizzle
+ return _('drizzle');
+ case 302: //heavy intensity drizzle
+ return _('heavy intensity drizzle');
+ case 310: //light intensity drizzle rain
+ return _('light intensity drizzle rain');
+ case 311: //drizzle rain
+ return _('drizzle rain');
+ case 312: //heavy intensity drizzle rain
+ return _('heavy intensity drizzle rain');
+ case 313: //shower rain and drizzle
+ return _('shower rain and drizzle');
+ case 314: //heavy shower rain and drizzle
+ return _('heavy shower rain and drizzle');
+ case 321: //shower drizzle
+ return _('shower drizzle');
+ case 500: //light rain
+ return _('light rain');
+ case 501: //moderate rain
+ return _('moderate rain');
+ case 502: //heavy intensity rain
+ return _('heavy intensity rain');
+ case 503: //very heavy rain
+ return _('very heavy rain');
+ case 504: //extreme rain
+ return _('extreme rain');
+ case 511: //freezing rain
+ return _('freezing rain');
+ case 520: //light intensity shower rain
+ return _('light intensity shower rain');
+ case 521: //shower rain
+ return _('shower rain');
+ case 522: //heavy intensity shower rain
+ return _('heavy intensity shower rain');
+ case 531: //ragged shower rain
+ return _('ragged shower rain');
+ case 600: //light snow
+ return _('light snow');
+ case 601: //snow
+ return _('snow');
+ case 602: //heavy snow
+ return _('heavy snow');
+ case 611: //sleet
+ return _('sleet');
+ case 612: //shower sleet
+ return _('shower sleet');
+ case 615: //light rain and snow
+ return _('light rain and snow');
+ case 616: //rain and snow
+ return _('rain and snow');
+ case 620: //light shower snow
+ return _('light shower snow');
+ case 621: //shower snow
+ return _('shower snow');
+ case 622: //heavy shower snow
+ return _('heavy shower snow');
+ case 701: //mist
+ return _('mist');
+ case 711: //smoke
+ return _('smoke');
+ case 721: //haze
+ return _('haze');
+ case 731: //Sand/Dust Whirls
+ return _('Sand/Dust Whirls');
+ case 741: //Fog
+ return _('Fog');
+ case 751: //sand
+ return _('sand');
+ case 761: //dust
+ return _('dust');
+ case 762: //VOLCANIC ASH
+ return _('VOLCANIC ASH');
+ case 771: //SQUALLS
+ return _('SQUALLS');
+ case 781: //TORNADO
+ return _('TORNADO');
+ case 800: //sky is clear
+ return _('sky is clear');
+ case 801: //few clouds
+ return _('few clouds');
+ case 802: //scattered clouds
+ return _('scattered clouds');
+ case 803: //broken clouds
+ return _('broken clouds');
+ case 804: //overcast clouds
+ return _('overcast clouds');
+ default:
+ return _('Not available');
+ }
+ },
+
+ toFahrenheit: function(t) {
+ return ((Number(t) * 1.8) + 32).toFixed(this._decimal_places);
+ },
+
+ toKelvin: function(t) {
+ return (Number(t) + 273.15).toFixed(this._decimal_places);
+ },
+
+ toRankine: function(t) {
+ return ((Number(t) * 1.8) + 491.67).toFixed(this._decimal_places);
+ },
+
+ toReaumur: function(t) {
+ return (Number(t) * 0.8).toFixed(this._decimal_places);
+ },
+
+ toRoemer: function(t) {
+ return ((Number(t) * 21 / 40) + 7.5).toFixed(this._decimal_places);
+ },
+
+ toDelisle: function(t) {
+ return ((100 - Number(t)) * 1.5).toFixed(this._decimal_places);
+ },
+
+ toNewton: function(t) {
+ return (Number(t) - 0.33).toFixed(this._decimal_places);
+ },
+
+ toInHg: function(p /*, t*/ ) {
+ return (p / 33.86530749).toFixed(this._decimal_places);
+ },
+
+ toBeaufort: function(w, t) {
+ if (w < 0.3)
+ return (!t) ? "0" : "(" + _("Calm") + ")";
+
+ else if (w >= 0.3 && w <= 1.5)
+ return (!t) ? "1" : "(" + _("Light air") + ")";
+
+ else if (w > 1.5 && w <= 3.4)
+ return (!t) ? "2" : "(" + _("Light breeze") + ")";
+
+ else if (w > 3.4 && w <= 5.4)
+ return (!t) ? "3" : "(" + _("Gentle breeze") + ")";
+
+ else if (w > 5, 4 && w <= 7.9)
+ return (!t) ? "4" : "(" + _("Moderate breeze") + ")";
+
+ else if (w > 7.9 && w <= 10.7)
+ return (!t) ? "5" : "(" + _("Fresh breeze") + ")";
+
+ else if (w > 10.7 && w <= 13.8)
+ return (!t) ? "6" : "(" + _("Strong breeze") + ")";
+
+ else if (w > 13.8 && w <= 17.1)
+ return (!t) ? "7" : "(" + _("Moderate gale") + ")";
+
+ else if (w > 17.1 && w <= 20.7)
+ return (!t) ? "8" : "(" + _("Fresh gale") + ")";
+
+ else if (w > 20.7 && w <= 24.4)
+ return (!t) ? "9" : "(" + _("Strong gale") + ")";
+
+ else if (w > 24.4 && w <= 28.4)
+ return (!t) ? "10" : "(" + _("Storm") + ")";
+
+ else if (w > 28.4 && w <= 32.6)
+ return (!t) ? "11" : "(" + _("Violent storm") + ")";
+
+ else
+ return (!t) ? "12" : "(" + _("Hurricane") + ")";
+ },
+
+ get_locale_day: function(abr) {
+ let days = [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')];
+ return days[abr];
+ },
+
+ get_wind_direction: function(deg) {
+ let arrows = ["\u2193", "\u2199", "\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198"];
+ let letters = [_('N'), _('NE'), _('E'), _('SE'), _('S'), _('SW'), _('W'), _('NW')];
+ let idx = Math.round(deg / 45) % arrows.length;
+ return (this._wind_direction) ? arrows[idx] : letters[idx];
+ },
+
+ icon_type: function(icon_name) {
+ if (!icon_name)
+ if (this._icon_type)
+ return "-symbolic";
+ else
+ return "";
+
+ if (this._icon_type)
+ if (String(icon_name).search("-symbolic") != -1)
+ return icon_name;
+ else
+ return icon_name + "-symbolic";
+ else
+ if (String(icon_name).search("-symbolic") != -1)
+ return String(icon_name).replace("-symbolic", "");
+ else
+ return icon_name;
+ },
+
+ load_json_async: function(url, params, fun) {
+ if (_httpSession === undefined) {
+ if (ExtensionUtils.versionCheck(['3.6'], Config.PACKAGE_VERSION)) {
+ // Soup session (see https://bugzilla.gnome.org/show_bug.cgi?id=661323#c64) (Simon Legner)
+ _httpSession = new Soup.SessionAsync();
+ Soup.Session.prototype.add_feature.call(_httpSession, new Soup.ProxyResolverDefault());
+ } else
+ _httpSession = new Soup.Session();
+ }
+
+ let message = Soup.form_request_new_from_hash('GET', url, params);
+
+ _httpSession.queue_message(message, Lang.bind(this, function(_httpSession, message) {
+
+ try {
+ if (!message.response_body.data) {
+ fun.call(this, 0);
+ return;
+ }
+ let jp = JSON.parse(message.response_body.data);
+ fun.call(this, jp);
+ } catch (e) {
+ fun.call(this, 0);
+ return;
+ }
+ }));
+ return;
+ },
+
+ parseWeatherCurrent: function() {
+ if (this.currentWeatherCache === undefined) {
+ this.refreshWeatherCurrent();
+ return;
+ }
+
+ if (this._old_position_in_panel != this._position_in_panel) {
+ switch (this._old_position_in_panel) {
+ case WeatherPosition.LEFT:
+ Main.panel._leftBox.remove_actor(this.actor);
+ break;
+ case WeatherPosition.CENTER:
+ Main.panel._centerBox.remove_actor(this.actor);
+ break;
+ case WeatherPosition.RIGHT:
+ Main.panel._rightBox.remove_actor(this.actor);
+ break;
+ }
+
+ let children = null;
+ switch (this._position_in_panel) {
+ case WeatherPosition.LEFT:
+ children = Main.panel._leftBox.get_children();
+ Main.panel._leftBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.CENTER:
+ children = Main.panel._centerBox.get_children();
+ Main.panel._centerBox.insert_child_at_index(this.actor, children.length);
+ break;
+ case WeatherPosition.RIGHT:
+ children = Main.panel._rightBox.get_children();
+ Main.panel._rightBox.insert_child_at_index(this.actor, 0);
+ break;
+ }
+ this._old_position_in_panel = this._position_in_panel;
+ }
+
+ let json = this.currentWeatherCache;
+ // Refresh current weather
+ let location = this.extractLocation(this._city);
+
+ let comment = json.weather[0].description;
+ if (this._translate_condition)
+ comment = this.get_weather_condition(json.weather[0].id);
+
+ let temperature = json.main.temp;
+ let cloudiness = json.clouds.all;
+ let humidity = json.main.humidity + ' %';
+ let pressure = json.main.pressure;
+ let pressure_unit = 'hPa';
+
+ let wind_direction = this.get_wind_direction(json.wind.deg);
+ let wind = json.wind.speed;
+ let wind_unit = 'm/s';
+
+ let sunrise = new Date(json.sys.sunrise * 1000);
+ let sunset = new Date(json.sys.sunset * 1000);
+ let now = new Date();
+
+ let iconname = this.get_weather_icon_safely(json.weather[0].id, now < sunrise || now > sunset);
+
+ if (this.lastBuildId === undefined)
+ this.lastBuildId = 0;
+
+ if (this.lastBuildDate === undefined)
+ this.lastBuildDate = 0;
+
+ if (this.lastBuildId != json.dt || !this.lastBuildDate) {
+ this.lastBuildId = json.dt;
+ this.lastBuildDate = new Date(this.lastBuildId * 1000);
+ }
+
+ switch (this._pressure_units) {
+ case WeatherPressureUnits.inHg:
+ pressure = this.toInHg(pressure);
+ pressure_unit = "inHg";
+ break;
+
+ case WeatherPressureUnits.hPa:
+ pressure = pressure.toFixed(this._decimal_places);
+ pressure_unit = "hPa";
+ break;
+
+ case WeatherPressureUnits.bar:
+ pressure = (pressure / 1000).toFixed(this._decimal_places);
+ pressure_unit = "bar";
+ break;
+
+ case WeatherPressureUnits.Pa:
+ pressure = (pressure * 100).toFixed(this._decimal_places);
+ pressure_unit = "Pa";
+ break;
+
+ case WeatherPressureUnits.kPa:
+ pressure = (pressure / 10).toFixed(this._decimal_places);
+ pressure_unit = "kPa";
+ break;
+
+ case WeatherPressureUnits.atm:
+ pressure = (pressure * 0.000986923267).toFixed(this._decimal_places);
+ pressure_unit = "atm";
+ break;
+
+ case WeatherPressureUnits.at:
+ pressure = (pressure * 0.00101971621298).toFixed(this._decimal_places);
+ pressure_unit = "at";
+ break;
+
+ case WeatherPressureUnits.Torr:
+ pressure = (pressure * 0.750061683).toFixed(this._decimal_places);
+ pressure_unit = "Torr";
+ break;
+
+ case WeatherPressureUnits.psi:
+ pressure = (pressure * 0.0145037738).toFixed(this._decimal_places);
+ pressure_unit = "psi";
+ break;
+ }
+
+ switch (this._units) {
+ case WeatherUnits.FAHRENHEIT:
+ temperature = this.toFahrenheit(temperature);
+ break;
+
+ case WeatherUnits.CELSIUS:
+ temperature = temperature.toFixed(this._decimal_places);
+ break;
+
+ case WeatherUnits.KELVIN:
+ temperature = this.toKelvin(temperature);
+ break;
+
+ case WeatherUnits.RANKINE:
+ temperature = this.toRankine(temperature);
+ break;
+
+ case WeatherUnits.REAUMUR:
+ temperature = this.toReaumur(temperature);
+ break;
+
+ case WeatherUnits.ROEMER:
+ temperature = this.toRoemer(temperature);
+ break;
+
+ case WeatherUnits.DELISLE:
+ temperature = this.toDelisle(temperature);
+ break;
+
+ case WeatherUnits.NEWTON:
+ temperature = this.toNewton(temperature);
+ break;
+ }
+
+ let lastBuild = '-';
+
+ if (this._clockFormat == "24h") {
+ sunrise = sunrise.toLocaleFormat("%R");
+ sunset = sunset.toLocaleFormat("%R");
+ lastBuild = this.lastBuildDate.toLocaleFormat("%R");
+ } else {
+ sunrise = sunrise.toLocaleFormat("%I:%M %p");
+ sunset = sunset.toLocaleFormat("%I:%M %p");
+ lastBuild = this.lastBuildDate.toLocaleFormat("%I:%M %p");
+ }
+
+ let beginOfDay = new Date(new Date().setHours(0, 0, 0, 0));
+ let d = Math.floor((this.lastBuildDate.getTime() - beginOfDay.getTime()) / 86400000);
+ if (d < 0) {
+ lastBuild = _("Yesterday");
+ if (d < -1)
+ lastBuild = _("%s days ago").replace("%s", -1 * d);
+ }
+
+ this._currentWeatherIcon.icon_name = this._weatherIcon.icon_name = iconname;
+
+ let weatherInfoC = "";
+ let weatherInfoT = "";
+
+ if (this._comment_in_panel)
+ weatherInfoC = comment;
+
+ if (this._text_in_panel)
+ weatherInfoT = parseFloat(temperature).toLocaleString() + ' ' + this.unit_to_unicode();
+
+ this._weatherInfo.text = weatherInfoC + ((weatherInfoC && weatherInfoT) ? ", " : "") + weatherInfoT;
+
+ this._currentWeatherSummary.text = comment + ", " + parseFloat(temperature).toLocaleString() + ' ' + this.unit_to_unicode();
+ this._currentWeatherLocation.text = location;
+ this._currentWeatherTemperature.text = cloudiness + ' %';
+ this._currentWeatherHumidity.text = parseFloat(humidity).toLocaleString() + ' %';
+ this._currentWeatherPressure.text = parseFloat(pressure).toLocaleString() + ' ' + pressure_unit;
+ this._currentWeatherSunrise.text = sunrise;
+ this._currentWeatherSunset.text = sunset;
+ this._currentWeatherBuild.text = lastBuild;
+
+ // Override wind units with our preference
+ switch (this._wind_speed_units) {
+ case WeatherWindSpeedUnits.MPH:
+ wind = (wind * WEATHER_CONV_MPS_IN_MPH).toFixed(this._decimal_places);
+ wind_unit = 'mph';
+ break;
+
+ case WeatherWindSpeedUnits.KPH:
+ wind = (wind * WEATHER_CONV_MPS_IN_KPH).toFixed(this._decimal_places);
+ wind_unit = 'km/h';
+ break;
+
+ case WeatherWindSpeedUnits.MPS:
+ wind = wind.toFixed(this._decimal_places);
+ break;
+
+ case WeatherWindSpeedUnits.KNOTS:
+ wind = (wind * WEATHER_CONV_MPS_IN_KNOTS).toFixed(this._decimal_places);
+ wind_unit = 'kn';
+ break;
+
+ case WeatherWindSpeedUnits.FPS:
+ wind = (wind * WEATHER_CONV_MPS_IN_FPS).toFixed(this._decimal_places);
+ wind_unit = 'ft/s';
+ break;
+
+ case WeatherWindSpeedUnits.BEAUFORT:
+ wind_unit = this.toBeaufort(wind, true);
+ wind = this.toBeaufort(wind);
+ }
+
+ if (!wind)
+ this._currentWeatherWind.text = '\u2013';
+ else if (wind === 0 || !wind_direction)
+ this._currentWeatherWind.text = parseFloat(wind).toLocaleString() + ' ' + wind_unit;
+ else // i.e. wind > 0 && wind_direction
+ this._currentWeatherWind.text = wind_direction + ' ' + parseFloat(wind).toLocaleString() + ' ' + wind_unit;
+
+ this.parseWeatherForecast();
+ this.recalcLayout();
+ },
+
+ refreshWeatherCurrent: function() {
+ if (!this.extractId(this._city)) {
+ this.updateCities();
+ return;
+ }
+ this.oldLocation = this.extractId(this._city);
+
+ let params = {
+ id: this.oldLocation,
+ units: 'metric'
+ };
+ if (this._appid)
+ params.APPID = this._appid;
+
+ this.load_json_async(WEATHER_URL_CURRENT, params, function(json) {
+ if (json && (Number(json.cod) == 200)) {
+
+ if (this.currentWeatherCache != json)
+ this.currentWeatherCache = json;
+
+ this.rebuildSelectCityItem();
+
+ this.parseWeatherCurrent();
+ } else {
+ // we are connected, but get no (or no correct) data, so invalidate
+ // the shown data and reload after 10 minutes (recommendded by openweathermap.org)
+ this.rebuildCurrentWeatherUi();
+ this.reloadWeatherCurrent(600);
+ }
+ });
+ this.reloadWeatherCurrent(this._refresh_interval_current);
+ },
+
+ reloadWeatherCurrent: function(interval) {
+ if (this._timeoutCurrent) {
+ Mainloop.source_remove(this._timeoutCurrent);
+ }
+ this._timeoutCurrent = Mainloop.timeout_add_seconds(interval, Lang.bind(this, function() {
+ this.currentWeatherCache = undefined;
+ if (this._connected)
+ this.parseWeatherCurrent();
+ else
+ this.rebuildCurrentWeatherUi();
+ return true;
+ }));
+ },
+
+ parseWeatherForecast: function() {
+ if (this.forecastWeatherCache === undefined) {
+ this.refreshWeatherForecast();
+ return;
+ }
+
+ let forecast = this.forecastWeatherCache;
+ let beginOfDay = new Date(new Date().setHours(0, 0, 0, 0));
+
+ // Refresh forecast
+ for (let i = 0; i < this._days_forecast; i++) {
+ let forecastUi = this._forecast[i];
+ let forecastData = forecast[i];
+ if (forecastData === undefined)
+ continue;
+
+ let t_low = forecastData.temp.min;
+ let t_high = forecastData.temp.max;
+
+ switch (this._units) {
+ case WeatherUnits.FAHRENHEIT:
+ t_low = this.toFahrenheit(t_low);
+ t_high = this.toFahrenheit(t_high);
+ break;
+
+ case WeatherUnits.CELSIUS:
+ t_low = t_low.toFixed(this._decimal_places);
+ t_high = t_high.toFixed(this._decimal_places);
+ break;
+
+ case WeatherUnits.KELVIN:
+ t_low = this.toKelvin(t_low);
+ t_high = this.toKelvin(t_high);
+ break;
+
+ case WeatherUnits.RANKINE:
+ t_low = this.toRankine(t_low);
+ t_high = this.toRankine(t_high);
+ break;
+
+ case WeatherUnits.REAUMUR:
+ t_low = this.toReaumur(t_low);
+ t_high = this.toReaumur(t_high);
+ break;
+
+ case WeatherUnits.ROEMER:
+ t_low = this.toRoemer(t_low);
+ t_high = this.toRoemer(t_high);
+ break;
+
+ case WeatherUnits.DELISLE:
+ t_low = this.toDelisle(t_low);
+ t_high = this.toDelisle(t_high);
+ break;
+
+ case WeatherUnits.NEWTON:
+ t_low = this.toNewton(t_low);
+ t_high = this.toNewton(t_high);
+ break;
+ }
+
+ let comment = forecastData.weather[0].description;
+ if (this._translate_condition)
+ comment = this.get_weather_condition(forecastData.weather[0].id);
+
+ let forecastDate = new Date(forecastData.dt * 1000);
+ let dayLeft = Math.floor((forecastDate.getTime() - beginOfDay.getTime()) / 86400000);
+
+ let date_string = _("Today");
+ if (dayLeft == 1)
+ date_string = _("Tomorrow");
+ else if (dayLeft > 1)
+ date_string = _("In %s days").replace("%s", dayLeft);
+ else if (dayLeft == -1)
+ date_string = _("Yesterday");
+ else if (dayLeft < -1)
+ date_string = _("%s days ago").replace("%s", -1 * dayLeft);
+
+ forecastUi.Day.text = date_string + ' (' + this.get_locale_day(forecastDate.getDay()) + ')\n' + forecastDate.toLocaleDateString();
+ forecastUi.Temperature.text = '\u2193 ' + parseFloat(t_low).toLocaleString() + ' ' + this.unit_to_unicode() + ' \u2191 ' + parseFloat(t_high).toLocaleString() + ' ' + this.unit_to_unicode();
+ forecastUi.Summary.text = comment;
+ forecastUi.Icon.icon_name = this.get_weather_icon_safely(forecastData.weather[0].id);
+ }
+ },
+
+ refreshWeatherForecast: function() {
+
+ if (!this.extractId(this._city)) {
+ this.updateCities();
+ return;
+ }
+
+ this.oldLocation = this.extractId(this._city);
+
+ let params = {
+ id: this.oldLocation,
+ units: 'metric',
+ cnt: '13'
+ };
+ if (this._appid)
+ params.APPID = this._appid;
+
+ this.load_json_async(WEATHER_URL_FORECAST, params, function(json) {
+ if (json && (Number(json.cod) == 200)) {
+ if (this.forecastWeatherCache != json.list)
+ this.forecastWeatherCache = json.list;
+
+ this.parseWeatherForecast();
+ } else {
+ // we are connected, but get no (or no correct) data, so invalidate
+ // the shown data and reload after 10 minutes (recommendded by openweathermap.org)
+ this.rebuildFutureWeatherUi();
+ this.reloadWeatherForecast(600);
+ }
+ });
+ this.reloadWeatherForecast(this._refresh_interval_forecast);
+ },
+
+ reloadWeatherForecast: function(interval) {
+ if (this._timeoutForecast) {
+ Mainloop.source_remove(this._timeoutForecast);
+ }
+ this._timeoutForecast = Mainloop.timeout_add_seconds(interval, Lang.bind(this, function() {
+ this.forecastWeatherCache = undefined;
+ if (this._connected)
+ this.parseWeatherForecast();
+ else
+ this.rebuildFutureWeatherUi();
+ return true;
+ }));
+ },
+
+ destroyCurrentWeather: function() {
+ if (this._currentWeather.get_child() !== null)
+ this._currentWeather.get_child().destroy();
+ },
+
+ destroyFutureWeather: function() {
+ if (this._futureWeather.get_child() !== null)
+ this._futureWeather.get_child().destroy();
+ },
+
+ rebuildCurrentWeatherUi: function() {
+ this._weatherInfo.text = _('Loading current weather ...');
+ this._weatherIcon.icon_name = 'view-refresh' + this.icon_type();
+
+ this.destroyCurrentWeather();
+
+ // This will hold the icon for the current weather
+ this._currentWeatherIcon = new St.Icon({
+ icon_size: 72,
+ icon_name: 'view-refresh' + this.icon_type(),
+ style_class: 'openweather-current-icon'
+ });
+
+ this._sunriseIcon = new St.Icon({
+ icon_size: 15,
+ icon_name: 'weather-clear' + this.icon_type(),
+ style_class: 'openweather-sunrise-icon'
+ });
+
+ this._sunsetIcon = new St.Icon({
+ icon_size: 15,
+ icon_name: 'weather-clear-night' + this.icon_type(),
+ style_class: 'openweather-sunset-icon'
+ });
+
+ this._buildIcon = new St.Icon({
+ icon_size: 15,
+ icon_name: 'view-refresh' + this.icon_type(),
+ style_class: 'openweather-build-icon'
+ });
+
+ // The summary of the current weather
+ this._currentWeatherSummary = new St.Label({
+ text: _('Loading ...'),
+ style_class: 'openweather-current-summary'
+ });
+ this._currentWeatherLocation = new St.Label({
+ text: _('Please wait')
+ });
+
+ let bb = new St.BoxLayout({
+ vertical: true,
+ style_class: 'openweather-current-summarybox'
+ });
+ bb.add_actor(this._currentWeatherLocation);
+ bb.add_actor(this._currentWeatherSummary);
+
+ this._currentWeatherSunrise = new St.Label({
+ text: '-'
+ });
+ this._currentWeatherSunset = new St.Label({
+ text: '-'
+ });
+ this._currentWeatherBuild = new St.Label({
+ text: '-'
+ });
+
+ let ab = new St.BoxLayout({
+ style_class: 'openweather-current-infobox'
+ });
+
+ ab.add_actor(this._sunriseIcon);
+ ab.add_actor(this._currentWeatherSunrise);
+ ab.add_actor(this._sunsetIcon);
+ ab.add_actor(this._currentWeatherSunset);
+ ab.add_actor(this._buildIcon);
+ ab.add_actor(this._currentWeatherBuild);
+ bb.add_actor(ab);
+
+ // Other labels
+ this._currentWeatherTemperature = new St.Label({
+ text: '...'
+ });
+ this._currentWeatherHumidity = new St.Label({
+ text: '...'
+ });
+ this._currentWeatherPressure = new St.Label({
+ text: '...'
+ });
+ this._currentWeatherWind = new St.Label({
+ text: '...'
+ });
+
+ let rb = new St.BoxLayout({
+ style_class: 'openweather-current-databox'
+ });
+ let rb_captions = new St.BoxLayout({
+ vertical: true,
+ style_class: 'openweather-current-databox-captions'
+ });
+ let rb_values = new St.BoxLayout({
+ vertical: true,
+ style_class: 'openweather-current-databox-values'
+ });
+ rb.add_actor(rb_captions);
+ rb.add_actor(rb_values);
+
+ rb_captions.add_actor(new St.Label({
+ text: _('Cloudiness:')
+ }));
+ rb_values.add_actor(this._currentWeatherTemperature);
+ rb_captions.add_actor(new St.Label({
+ text: _('Humidity:')
+ }));
+ rb_values.add_actor(this._currentWeatherHumidity);
+ rb_captions.add_actor(new St.Label({
+ text: _('Pressure:')
+ }));
+ rb_values.add_actor(this._currentWeatherPressure);
+ rb_captions.add_actor(new St.Label({
+ text: _('Wind:')
+ }));
+ rb_values.add_actor(this._currentWeatherWind);
+
+ let xb = new St.BoxLayout();
+ xb.add_actor(bb);
+ xb.add_actor(rb);
+
+ let box = new St.BoxLayout({
+ style_class: 'openweather-current-iconbox'
+ });
+ box.add_actor(this._currentWeatherIcon);
+ box.add_actor(xb);
+ this._currentWeather.set_child(box);
+ },
+
+ scrollForecastBy: function(delta) {
+ if (this._forecastScrollBox === undefined)
+ return;
+ this._forecastScrollBox.hscroll.adjustment.value += delta;
+ },
+
+ rebuildFutureWeatherUi: function() {
+ this.destroyFutureWeather();
+
+ this._forecast = [];
+ this._forecastBox = new St.BoxLayout({
+ x_align: this._center_forecast ? St.Align.END : St.Align.START,
+ style_class: 'openweather-forecast-box'
+ });
+
+ this._forecastScrollBox = new St.ScrollView({
+ style_class: 'openweather-forecasts'
+ });
+
+ let pan = new Clutter.PanAction({
+ interpolate: true
+ });
+ pan.connect('pan', Lang.bind(this, function(action) {
+
+ let[dist, dx, dy] = action.get_motion_delta(0);
+
+ this.scrollForecastBy(-1 * (dx / this._forecastScrollBox.width) * this._forecastScrollBox.hscroll.adjustment.page_size);
+ return false;
+ }));
+ this._forecastScrollBox.add_action(pan);
+
+ this._forecastScrollBox.connect('scroll-event', Lang.bind(this, this._onScroll));
+ this._forecastScrollBox.hscroll.connect('scroll-event', Lang.bind(this, this._onScroll));
+
+ this._forecastScrollBox.hscroll.margin_right = 25;
+ this._forecastScrollBox.hscroll.margin_left = 25;
+ this._forecastScrollBox.hscroll.hide();
+ this._forecastScrollBox.vscrollbar_policy = Gtk.PolicyType.NEVER;
+ this._forecastScrollBox.hscrollbar_policy = Gtk.PolicyType.AUTOMATIC;
+ this._forecastScrollBox.enable_mouse_scrolling = true;
+ this._forecastScrollBox.hide();
+
+ this._futureWeather.set_child(this._forecastScrollBox);
+
+ for (let i = 0; i < this._days_forecast; i++) {
+ let forecastWeather = {};
+
+ forecastWeather.Icon = new St.Icon({
+ icon_size: 48,
+ icon_name: 'view-refresh' + this.icon_type(),
+ style_class: 'openweather-forecast-icon'
+ });
+ forecastWeather.Day = new St.Label({
+ style_class: 'openweather-forecast-day'
+ });
+ forecastWeather.Summary = new St.Label({
+ style_class: 'openweather-forecast-summary'
+ });
+ forecastWeather.Temperature = new St.Label({
+ style_class: 'openweather-forecast-temperature'
+ });
+
+ let by = new St.BoxLayout({
+ vertical: true,
+ style_class: 'openweather-forecast-databox'
+ });
+ by.add_actor(forecastWeather.Day);
+ by.add_actor(forecastWeather.Summary);
+ by.add_actor(forecastWeather.Temperature);
+
+ let bb = new St.BoxLayout({
+ style_class: 'openweather-forecast-iconbox'
+ });
+ bb.add_actor(forecastWeather.Icon);
+ bb.add_actor(by);
+
+ this._forecast[i] = forecastWeather;
+ this._forecastBox.add_actor(bb);
+ }
+ this._forecastScrollBox.add_actor(this._forecastBox);
+ },
+
+ _onScroll: function(actor, event) {
+ let dx = 0;
+ let dy = 0;
+ switch (event.get_scroll_direction()) {
+ case Clutter.ScrollDirection.UP:
+ dy = -1;
+ break;
+ case Clutter.ScrollDirection.DOWN:
+ dy = 1;
+ break;
+ // horizontal scrolling will be handled by the control itself
+ default:
+ return true;
+ }
+
+ this.scrollForecastBy(dy * this._forecastScrollBox.hscroll.adjustment.stepIncrement);
+ return false;
+ }
+});
+
+let openweatherMenu;
+
+function init() {
+ Convenience.initTranslations('gnome-shell-extension-openweather');
+}
+
+function enable() {
+ openweatherMenu = new OpenweatherMenuButton();
+ Main.panel.addToStatusArea('openweatherMenu', openweatherMenu);
+}
+
+function disable() {
+ openweatherMenu.stop();
+ openweatherMenu.destroy();
+}
diff --git a/temp.txt b/temp.txt
new file mode 100644
index 0000000..9bc8967
--- /dev/null
+++ b/temp.txt
@@ -0,0 +1,937 @@
+{
+ "cod":"200",
+ "message":0.0227,
+ "city":
+ {
+ "id":2807184,
+ "name":"Witzenhausen",
+ "coord":
+ {
+ "lon":9.86667,
+ "lat":51.333328
+ },
+ "country":"DE",
+ "population":16055
+ },
+ "cnt":10,
+ "list":
+ [
+ {
+ "dt":1382526000,
+ "temp":
+ {
+ "day":18.21,
+ "min":15.06,
+ "max":18.39,
+ "night":15.06,
+ "eve":17.24,
+ "morn":17.89
+ },
+ "pressure":990.22,
+ "humidity":75,
+ "weather":
+ [
+ {
+ "id":804,
+ "main":"Clouds",
+ "description":"overcast clouds",
+ "icon":"04d"
+ }
+ ],
+ "speed":7.59,
+ "deg":216,
+ "clouds":88
+ },
+ {
+ "dt":1382612400,
+ "temp":
+ {
+ "day":12.78,
+ "min":10.18,
+ "max":13.3,
+ "night":10.18,
+ "eve":10.8,
+ "morn":12.04
+ },
+ "pressure":999.55,
+ "humidity":100,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":2.28,
+ "deg":328,
+ "clouds":88,
+ "rain":6
+ },
+ {
+ "dt":1382698800,
+ "temp":
+ {
+ "day":14.51,
+ "min":11.29,
+ "max":14.95,
+ "night":14.95,
+ "eve":14.45,
+ "morn":11.29
+ },
+ "pressure":997.12,
+ "humidity":99,
+ "weather":
+ [
+ {
+ "id":500,
+ "main":"Rain",
+ "description":"light rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":5.02,
+ "deg":166,
+ "clouds":92,
+ "rain":1
+ },
+ {
+ "dt":1382785200,
+ "temp":
+ {
+ "day":18.32,
+ "min":15.21,
+ "max":18.32,
+ "night":15.81,
+ "eve":17.21,
+ "morn":15.21
+ },
+ "pressure":991.83,
+ "humidity":89,
+ "weather":
+ [
+ {
+ "id":500,
+ "main":"Rain",
+ "description":"light rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":6.92,
+ "deg":211,
+ "clouds":20,
+ "rain":1
+ },
+ {
+ "dt":1382871600,
+ "temp":
+ {
+ "day":11.91,
+ "min":10.7,
+ "max":13.76,
+ "night":10.7,
+ "eve":11.4,
+ "morn":13.28
+ },
+ "pressure":991.86,
+ "humidity":90,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":9.27,
+ "deg":256,
+ "clouds":24,
+ "rain":7
+ },
+ {
+ "dt":1382958000,
+ "temp":
+ {
+ "day":12.72,
+ "min":9.59,
+ "max":13.11,
+ "night":13.11,
+ "eve":12.94,
+ "morn":9.59
+ },
+ "pressure":983.93,
+ "humidity":0,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":7.39,
+ "deg":205,
+ "clouds":85,
+ "rain":9.48
+ },
+ {
+ "dt":1383044400,
+ "temp":
+ {
+ "day":12.55,
+ "min":10.99,
+ "max":12.55,
+ "night":10.99,
+ "eve":11.32,
+ "morn":11.08
+ },
+ "pressure":974.35,
+ "humidity":0,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":11.04,
+ "deg":222,
+ "clouds":78,
+ "rain":4.04
+ },
+ {
+ "dt":1383130800,
+ "temp":
+ {
+ "day":13.45,
+ "min":11.12,
+ "max":13.45,
+ "night":11.12,
+ "eve":12.01,
+ "morn":11.28
+ },
+ "pressure":974.2,
+ "humidity":0,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":7.86,
+ "deg":214,
+ "clouds":96,
+ "rain":3.98
+ },
+ {
+ "dt":1383217200,
+ "temp":
+ {
+ "day":12.61,
+ "min":10.44,
+ "max":12.61,
+ "night":10.44,
+ "eve":11.22,
+ "morn":10.67
+ },
+ "pressure":983.29,
+ "humidity":0,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":7.34,
+ "deg":228,
+ "clouds":4,
+ "rain":5.07
+ },
+ {
+ "dt":1383303600,
+ "temp":
+ {
+ "day":10.96,
+ "min":8.19,
+ "max":10.96,
+ "night":8.19,
+ "eve":9.54,
+ "morn":9.71
+ },
+ "pressure":996.06,
+ "humidity":0,
+ "weather":
+ [
+ {
+ "id":501,
+ "main":"Rain",
+ "description":"moderate rain",
+ "icon":"10d"
+ }
+ ],
+ "speed":3.4,
+ "deg":268,
+ "clouds":98,
+ "rain":6.79
+ }
+ ]
+}
+
+
+
+{
+ "coord":
+ {
+ "lon":9.86667,
+ "lat":51.333328
+ },
+ "sys":
+ {
+ "country":"DE",
+ "sunrise":1382507949,
+ "sunset":1382544624
+ },
+ "weather":
+ [
+ {
+ "id":804,
+ "main":"Clouds",
+ "description":"overcast clouds",
+ "icon":"04d"
+ }
+ ],
+ "base":"global stations",
+ "main":
+ {
+ "temp":17.885,
+ "temp_min":17.885,
+ "temp_max":17.885,
+ "pressure":990.17,
+ "sea_level":1019.55,
+ "grnd_level":990.17,
+ "humidity":77
+ },
+ "wind":
+ {
+ "speed":7.17,
+ "deg":205.505
+ },
+ "clouds":
+ {
+ "all":92
+ },
+ "dt":1382514022,
+ "id":2807184,
+ "name":"Witzenhausen",
+ "cod":200
+}
+
+{
+ "coord":
+ {
+ "lon":1.43296,
+ "lat":38.908829
+ },
+ "sys":
+ {
+ "country":"ES",
+ "sunrise":1382508754,
+ "sunset":1382547866
+ },
+ "weather":
+ [
+ {
+ "id":800,
+ "main":"Clear",
+ "description":"sky is clear",
+ "icon":"02d"
+ }
+ ],
+ "base":"global stations",
+ "main":
+ {
+ "temp":23.453,
+ "temp_min":23.453,
+ "temp_max":23.453,
+ "pressure":1028.28,
+ "sea_level":1028.37,
+ "grnd_level":1028.28,
+ "humidity":100
+ },
+ "wind":
+ {
+ "speed":7.96,
+ "deg":225.5
+ },
+ "clouds":
+ {
+ "all":8
+ },
+ "dt":1382545727,
+ "id":2516479,
+ "name":"Ibiza",
+ "cod":200
+}
+
+ English - en, Russian - ru, Italian - it, Spanish - sp, Ukrainian - ua, German - de, Portuguese - pt, Romanian - ro, Polish - pl, Finnish - fi, Dutch - nl, French - fr, Bulgarian - bg, Swedish - se, Chinese Traditional - zh_tw, Chinese Simplified - zh_cn, Turkish - tr , Czech - cz
+
+
+https://api.forecast.io/forecast/b251335276b56396cc98b7c79b282971/51.3750768,9.9179173?exclude=minutely,hourly&units=si
+
+{
+ "latitude":51.3750768,
+ "longitude":9.9179173,
+ "timezone":"Europe/Berlin",
+ "offset":1,
+ "currently":
+ {
+ "time":1426481725,
+ "summary":"Clear",
+ "icon":"clear-night",
+ "precipIntensity":0,
+ "precipProbability":0,
+ "temperature":1.07,
+ "apparentTemperature":-3.68,
+ "dewPoint":-0.08,
+ "humidity":0.92,
+ "windSpeed":5.19,
+ "windBearing":98,
+ "cloudCover":0.01,
+ "pressure":1026.57,
+ "ozone":424.04
+ },
+ "daily":
+ {
+ "summary":"Drizzle on Friday and Saturday, with temperatures peaking at 16C on Wednesday.",
+ "icon":"rain",
+ "data":
+ [
+ {
+ "time":1426460400,
+ "summary":"Mostly cloudy starting in the afternoon, continuing until evening.",
+ "icon":"partly-cloudy-day",
+ "sunriseTime":1426484069,
+ "sunsetTime":1426526784,
+ "moonPhase":0.85,
+ "precipIntensity":0,
+ "precipIntensityMax":0,
+ "precipProbability":0,
+ "temperatureMin":0.94,
+ "temperatureMinTime":1426478400,
+ "temperatureMax":11.72,
+ "temperatureMaxTime":1426518000,
+ "apparentTemperatureMin":-3.93,
+ "apparentTemperatureMinTime":1426478400,
+ "apparentTemperatureMax":11.72,
+ "apparentTemperatureMaxTime":1426518000,
+ "dewPoint":4.12,
+ "humidity":0.85,
+ "windSpeed":5.33,
+ "windBearing":104,
+ "cloudCover":0.17,
+ "pressure":1026.07,
+ "ozone":420.3
+ },
+ {
+ "time":1426546800,
+ "summary":"Partly cloudy starting in the afternoon.",
+ "icon":"partly-cloudy-night",
+ "sunriseTime":1426570332,
+ "sunsetTime":1426613285,
+ "moonPhase":0.89,
+ "precipIntensity":0,
+ "precipIntensityMax":0,
+ "precipProbability":0,
+ "temperatureMin":1.35,
+ "temperatureMinTime":1426568400,
+ "temperatureMax":13.86,
+ "temperatureMaxTime":1426604400,
+ "apparentTemperatureMin":-1.95,
+ "apparentTemperatureMinTime":1426568400,
+ "apparentTemperatureMax":13.86,
+ "apparentTemperatureMaxTime":1426604400,
+ "dewPoint":5.29,
+ "humidity":0.86,
+ "windSpeed":2.7,
+ "windBearing":105,
+ "cloudCover":0.24,
+ "pressure":1025.65,
+ "ozone":391.18
+ },
+ {
+ "time":1426633200,
+ "summary":"Partly cloudy in the morning.",
+ "icon":"partly-cloudy-night",
+ "sunriseTime":1426656595,
+ "sunsetTime":1426699785,
+ "moonPhase":0.93,
+ "precipIntensity":0,
+ "precipIntensityMax":0,
+ "precipProbability":0,
+ "temperatureMin":2.74,
+ "temperatureMinTime":1426654800,
+ "temperatureMax":15.66,
+ "temperatureMaxTime":1426687200,
+ "apparentTemperatureMin":2.74,
+ "apparentTemperatureMinTime":1426654800,
+ "apparentTemperatureMax":15.66,
+ "apparentTemperatureMaxTime":1426687200,
+ "dewPoint":5.94,
+ "humidity":0.83,
+ "windSpeed":0.49,
+ "windBearing":49,
+ "cloudCover":0.21,
+ "pressure":1025.06,
+ "ozone":387.11
+ },
+ {
+ "time":1426719600,
+ "summary":"Mostly cloudy throughout the day.",
+ "icon":"partly-cloudy-day",
+ "sunriseTime":1426742858,
+ "sunsetTime":1426786286,
+ "moonPhase":0.97,
+ "precipIntensity":0,
+ "precipIntensityMax":0,
+ "precipProbability":0,
+ "temperatureMin":3.92,
+ "temperatureMinTime":1426744800,
+ "temperatureMax":9.96,
+ "temperatureMaxTime":1426770000,
+ "apparentTemperatureMin":2.91,
+ "apparentTemperatureMinTime":1426744800,
+ "apparentTemperatureMax":8.87,
+ "apparentTemperatureMaxTime":1426770000,
+ "dewPoint":5.89,
+ "humidity":0.91,
+ "windSpeed":1.7,
+ "windBearing":308,
+ "cloudCover":0.6,
+ "pressure":1024.53,
+ "ozone":401.06
+ },
+ {
+ "time":1426806000,
+ "summary":"Drizzle until evening, starting again overnight.",
+ "icon":"rain",
+ "sunriseTime":1426829121,
+ "sunsetTime":1426872786,
+ "moonPhase":0.01,
+ "precipIntensity":0.1041,
+ "precipIntensityMax":0.2184,
+ "precipIntensityMaxTime":1426863600,
+ "precipProbability":0.68,
+ "precipType":"rain",
+ "temperatureMin":3.6,
+ "temperatureMinTime":1426831200,
+ "temperatureMax":6.87,
+ "temperatureMaxTime":1426863600,
+ "apparentTemperatureMin":1.98,
+ "apparentTemperatureMinTime":1426831200,
+ "apparentTemperatureMax":4.71,
+ "apparentTemperatureMaxTime":1426863600,
+ "dewPoint":4.37,
+ "humidity":0.91,
+ "windSpeed":2.48,
+ "windBearing":290,
+ "cloudCover":0.89,
+ "pressure":1020.38,
+ "ozone":387.87
+ },
+ {
+ "time":1426892400,
+ "summary":"Light rain until afternoon.",
+ "icon":"rain",
+ "sunriseTime":1426915383,
+ "sunsetTime":1426959286,
+ "moonPhase":0.04,
+ "precipIntensity":0.1321,
+ "precipIntensityMax":0.2438,
+ "precipIntensityMaxTime":1426906800,
+ "precipProbability":0.8,
+ "precipType":"rain",
+ "temperatureMin":0.57,
+ "temperatureMinTime":1426975200,
+ "temperatureMax":5.71,
+ "temperatureMaxTime":1426892400,
+ "apparentTemperatureMin":-2.42,
+ "apparentTemperatureMinTime":1426975200,
+ "apparentTemperatureMax":3.27,
+ "apparentTemperatureMaxTime":1426892400,
+ "dewPoint":2.03,
+ "humidity":0.91,
+ "windSpeed":3.17,
+ "windBearing":357,
+ "cloudCover":0.86,
+ "pressure":1015.43,
+ "ozone":410.38
+ },
+ {
+ "time":1426978800,
+ "summary":"Partly cloudy overnight.",
+ "icon":"partly-cloudy-night",
+ "sunriseTime":1427001646,
+ "sunsetTime":1427045786,
+ "moonPhase":0.08,
+ "precipIntensity":0.0305,
+ "precipIntensityMax":0.0356,
+ "precipIntensityMaxTime":1427025600,
+ "precipProbability":0.01,
+ "precipType":"snow",
+ "precipAccumulation":0.602,
+ "temperatureMin":-2.46,
+ "temperatureMinTime":1427000400,
+ "temperatureMax":4.5,
+ "temperatureMaxTime":1427036400,
+ "apparentTemperatureMin":-5.86,
+ "apparentTemperatureMinTime":1427000400,
+ "apparentTemperatureMax":1.8,
+ "apparentTemperatureMaxTime":1427036400,
+ "dewPoint":-3.39,
+ "humidity":0.75,
+ "windSpeed":2.65,
+ "windBearing":59,
+ "cloudCover":0.05,
+ "pressure":1020.27,
+ "ozone":356.07
+ },
+ {
+ "time":1427065200,
+ "summary":"Mostly cloudy throughout the day.",
+ "icon":"partly-cloudy-day",
+ "sunriseTime":1427087908,
+ "sunsetTime":1427132286,
+ "moonPhase":0.12,
+ "precipIntensity":0.0356,
+ "precipIntensityMax":0.0914,
+ "precipIntensityMaxTime":1427133600,
+ "precipProbability":0.1,
+ "precipType":"rain",
+ "temperatureMin":-2.33,
+ "temperatureMinTime":1427086800,
+ "temperatureMax":6.96,
+ "temperatureMaxTime":1427119200,
+ "apparentTemperatureMin":-4.58,
+ "apparentTemperatureMinTime":1427090400,
+ "apparentTemperatureMax":4.99,
+ "apparentTemperatureMaxTime":1427119200,
+ "dewPoint":-3.86,
+ "humidity":0.65,
+ "windSpeed":1.13,
+ "windBearing":216,
+ "cloudCover":0.73,
+ "pressure":1019.58,
+ "ozone":334.74
+ }
+ ]
+ },
+ "flags":
+ {
+ "sources":
+ [
+ "isd",
+ "madis",
+ "metno_ce",
+ "metno_ne",
+ "fnmoc",
+ "cmc",
+ "gfs"
+ ],
+ "isd-stations":
+ [
+ "094490-99999",
+ "104380-99999",
+ "104440-99999",
+ "104480-99999",
+ "104490-99999"
+ ],
+ "madis-stations":
+ [
+ "D8965",
+ "E0831",
+ "E0954",
+ "E4790",
+ "EDVK",
+ "ETHF"
+ ],
+ "metno-license":"Based on data from the Norwegian Meteorological Institute. (http://api.met.no/)",
+ "units":"si"
+ }
+}
+
+https://api.forecast.io/forecast/b251335276b56396cc98b7c79b282971/51.3750768,9.9175961?units=si&exclude=currently,minutely,hourly,alerts,flags
+
+{
+ "latitude":51.3750768,
+ "longitude":9.9175961,
+ "timezone":"Europe/Berlin",
+ "offset":1,
+ "daily":
+ {
+ "summary":"Light rain today through Friday, with temperatures rising to 13C on Monday.",
+ "icon":"rain",
+ "data":
+ [
+ {
+ "time":1426892400,
+ "summary":"Light rain until afternoon, starting again in the evening.",
+ "icon":"rain",
+ "sunriseTime":1426915383,
+ "sunsetTime":1426959286,
+ "moonPhase":0.04,
+ "precipIntensity":0.0914,
+ "precipIntensityMax":0.2388,
+ "precipIntensityMaxTime":1426960800,
+ "precipProbability":0.88,
+ "precipType":"rain",
+ "temperatureMin":-0.01,
+ "temperatureMinTime":1426903200,
+ "temperatureMax":7.6,
+ "temperatureMaxTime":1426950000,
+ "apparentTemperatureMin":-2.87,
+ "apparentTemperatureMinTime":1426910400,
+ "apparentTemperatureMax":6.66,
+ "apparentTemperatureMaxTime":1426950000,
+ "dewPoint":2.58,
+ "humidity":0.92,
+ "windSpeed":1.95,
+ "windBearing":287,
+ "cloudCover":0.79,
+ "pressure":1016.81,
+ "ozone":418.83
+ },
+ {
+ "time":1426978800,
+ "summary":"Mostly cloudy until afternoon.",
+ "icon":"partly-cloudy-day",
+ "sunriseTime":1427001646,
+ "sunsetTime":1427045786,
+ "moonPhase":0.08,
+ "precipIntensity":0.0203,
+ "precipIntensityMax":0.0864,
+ "precipIntensityMaxTime":1426982400,
+ "precipProbability":0.03,
+ "precipType":"rain",
+ "temperatureMin":-0.59,
+ "temperatureMinTime":1427004000,
+ "temperatureMax":6.78,
+ "temperatureMaxTime":1427036400,
+ "apparentTemperatureMin":-5.62,
+ "apparentTemperatureMinTime":1427004000,
+ "apparentTemperatureMax":3.92,
+ "apparentTemperatureMaxTime":1427036400,
+ "dewPoint":-0.18,
+ "humidity":0.82,
+ "windSpeed":3.97,
+ "windBearing":77,
+ "cloudCover":0.5,
+ "pressure":1025.36,
+ "ozone":364.7
+ },
+ {
+ "time":1427065200,
+ "summary":"Partly cloudy until afternoon.",
+ "icon":"partly-cloudy-day",
+ "sunriseTime":1427087908,
+ "sunsetTime":1427132286,
+ "moonPhase":0.12,
+ "precipIntensity":0,
+ "precipIntensityMax":0,
+ "precipProbability":0,
+ "temperatureMin":-3.18,
+ "temperatureMinTime":1427086800,
+ "temperatureMax":13.21,
+ "temperatureMaxTime":1427119200,
+ "apparentTemperatureMin":-5.2,
+ "apparentTemperatureMinTime":1427079600,
+ "apparentTemperatureMax":13.21,
+ "apparentTemperatureMaxTime":1427119200,
+ "dewPoint":-1.16,
+ "humidity":0.71,
+ "windSpeed":1.21,
+ "windBearing":169,
+ "cloudCover":0.33,
+ "pressure":1018.13,
+ "ozone":319.54
+ },
+ {
+ "time":1427151600,
+ "summary":"Mostly cloudy starting in the afternoon.",
+ "icon":"partly-cloudy-night",
+ "sunriseTime":1427174171,
+ "sunsetTime":1427218786,
+ "moonPhase":0.15,
+ "precipIntensity":0.0203,
+ "precipIntensityMax":0.0635,
+ "precipIntensityMaxTime":1427212800,
+ "precipProbability":0.02,
+ "precipType":"rain",
+ "temperatureMin":-1.47,
+ "temperatureMinTime":1427169600,
+ "temperatureMax":12.66,
+ "temperatureMaxTime":1427205600,
+ "apparentTemperatureMin":-1.47,
+ "apparentTemperatureMinTime":1427169600,
+ "apparentTemperatureMax":12.66,
+ "apparentTemperatureMaxTime":1427205600,
+ "dewPoint":2.52,
+ "humidity":0.83,
+ "windSpeed":1.1,
+ "windBearing":230,
+ "cloudCover":0.3,
+ "pressure":1007.38,
+ "ozone":368.29
+ },
+ {
+ "time":1427238000,
+ "summary":"Light rain overnight.",
+ "icon":"rain",
+ "sunriseTime":1427260433,
+ "sunsetTime":1427305285,
+ "moonPhase":0.19,
+ "precipIntensity":0.0483,
+ "precipIntensityMax":0.0864,
+ "precipIntensityMaxTime":1427274000,
+ "precipProbability":0.05,
+ "precipType":"rain",
+ "temperatureMin":0.86,
+ "temperatureMinTime":1427252400,
+ "temperatureMax":8.93,
+ "temperatureMaxTime":1427295600,
+ "apparentTemperatureMin":0.86,
+ "apparentTemperatureMinTime":1427252400,
+ "apparentTemperatureMax":7.97,
+ "apparentTemperatureMaxTime":1427295600,
+ "dewPoint":2.88,
+ "humidity":0.89,
+ "windSpeed":0.95,
+ "windBearing":335,
+ "cloudCover":0.93,
+ "pressure":1005.42,
+ "ozone":384.05
+ },
+ {
+ "time":1427324400,
+ "summary":"Light rain throughout the day.",
+ "icon":"rain",
+ "sunriseTime":1427346696,
+ "sunsetTime":1427391785,
+ "moonPhase":0.22,
+ "precipIntensity":0.3023,
+ "precipIntensityMax":0.5588,
+ "precipIntensityMaxTime":1427360400,
+ "precipProbability":0.8,
+ "precipType":"rain",
+ "temperatureMin":1.57,
+ "temperatureMinTime":1427349600,
+ "temperatureMax":7.74,
+ "temperatureMaxTime":1427385600,
+ "apparentTemperatureMin":-2.31,
+ "apparentTemperatureMinTime":1427349600,
+ "apparentTemperatureMax":5.8,
+ "apparentTemperatureMaxTime":1427385600,
+ "dewPoint":4.02,
+ "humidity":0.93,
+ "windSpeed":3.08,
+ "windBearing":1,
+ "cloudCover":0.99,
+ "pressure":1004.17,
+ "ozone":383.65
+ },
+ {
+ "time":1427410800,
+ "summary":"Overcast throughout the day.",
+ "icon":"cloudy",
+ "sunriseTime":1427432959,
+ "sunsetTime":1427478284,
+ "moonPhase":0.25,
+ "precipIntensity":0.0686,
+ "precipIntensityMax":0.1829,
+ "precipIntensityMaxTime":1427410800,
+ "precipProbability":0.42,
+ "precipType":"rain",
+ "temperatureMin":1.35,
+ "temperatureMinTime":1427436000,
+ "temperatureMax":7.37,
+ "temperatureMaxTime":1427472000,
+ "apparentTemperatureMin":-1.55,
+ "apparentTemperatureMinTime":1427436000,
+ "apparentTemperatureMax":5.62,
+ "apparentTemperatureMaxTime":1427472000,
+ "dewPoint":3.51,
+ "humidity":0.93,
+ "windSpeed":2.32,
+ "windBearing":331,
+ "cloudCover":1,
+ "pressure":1009.45,
+ "ozone":351.61
+ },
+ {
+ "time":1427497200,
+ "summary":"Overcast throughout the day.",
+ "icon":"cloudy",
+ "sunriseTime":1427519221,
+ "sunsetTime":1427564784,
+ "moonPhase":0.29,
+ "precipIntensity":0.0432,
+ "precipIntensityMax":0.0813,
+ "precipIntensityMaxTime":1427554800,
+ "precipProbability":0.08,
+ "precipType":"rain",
+ "temperatureMin":0.93,
+ "temperatureMinTime":1427518800,
+ "temperatureMax":8.17,
+ "temperatureMaxTime":1427554800,
+ "apparentTemperatureMin":0.93,
+ "apparentTemperatureMinTime":1427518800,
+ "apparentTemperatureMax":6.77,
+ "apparentTemperatureMaxTime":1427554800,
+ "dewPoint":3.03,
+ "humidity":0.9,
+ "windSpeed":1.51,
+ "windBearing":311,
+ "cloudCover":0.96,
+ "pressure":1011.46,
+ "ozone":349.29
+ }
+ ]
+ }
+}
+
+https://api.forecast.io/forecast/b251335276b56396cc98b7c79b282971/51.3750768,9.9175961?units=si&exclude=daily,minutely,hourly,alerts,flags
+
+{
+ "latitude":51.3750768,
+ "longitude":9.9175961,
+ "timezone":"Europe/Berlin",
+ "offset":1,
+ "currently":
+ {
+ "time":1426944648,
+ "summary":"Mostly Cloudy",
+ "icon":"partly-cloudy-day",
+ "precipIntensity":0.1245,
+ "precipProbability":0.1,
+ "precipType":"rain",
+ "temperature":6.17,
+ "apparentTemperature":4.28,
+ "dewPoint":4.68,
+ "humidity":0.9,
+ "windSpeed":2.51,
+ "windBearing":295,
+ "cloudCover":0.71,
+ "pressure":1015.34,
+ "ozone":448.84
+ }
+}
diff --git a/updateChangeLog.sh b/updateChangeLog.sh
new file mode 100755
index 0000000..de3266b
--- /dev/null
+++ b/updateChangeLog.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+COM_LAST=`head -1 ChangeLog | cut -d " " -f 2`
+
+echo "Downloading git log from commit $COM_LAST (excluded) to HEAD (included)"
+
+git log --decorate=no --date=rfc $COM_LAST...HEAD > ChangeLog.new
+
+cat "ChangeLog" >> "ChangeLog.new"
+
+mv "ChangeLog.new" "ChangeLog"
diff --git a/zip-file/openweather.shell-extension.zip b/zip-file/openweather.shell-extension.zip
new file mode 100644
index 0000000..8134683
Binary files /dev/null and b/zip-file/openweather.shell-extension.zip differ