You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by mw...@apache.org on 2013/05/15 22:36:05 UTC

[26/37] Add WP7 and WP8 platform files.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs b/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs
new file mode 100644
index 0000000..1528807
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Globalization.cs
@@ -0,0 +1,1178 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+using System;
+using System.Globalization;
+using System.Runtime.Serialization;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    /// <summary>
+    /// Provides information about system locale, culture settings, number formats, ect.
+    /// </summary>
+    public class Globalization : BaseCommand
+    {
+
+        #region Globalization errors
+
+        /// <summary>
+        /// Globalization error codes.
+        /// </summary>
+        public enum ErrorCode : int
+        {
+            UnknownError = 0,
+            FormattingError = 1,
+            ParsingError = 2,
+            PatternError = 3
+        }
+
+        /// <summary>
+        /// Represents globalization error object.
+        /// </summary>
+        [DataContract]
+        public class GlobalizationError
+        {
+            #region Error messages
+            /// <summary>
+            /// Error messages
+            /// </summary>        
+            public const string UnknownError = "UNKNOWN_ERROR";
+            public const string FormattingError = "FORMATTIN_ERROR";
+            public const string ParsingError = "PARSING_ERROR";
+            public const string PatternError = "PATTERN_ERROR";
+
+            #endregion
+
+            /// <summary>
+            /// Error code
+            /// </summary>
+            [DataMember(Name = "code", IsRequired = false)]
+            public ErrorCode Code { get; set; }
+
+            /// <summary>
+            /// Error message
+            /// </summary>
+            [DataMember(Name = "message", IsRequired = false)]
+            public string Message { get; set; }
+
+            /// <summary>
+            /// Default constructor
+            /// </summary>
+            public GlobalizationError()
+            {
+                this.Code = ErrorCode.UnknownError;
+                this.Message = UnknownError;
+            }
+
+            /// <summary>
+            /// Constructor setting error code
+            /// </summary>
+            public GlobalizationError(ErrorCode error)
+            {
+                this.Code = error;
+
+                switch (error)
+                {
+                    case ErrorCode.ParsingError:
+                        {
+                            this.Message = ParsingError;
+                            break;
+                        }
+                    case ErrorCode.FormattingError:
+                        {
+                            this.Message = FormattingError;
+                            break;
+                        }
+                    case ErrorCode.PatternError:
+                        {
+                            this.Message = PatternError;
+                            break;
+                        }
+                    default:
+                        {
+                            this.Message = UnknownError;
+                            break;
+                        }
+                }
+            }
+        }
+
+        #endregion
+
+        #region Globalization options
+
+        /// <summary>
+        /// Represents globalization options.
+        /// </summary>
+        [DataContract]
+        public class GlobalizationOptions
+        {
+            #region available option values
+            /// <summary>
+            /// Number pattern types.
+            /// </summary>        
+            public const string Percent = "percent";
+            public const string Currency = "currency";
+            public const string Decimal = "decimal";
+
+            /// <summary>
+            /// Format length types
+            /// </summary>        
+            public const string Short = "short";
+            public const string Medium = "medium";
+            public const string Long = "long";
+            public const string Full = "full";
+
+            /// <summary>
+            /// Selector types
+            /// </summary>        
+            public const string TimeSelector = "time";
+            public const string DateSelector = "date";
+            public const string DateAndTimeSelector = "date and time";
+
+            /// <summary>
+            /// Date name types
+            /// </summary>        
+            public const string Narrow = "narrow";
+            public const string Wide = "wide";
+
+            /// <summary>
+            /// Date name items
+            /// </summary>        
+            public const string Months = "months";
+            public const string Days = "days";
+
+            #endregion
+
+            /// <summary>
+            /// Additional options
+            /// </summary>
+            [DataMember(Name = "options", IsRequired = false)]
+            public Options AdditionalOptions { get; set; }
+
+            /// <summary>
+            /// Date to convert
+            /// </summary>
+            [DataMember(Name = "date", IsRequired = false)]
+            public long Date { get; set; }
+
+            /// <summary>
+            /// Date as stirng
+            /// </summary>
+            [DataMember(Name = "dateString", IsRequired = false)]
+            public string DateString { get; set; }
+
+            /// <summary>
+            /// Currency code
+            /// </summary>
+            [DataMember(Name = "currencyCode", IsRequired = false)]
+            public string CurrencyCode { get; set; }
+
+            /// <summary>
+            /// Number as string
+            /// </summary>
+            [DataMember(Name = "numberString", IsRequired = false)]
+            public string NumberString { get; set; }
+
+            /// <summary>
+            /// Number to convert
+            /// </summary>
+            [DataMember(Name = "number", IsRequired = false)]
+            public double Number { get; set; }
+        }
+
+        /// <summary>
+        /// Represents additional options
+        /// </summary>
+        [DataContract]
+        public class Options
+        {
+            /// <summary>
+            /// Pattern type
+            /// </summary>
+            [DataMember(Name = "type", IsRequired = false)]
+            public string Type { get; set; }
+
+            /// <summary>
+            /// Format length
+            /// </summary>
+            [DataMember(Name = "formatLength", IsRequired = false)]
+            public string FormatLength { get; set; }
+
+            /// <summary>
+            /// Selector
+            /// </summary>
+            [DataMember(Name = "selector", IsRequired = false)]
+            public string Selector { get; set; }
+
+            /// <summary>
+            /// Date name item
+            /// </summary>
+            [DataMember(Name = "item", IsRequired = false)]
+            public string Item { get; set; }
+        }
+
+        #endregion
+
+        #region returned objects
+
+        #region Number pattern object
+
+        /// <summary>
+        /// Represents number pattern
+        /// </summary>
+        [DataContract]
+        public class NumberPattern
+        {
+            /// <summary>
+            /// Pattern
+            /// </summary>
+            [DataMember(Name = "pattern", IsRequired = false)]
+            public string Pattern { get; set; }
+
+            /// <summary>
+            /// Symbol
+            /// </summary>
+            [DataMember(Name = "symbol", IsRequired = false)]
+            public string Symbol { get; set; }
+
+            /// <summary>
+            /// Fraction
+            /// </summary>
+            [DataMember(Name = "fraction", IsRequired = false)]
+            public int Fraction { get; set; }
+
+            /// <summary>
+            /// Positive
+            /// </summary>
+            [DataMember(Name = "positive", IsRequired = false)]
+            public string Positive { get; set; }
+
+            /// <summary>
+            /// Negative
+            /// </summary>
+            [DataMember(Name = "negative", IsRequired = false)]
+            public string Negative { get; set; }
+
+            /// <summary>
+            /// Rounding
+            /// </summary>
+            [DataMember(Name = "rounding", IsRequired = false)]
+            public int Rounding { get; set; }
+
+            /// <summary>
+            /// Decimal
+            /// </summary>
+            [DataMember(Name = "decimal", IsRequired = false)]
+            public string Decimal { get; set; }
+
+            /// <summary>
+            /// Grouping
+            /// </summary>
+            [DataMember(Name = "grouping", IsRequired = false)]
+            public string Grouping { get; set; }
+
+            /// <summary>
+            /// Constructor of the class
+            /// </summary>
+            /// <param name="pattern"></param>
+            /// <param name="symbol"></param>
+            /// <param name="fraction"></param>
+            /// <param name="positive"></param>
+            /// <param name="negative"></param>
+            /// <param name="rounding"></param>
+            /// <param name="dec"></param>
+            /// <param name="grouping"></param>
+            public NumberPattern(string pattern, string symbol, int fraction, string positive, string negative, int rounding, string dec, string grouping)
+            {
+                this.Pattern = pattern;
+                this.Symbol = symbol;
+                this.Fraction = fraction;
+                this.Positive = positive;
+                this.Negative = negative;
+                this.Rounding = rounding;
+                this.Decimal = dec;
+                this.Grouping = grouping;
+            }
+        }
+        #endregion
+
+        #region Date format object
+
+        /// <summary>
+        /// Represents date format
+        /// </summary>
+        [DataContract]
+        public class DateFormat
+        {
+            /// <summary>
+            /// Year
+            /// </summary>
+            [DataMember(Name = "year", IsRequired = false)]
+            public int Year { get; set; }
+
+            /// <summary>
+            /// Month
+            /// </summary>
+            [DataMember(Name = "month", IsRequired = false)]
+            public int Month { get; set; }
+
+            /// <summary>
+            /// Day
+            /// </summary>
+            [DataMember(Name = "day", IsRequired = false)]
+            public int Day { get; set; }
+
+            /// <summary>
+            /// Hour
+            /// </summary>
+            [DataMember(Name = "hour", IsRequired = false)]
+            public int Hour { get; set; }
+
+            /// <summary>
+            /// Minute
+            /// </summary>
+            [DataMember(Name = "minute", IsRequired = false)]
+            public int Minute { get; set; }
+
+            /// <summary>
+            /// Second
+            /// </summary>
+            [DataMember(Name = "second", IsRequired = false)]
+            public int Second { get; set; }
+
+            /// <summary>
+            /// Millisecond
+            /// </summary>
+            [DataMember(Name = "millisecond", IsRequired = false)]
+            public int Millisecond { get; set; }
+
+            public DateFormat(int year, int month, int day, int hour, int minute, int second, int millisecond)
+            {
+                this.Year = year;
+                this.Month = month;
+                this.Day = day;
+                this.Hour = hour;
+                this.Minute = minute;
+                this.Millisecond = millisecond;
+            }
+
+        }
+        #endregion
+
+        #region Date pattern object
+
+        /// <summary>
+        /// Represents date pattern object
+        /// </summary>
+        [DataContract]
+        public class DatePattern
+        {
+
+            /// <summary>
+            /// Date pattern
+            /// </summary>
+            [DataMember(Name = "pattern", IsRequired = false)]
+            public string Pattern { get; set; }
+
+            /// <summary>
+            /// TimeZone
+            /// </summary>
+            [DataMember(Name = "timezone", IsRequired = false)]
+            public string TimeZone { get; set; }
+
+            /// <summary>
+            /// UTC offset
+            /// </summary>
+            [DataMember(Name = "utc_offset", IsRequired = false)]
+            public double UtcOffset { get; set; }
+
+            /// <summary>
+            /// Dst offset
+            /// </summary>
+            [DataMember(Name = "dst_offset", IsRequired = false)]
+            public double DstOffset { get; set; }
+
+            /// <summary>
+            /// Constructor of the class
+            /// </summary>
+            /// <param name="pattern"></param>
+            /// <param name="timezone"></param>
+            /// <param name="utcOffset"></param>
+            /// <param name="dstOffset"></param>
+            public DatePattern(string pattern, string timezone, double utcOffset, double dstOffset)
+            {
+                this.Pattern = pattern;
+                this.TimeZone = timezone;
+                this.UtcOffset = utcOffset;
+                this.DstOffset = dstOffset;
+            }
+
+        }
+
+        #endregion
+
+        #endregion
+
+        #region Locale info
+
+        /// <summary>
+        /// Gets the string identifier for the client's current locale setting.
+        /// </summary>
+        /// <param name="options"></param>               
+        public void getLocaleName(string options)
+        {
+            try
+            {
+                var locale = RegionInfo.CurrentRegion.TwoLetterISORegionName;
+                PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(locale));
+                this.DispatchCommandResult(result);
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+            }
+        }
+
+        /// <summary>
+        /// Gets the string identifier for the client's current language.
+        /// </summary>
+        /// <param name="options"></param>               
+        public void getPreferredLanguage(string options)
+        {
+            try
+            {
+                var language = CultureInfo.CurrentCulture.TwoLetterISOLanguageName;
+                PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(language));
+                this.DispatchCommandResult(result);
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+            }
+        }
+
+        #endregion
+
+        #region Date and time info
+
+        /// <summary>
+        /// Gets whether daylight savings time is in effect for a given date using the client's 
+        /// time zone and calendar.        
+        /// </summary>
+        /// <param name="opitons">Date to daylight savings check.</param>
+        public void isDayLightSavingsTime(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+                DateTime date = start.AddMilliseconds(globalOptions.Date).ToLocalTime();
+                TimeZoneInfo localZone = TimeZoneInfo.Local;
+                bool isDaylightSavingTime = localZone.IsDaylightSavingTime(date);
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(isDaylightSavingTime, "dst")));
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+            }
+        }
+
+        /// <summary>
+        /// Gets the first day of the week according to the client's user preferences and calendar.
+        /// The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
+        /// </summary>
+        /// <param name="options"></param>
+        public void getFirstDayOfWeek(string options)
+        {
+            try
+            {
+                // DateTimeFormat returns days of the week numbered from zero, so we have to increase returned value by one.
+                var firstDayOfWeek = (int)CultureInfo.CurrentCulture.DateTimeFormat.FirstDayOfWeek + 1;
+                PluginResult result = new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(firstDayOfWeek));
+                this.DispatchCommandResult(result);
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+            }
+        }
+
+        #endregion
+
+        #region Formatting
+
+        /// <summary>
+        /// Gets a date formatted as a string according to the client's user preferences and calendar using the time zone of the client. 
+        /// </summary>
+        /// <param name="options"></param>
+        public void dateToString(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                DateTime start = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+                DateTime date = start.AddMilliseconds(globalOptions.Date).ToLocalTime();
+
+                string format = "{0:M/dd/yy H:m:s}"; //short datetime by default
+                int formatLength = 0; //default format
+                int selector = 0; //default selector 
+
+                if (globalOptions.AdditionalOptions != null)
+                {
+                    if (globalOptions.AdditionalOptions.FormatLength != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.FormatLength;
+
+                        if (t.Equals(GlobalizationOptions.Full))
+                        {
+                            formatLength++;
+                        }
+                    }
+
+                    if (globalOptions.AdditionalOptions.Selector != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.Selector;
+
+                        if (t.Equals(GlobalizationOptions.DateSelector))
+                        {
+                            selector += 10;
+                        }
+                        else if (t.Equals(GlobalizationOptions.TimeSelector))
+                        {
+                            selector += 20;
+                        }
+                    }
+
+                    //determine return value
+                    int method = formatLength + selector;
+
+                    switch (method)
+                    {
+                        case 1: // full datetime
+                            {
+                                format = "{0:MMMM/dddd/yyyy HH:mm:ss tt}";
+                                break;
+                            }
+                        case 10: // short date
+                            {
+                                format = "{0:d}";
+                                break;
+                            }
+                        case 11: // full date
+                            {
+                                format = "{0:D}";
+                                break;
+                            }
+                        case 20: // short time
+                            {
+                                format = "{0:t}";
+                                break;
+                            }
+                        case 21: // full time
+                            {
+                                format = "{0:T}";
+                                break;
+                            }
+                        default: // short datetime
+                            {
+                                format = "{0:M/dd/yy H:m:s}";
+                                break;
+                            }
+                    }
+                }
+
+                string formattedValue = string.Format(CultureInfo.CurrentCulture, format, date);
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(formattedValue)));
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+            }
+        }
+
+        /// <summary>
+        /// Parses a date formatted as a string according to the client's user preferences and calendar using the time zone of the client and returns the corresponding date object
+        /// </summary>
+        /// <param name="options"></param>
+        public void stringToDate(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                if (string.IsNullOrEmpty(globalOptions.DateString))
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                string format = "M/dd/yy H:m:s"; // short datetime by default
+                int formatLength = 0; //default format
+                int selector = 0; //default selector 
+
+                if (globalOptions.AdditionalOptions != null)
+                {
+                    if (globalOptions.AdditionalOptions.FormatLength != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.FormatLength;
+
+                        if (t.Equals(GlobalizationOptions.Full))
+                        {
+                            formatLength++;
+                        }
+                    }
+
+                    if (globalOptions.AdditionalOptions.Selector != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.Selector;
+
+                        if (t.Equals(GlobalizationOptions.DateSelector))
+                        {
+                            selector += 10;
+                        }
+                        else if (t.Equals(GlobalizationOptions.TimeSelector))
+                        {
+                            selector += 20;
+                        }
+                    }
+
+                    //determine return value
+                    int method = formatLength + selector;
+
+                    switch (method)
+                    {
+                        case 1: // full datetime
+                            {
+                                format = "MMMM/dddd/yyyy HH:mm:ss tt";
+                                break;
+                            }
+                        case 10: // short date
+                            {
+                                format = "d";
+                                break;
+                            }
+                        case 11: // full date
+                            {
+                                format = "D";
+                                break;
+                            }
+                        case 20: // short time
+                            {
+                                format = "t";
+                                break;
+                            }
+                        case 21: // full time
+                            {
+                                format = "T";
+                                break;
+                            }
+                        default: // short datetime
+                            {
+                                format = "M/dd/yy H:m:s";
+                                break;
+                            }
+                    }
+                }
+
+                DateTime date = DateTime.ParseExact(globalOptions.DateString, format, CultureInfo.CurrentCulture);
+                DateFormat dateFormat = new DateFormat(date.Year, date.Month, date.Day, date.Hour, date.Minute, date.Second, date.Millisecond);
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, dateFormat));
+
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.ParsingError)));
+            }
+        }
+
+        /// <summary>
+        /// Gets a pattern string for formatting and parsing dates according to the client's user preferences.
+        /// </summary>
+        /// <param name="options"></param>
+        public void getDatePattern(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                DateTimeFormatInfo dateFormatInfo = DateTimeFormatInfo.CurrentInfo;
+                string pattern = dateFormatInfo.FullDateTimePattern; // full datetime by default
+                int formatLength = 0; //default format
+                int selector = 0; //default selector 
+
+                if (globalOptions.AdditionalOptions != null)
+                {
+                    if (globalOptions.AdditionalOptions.FormatLength != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.FormatLength;
+
+                        if (t.Equals(GlobalizationOptions.Full))
+                        {
+                            formatLength++;
+                        }
+                    }
+
+                    if (globalOptions.AdditionalOptions.Selector != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.Selector;
+
+                        if (t.Equals(GlobalizationOptions.DateSelector))
+                        {
+                            selector += 10;
+                        }
+                        else if (t.Equals(GlobalizationOptions.TimeSelector))
+                        {
+                            selector += 20;
+                        }
+                    }
+
+                    //determine return value
+                    int method = formatLength + selector;
+
+                    switch (method)
+                    {
+                        case 1: // full datetime
+                            {
+                                pattern = dateFormatInfo.FullDateTimePattern;
+                                break;
+                            }
+                        case 10: // short date
+                            {
+                                pattern = dateFormatInfo.ShortDatePattern;
+                                break;
+                            }
+                        case 11: // full date
+                            {
+                                pattern = dateFormatInfo.LongDatePattern;
+                                break;
+                            }
+                        case 20: // short time
+                            {
+                                pattern = dateFormatInfo.ShortTimePattern;
+                                break;
+                            }
+                        case 21: // full time
+                            {
+                                pattern = dateFormatInfo.LongTimePattern;
+                                break;
+                            }
+                        default: // short datetime
+                            {
+                                // Seems like C# doesn't support short datetime pattern so we use full format
+                                // http://msdn.microsoft.com/en-us/library/1at0z4ew%28v=vs.71%29.aspx
+                                pattern = dateFormatInfo.FullDateTimePattern;
+                                break;
+                            }
+                    }
+                }
+
+                TimeZoneInfo localZone = TimeZoneInfo.Local;
+                DatePattern datePattern = new DatePattern(pattern, localZone.DisplayName, localZone.BaseUtcOffset.TotalSeconds, 0);
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, datePattern));
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.PatternError)));
+            }
+        }
+
+        /// <summary>
+        /// Gets an array of either the names of the months or days of the week according to the client's user preferences and calendar.
+        /// </summary>
+        /// <param name="options"></param>
+        public void getDateNames(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                int type = 0; //default wide
+                int item = 0; //default months 
+
+                if (globalOptions.AdditionalOptions != null)
+                {
+                    if (globalOptions.AdditionalOptions.Type != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.Type;
+
+                        if (t.Equals(GlobalizationOptions.Narrow))
+                        {
+                            type++;
+                        }
+                    }
+
+                    if (globalOptions.AdditionalOptions.Item != null)
+                    {
+                        string t = globalOptions.AdditionalOptions.Item;
+
+                        if (t.Equals(GlobalizationOptions.Days))
+                        {
+                            item += 10;
+                        }
+                    }
+                }
+
+                //determine return value
+                int method = item + type;
+                string[] namesArray;
+                CultureInfo currentCulture = CultureInfo.CurrentCulture;
+
+                if (method == 1) //months and narrow
+                {
+                    namesArray = currentCulture.DateTimeFormat.AbbreviatedMonthNames;
+                }
+                else if (method == 10) //days and wide
+                {
+                    namesArray = currentCulture.DateTimeFormat.DayNames;
+                }
+                else if (method == 11) //days and narrow
+                {
+                    namesArray = currentCulture.DateTimeFormat.AbbreviatedDayNames;
+                }
+                else //default: months and wide
+                {
+                    namesArray = currentCulture.DateTimeFormat.MonthNames;
+                }
+
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(namesArray)));
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError()));
+            }
+        }
+
+        /// <summary>
+        /// Gets a number formatted as a string according to the client's user preferences. 
+        /// </summary>
+        /// <param name="options"></param>
+        public void numberToString(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                string format = string.Empty;
+                string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+                    GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+
+                switch (numberFormatType)
+                {
+                    case GlobalizationOptions.Percent:
+                        {
+                            format = "{0:p}";
+                            break;
+                        }
+
+                    case GlobalizationOptions.Currency:
+                        {
+                            format = "{0:c}";
+                            break;
+                        }
+
+                    default:
+                        {
+                            format = "{0:f}";
+                            break;
+                        }
+                }
+
+                string formattedValue = string.Format(CultureInfo.CurrentCulture, format, globalOptions.Number);
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(formattedValue)));
+
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+            }
+        }
+
+        /// <summary>
+        /// Gets a number formatted as a string according to the client's user preferences and returns the corresponding number.
+        /// </summary>
+        /// <param name="options"></param>
+        public void stringToNumber(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                if (string.IsNullOrEmpty(globalOptions.NumberString))
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                string numberString = globalOptions.NumberString;
+                string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+                    GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+
+                NumberStyles numberStyle;
+
+                switch (numberFormatType)
+                {
+                    case GlobalizationOptions.Percent:
+                        {
+                            numberStyle = NumberStyles.Any;
+                            numberString = numberString.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.PercentSymbol, "");
+                            break;
+                        }
+
+                    case GlobalizationOptions.Currency:
+                        {
+                            numberStyle = NumberStyles.Currency;
+                            break;
+                        }
+
+                    default:
+                        {
+                            numberStyle = NumberStyles.Number;
+                            break;
+                        }
+                }
+
+                double value = double.Parse(numberString, numberStyle, CultureInfo.CurrentCulture);
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, this.WrapIntoJSON(value)));
+
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.ParsingError)));
+            }
+        }
+
+
+        /// <summary>
+        /// Gets a pattern string for formatting and parsing numbers according to the client's user preferences.
+        /// </summary>
+        /// <param name="options"></param>
+        public void getNumberPattern(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                CultureInfo cultureInfo = CultureInfo.CurrentCulture;
+                NumberFormatInfo formatInfo = cultureInfo.NumberFormat;
+                string numberFormatType = (globalOptions.AdditionalOptions == null || string.IsNullOrEmpty(globalOptions.AdditionalOptions.Type)) ?
+                    GlobalizationOptions.Decimal : globalOptions.AdditionalOptions.Type;
+                NumberPattern pattern = null;
+                string symbol;
+
+                // TODO find out how to get format pattern and the number of fraction digits
+                switch (numberFormatType)
+                {
+                    case GlobalizationOptions.Percent:
+                        {
+                            symbol = formatInfo.PercentSymbol;
+                            pattern = new NumberPattern("", symbol, 0, formatInfo.PercentPositivePattern.ToString(), formatInfo.PercentNegativePattern.ToString(), 0, formatInfo.PercentDecimalSeparator, formatInfo.PercentGroupSeparator);
+                            break;
+                        }
+                    case GlobalizationOptions.Currency:
+                        {
+                            symbol = formatInfo.CurrencySymbol;
+                            pattern = new NumberPattern("", symbol, 0, formatInfo.CurrencyPositivePattern.ToString(), formatInfo.CurrencyNegativePattern.ToString(), 0, formatInfo.CurrencyDecimalSeparator, formatInfo.CurrencyGroupSeparator);
+                            break;
+                        }
+                    default:
+                        {
+                            symbol = formatInfo.NumberDecimalSeparator;
+                            pattern = new NumberPattern("", symbol, 0, "", formatInfo.NumberNegativePattern.ToString(), 0, formatInfo.NumberDecimalSeparator, formatInfo.NumberGroupSeparator);
+                            break;
+                        }
+                }
+
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.OK, pattern));
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.PatternError)));
+            }
+        }
+
+        /// <summary>
+        /// Gets a pattern string for formatting and parsing currency values according to the client's user preferences and ISO 4217 currency code.
+        /// </summary>
+        /// <param name="options"></param>
+        public void getCurrencyPattern(string options)
+        {
+            GlobalizationOptions globalOptions;
+
+            try
+            {
+                string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+                globalOptions = JSON.JsonHelper.Deserialize<GlobalizationOptions>(args[0]);
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+
+            try
+            {
+                if (string.IsNullOrEmpty(globalOptions.CurrencyCode))
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                string currencyCode = globalOptions.CurrencyCode;
+
+                // temporary not supported via lack of api required
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.INVALID_ACTION, "Not supported"));
+                return;
+
+                // TODO find the way to get currency info from currency code
+                // http://stackoverflow.com/questions/12373800/3-digit-currency-code-to-currency-symbol
+                // http://stackoverflow.com/questions/6924067/how-to-get-specific-culture-currency-pattern
+                // CultureInfo cultureInfo = new CultureInfo(currencyCode);
+                // NumberFormatInfo numberFormat = cultureInfo.NumberFormat;
+            }
+            catch (Exception e)
+            {
+                this.DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, new GlobalizationError(ErrorCode.FormattingError)));
+            }
+        }
+
+        #endregion
+
+
+        #region private methods
+
+        /// <summary>
+        /// Wraps data into JSON format
+        /// </summary>
+        /// <param name="data">data</param>
+        /// <returns>data formatted as JSON object</returns>
+        private string WrapIntoJSON<T>(T data, string keyName = "value")
+        {
+            string param = "{0}";
+            string stringifiedData = data.ToString();
+
+            if (data.GetType() == typeof(string))
+            {
+                param = "\"" + param + "\"";
+            }
+
+            if (data.GetType() == typeof(bool))
+            {
+                stringifiedData = stringifiedData.ToLower();
+            }
+
+            if (data.GetType() == typeof(string[]))
+            {
+                stringifiedData = JSON.JsonHelper.Serialize(data);
+            }
+
+            var formattedData = string.Format("\"" + keyName + "\":" + param, stringifiedData);
+            formattedData = "{" + formattedData + "}";
+
+            return formattedData;
+        }
+
+        #endregion
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs b/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs
new file mode 100644
index 0000000..62b6462
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/ImageExifHelper.cs
@@ -0,0 +1,209 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+ 
+*/
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Windows.Media.Imaging;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    public class ImageExifOrientation
+    {
+        public const int Portrait = 1;
+        public const int PortraitUpsideDown = 3;
+        public const int LandscapeLeft = 6;
+        public const int LandscapeRight = 8;
+    }
+
+    public class ImageExifHelper
+    {
+
+        public static Stream RotateStream(Stream stream, int angle)
+        {
+            stream.Position = 0;
+            if (angle % 90 != 0 || angle < 0)
+            {
+                throw new ArgumentException();
+            }
+            if (angle % 360 == 0)
+            {
+                return stream;
+            }
+
+            angle = angle % 360;
+
+            BitmapImage bitmap = new BitmapImage();
+            bitmap.SetSource(stream);
+            WriteableBitmap wbSource = new WriteableBitmap(bitmap);
+
+            WriteableBitmap wbTarget = null;
+
+            int srcPixelWidth = wbSource.PixelWidth;
+            int srcPixelHeight = wbSource.PixelHeight;
+
+            if (angle % 180 == 0)
+            {
+                wbTarget = new WriteableBitmap(srcPixelWidth, srcPixelHeight);
+            }
+            else
+            {
+                wbTarget = new WriteableBitmap(srcPixelHeight, srcPixelWidth);
+            }
+
+            int destPixelWidth = wbTarget.PixelWidth;
+            int[] srcPxls = wbSource.Pixels;
+            int[] destPxls = wbTarget.Pixels;
+
+            // this ugly if/else is to avoid a conditional check for every pixel
+            if (angle == 90)
+            {
+                for (int x = 0; x < srcPixelWidth; x++)
+                {
+                    for (int y = 0; y < srcPixelHeight; y++)
+                    {
+                        destPxls[(srcPixelHeight - y - 1) + (x * destPixelWidth)] = srcPxls[x + y * srcPixelWidth];
+                    }
+                }
+            }
+            else if (angle == 180)
+            {
+                for (int x = 0; x < srcPixelWidth; x++)
+                {
+                    for (int y = 0; y < srcPixelHeight; y++)
+                    {
+                        destPxls[(srcPixelWidth - x - 1) + (srcPixelHeight - y - 1) * srcPixelWidth] = srcPxls[x + y * srcPixelWidth];
+                    }
+                }
+            }
+            else if (angle == 270)
+            {
+                for (int x = 0; x < srcPixelWidth; x++)
+                {
+                    for (int y = 0; y < srcPixelHeight; y++)
+                    {
+                        destPxls[y + (srcPixelWidth - x - 1) * destPixelWidth] = srcPxls[x + y * srcPixelWidth];
+                    }
+                }
+            }
+
+            MemoryStream targetStream = new MemoryStream();
+            wbTarget.SaveJpeg(targetStream, destPixelWidth, wbTarget.PixelHeight, 0, 100);
+            return targetStream;
+        }
+
+        public static int getImageOrientationFromStream(Stream imgStream)
+        {
+
+            // 0xFFD8 : jpgHeader
+            // 0xFFE1 :
+            // 0x???? : length of exif data
+            // 0x????, 0x???? : Chars 'E','x','i','f'
+            // 0x0000 : 2 empty bytes
+            // <== mark beginning of tags SIZE:ID:VALUE
+            // 0x???? : 'II' or 'MM' for Intel or Motorola ( always getting II on my WP7 devices ), determines littleEndian-ness
+            // 0x002A : marker value
+            // 0x???? : offset to the Image File Data
+
+            // XXXX possible space before actual tag data ... we skip to mark + offset
+
+            // 0x???? number of exif tags present
+
+            // make sure we are at the beginning
+            imgStream.Seek(0, SeekOrigin.Begin);
+            BinaryReader reader = new BinaryReader(imgStream);
+
+            byte[] jpgHdr = reader.ReadBytes(2); // always (0xFFD8)
+
+            byte start = reader.ReadByte(); // 0xFF
+            byte index = reader.ReadByte(); // 0xE1
+
+            while (start == 0xFF && index != 0xE1) // This never seems to happen, todo: optimize
+            {
+                // Get the data length
+                ushort dLen = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+                // skip along
+                reader.ReadBytes(dLen - 2);
+                start = reader.ReadByte();
+                index = reader.ReadByte();
+            }
+
+            // It's only success if we found the 0xFFE1 marker
+            if (start != 0xFF || index != 0xE1)
+            {
+                //   throw new Exception("Could not find Exif data block");
+                Debug.WriteLine("Did not find EXIF data");
+                return 0;
+            }
+
+            // read 2 byte length of EXIF data
+            ushort exifLen = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+            String exif = ""; // build the string
+            for (var n = 0; n < 4; n++)
+            {
+                exif += reader.ReadChar();
+            }
+            if (exif != "Exif")
+            {
+                // did not find exif data ...
+                Debug.WriteLine("Did not find EXIF data");
+                return 0;
+            }
+
+            // read 2 empty bytes
+            //ushort emptyBytes = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+            reader.ReadBytes(2);
+
+            long headerMark = reader.BaseStream.Position; // where are we now <==
+
+            //bool isLEndian = (reader.ReadChar() + "" + reader.ReadChar()) == "II";
+            reader.ReadBytes(2); // 'II' or 'MM', but we don't care
+
+            if (0x002A != BitConverter.ToUInt16(reader.ReadBytes(2), 0))
+            {
+                Debug.WriteLine("Error in data != 0x002A");
+                return 0;
+            }
+
+            // Get the offset to the IFD (image file directory)
+            ushort imgOffset = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+
+            imgStream.Position = headerMark + imgOffset;
+            ushort tagCount = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+            for (ushort x = 0; x < tagCount; x++)
+            {
+                // Orientation = 0x112, aka 274
+                if (0x112 == BitConverter.ToUInt16(reader.ReadBytes(2), 0))
+                {
+                    ushort dType = BitConverter.ToUInt16(reader.ReadBytes(2), 0);
+                    // don't care ..
+                    uint comps = reader.ReadUInt32();
+                    byte[] tagData = reader.ReadBytes(4);
+                    int orientation = (int)tagData[0];
+                    Debug.WriteLine("orientation = " + orientation.ToString());
+                    return orientation;
+                    // 6 means rotate clockwise 90 deg
+                    // 8 means rotate counter-clockwise 90 deg
+                    // 1 means all is good
+                    // 3 means flip vertical
+                }
+                // skip to the next item, 12 bytes each
+                reader.BaseStream.Seek(10, SeekOrigin.Current);
+            }
+            return 0;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs b/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs
new file mode 100644
index 0000000..425f5ae
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/InAppBrowser.cs
@@ -0,0 +1,268 @@
+using System;
+using System.Net;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Ink;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Shapes;
+using Microsoft.Phone.Controls;
+using System.Diagnostics;
+using System.Runtime.Serialization;
+using WPCordovaClassLib.Cordova;
+using WPCordovaClassLib.Cordova.Commands;
+using WPCordovaClassLib.Cordova.JSON;
+using Microsoft.Phone.Shell;
+using Microsoft.Phone.Tasks;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    [DataContract]
+    public class BrowserOptions
+    {
+        [DataMember]
+        public string url;
+
+        [DataMember]
+        public bool isGeolocationEnabled;
+    }
+
+    public class InAppBrowser : BaseCommand
+    {
+
+        private static WebBrowser browser;
+        private static ApplicationBarIconButton backButton;
+        private static ApplicationBarIconButton fwdButton;
+
+        public void open(string options)
+        {
+            string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
+            //BrowserOptions opts = JSON.JsonHelper.Deserialize<BrowserOptions>(options);
+            string urlLoc = args[0];
+            string target = args[1];
+            /*
+                _self - opens in the Cordova WebView if url is in the white-list, else it opens in the InAppBrowser 
+                _blank - always open in the InAppBrowser 
+                _system - always open in the system web browser 
+            */
+            switch (target)
+            {
+                case "_blank":
+                    ShowInAppBrowser(urlLoc);
+                    break;
+                case "_self":
+                    ShowCordovaBrowser(urlLoc);
+                    break;
+                case "_system":
+                    ShowSystemBrowser(urlLoc);
+                    break;
+            }
+
+
+        }
+
+        private void ShowCordovaBrowser(string url)
+        {
+            Uri loc = new Uri(url, UriKind.RelativeOrAbsolute);
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+                if (frame != null)
+                {
+                    PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+                    if (page != null)
+                    {
+                        CordovaView cView = page.FindName("CordovaView") as CordovaView;
+                        if (cView != null)
+                        {
+                            WebBrowser br = cView.Browser;
+                            br.Navigate(loc);
+                        }
+                    }
+
+                }
+            });
+        }
+
+        private void ShowSystemBrowser(string url)
+        {
+            WebBrowserTask webBrowserTask = new WebBrowserTask();
+            webBrowserTask.Uri = new Uri(url, UriKind.Absolute);
+            webBrowserTask.Show();
+        }
+
+
+        // Display an inderminate progress indicator
+        private void ShowInAppBrowser(string url)
+        {
+            Uri loc = new Uri(url);
+
+            Deployment.Current.Dispatcher.BeginInvoke(() =>
+            {
+                if (browser != null)
+                {
+                    //browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
+                    browser.Navigate(loc);
+                }
+                else
+                {
+                    PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+                    if (frame != null)
+                    {
+                        PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+
+                        if (page != null)
+                        {
+                            Grid grid = page.FindName("LayoutRoot") as Grid;
+                            if (grid != null)
+                            {
+                                browser = new WebBrowser();
+                                browser.IsScriptEnabled = true;
+                                browser.LoadCompleted += new System.Windows.Navigation.LoadCompletedEventHandler(browser_LoadCompleted);
+                                browser.Navigating += new EventHandler<NavigatingEventArgs>(browser_Navigating);
+                                browser.NavigationFailed += new System.Windows.Navigation.NavigationFailedEventHandler(browser_NavigationFailed);
+                                browser.Navigated += new EventHandler<System.Windows.Navigation.NavigationEventArgs>(browser_Navigated);
+                                
+                                browser.Navigate(loc);
+                                //browser.IsGeolocationEnabled = opts.isGeolocationEnabled;
+                                grid.Children.Add(browser);
+                            }
+
+                            ApplicationBar bar = new ApplicationBar();
+                            bar.BackgroundColor = Colors.Gray;
+                            bar.IsMenuEnabled = false;
+
+                            backButton = new ApplicationBarIconButton();
+                            backButton.Text = "Back";
+                            backButton.IconUri = new Uri("/Images/appbar.back.rest.png", UriKind.Relative);
+                            backButton.Click += new EventHandler(backButton_Click);
+                            //backButton.IsEnabled = false;
+                            bar.Buttons.Add(backButton);
+
+
+                            fwdButton = new ApplicationBarIconButton();
+                            fwdButton.Text = "Forward";
+                            fwdButton.IconUri = new Uri("/Images/appbar.next.rest.png", UriKind.Relative);
+                            fwdButton.Click += new EventHandler(fwdButton_Click);
+                            //fwdButton.IsEnabled = false;
+                            bar.Buttons.Add(fwdButton);
+
+                            ApplicationBarIconButton closeBtn = new ApplicationBarIconButton();
+                            closeBtn.Text = "Close";
+                            closeBtn.IconUri = new Uri("/Images/appbar.close.rest.png", UriKind.Relative);
+                            closeBtn.Click += new EventHandler(closeBtn_Click);
+                            bar.Buttons.Add(closeBtn);
+
+                            page.ApplicationBar = bar;
+                        }
+
+                    }
+                }
+            });
+        }
+
+        void browser_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+
+        }
+
+        void fwdButton_Click(object sender, EventArgs e)
+        {
+            if (browser != null)
+            {
+                try
+                {
+                    //browser.GoForward();
+                    browser.InvokeScript("execScript", "history.forward();");
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+
+        void backButton_Click(object sender, EventArgs e)
+        {
+            if (browser != null)
+            {
+                try
+                {
+                    //browser.GoBack();
+                    browser.InvokeScript("execScript", "history.back();");
+                }
+                catch (Exception)
+                {
+
+                }
+            }
+        }
+
+        void closeBtn_Click(object sender, EventArgs e)
+        {
+            this.close();
+        }
+
+
+        public void close(string options = "")
+        {
+            if (browser != null)
+            {
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
+                    if (frame != null)
+                    {
+                        PhoneApplicationPage page = frame.Content as PhoneApplicationPage;
+                        if (page != null)
+                        {
+                            Grid grid = page.FindName("LayoutRoot") as Grid;
+                            if (grid != null)
+                            {
+                                grid.Children.Remove(browser);
+                            }
+                            page.ApplicationBar = null;
+                        }
+                    }
+                    browser = null;
+                    string message = "{\"type\":\"exit\"}";
+                    PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+                    result.KeepCallback = false;
+                    this.DispatchCommandResult(result);
+                });
+            }
+        }
+
+        void browser_Navigated(object sender, System.Windows.Navigation.NavigationEventArgs e)
+        {
+            //if (browser != null)
+            //{
+            //    backButton.IsEnabled = browser.CanGoBack;
+            //    fwdButton.IsEnabled = browser.CanGoForward;
+            //}
+            string message = "{\"type\":\"loadstop\", \"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+            PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+            result.KeepCallback = true;
+            this.DispatchCommandResult(result);
+        }
+
+        void browser_NavigationFailed(object sender, System.Windows.Navigation.NavigationFailedEventArgs e)
+        {
+            string message = "{\"type\":\"error\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+            PluginResult result = new PluginResult(PluginResult.Status.ERROR, message);
+            result.KeepCallback = true;
+            this.DispatchCommandResult(result);
+        }
+
+        void browser_Navigating(object sender, NavigatingEventArgs e)
+        {
+            string message = "{\"type\":\"loadstart\",\"url\":\"" + e.Uri.AbsoluteUri + "\"}";
+            PluginResult result = new PluginResult(PluginResult.Status.OK, message);
+            result.KeepCallback = true;
+            this.DispatchCommandResult(result);
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/f59ddbbd/lib/cordova-wp7/templates/standalone/Plugins/Media.cs
----------------------------------------------------------------------
diff --git a/lib/cordova-wp7/templates/standalone/Plugins/Media.cs b/lib/cordova-wp7/templates/standalone/Plugins/Media.cs
new file mode 100644
index 0000000..90c54f1
--- /dev/null
+++ b/lib/cordova-wp7/templates/standalone/Plugins/Media.cs
@@ -0,0 +1,532 @@
+/*  
+	Licensed under the Apache License, Version 2.0 (the "License");
+	you may not use this file except in compliance with the License.
+	You may obtain a copy of the License at
+	
+	http://www.apache.org/licenses/LICENSE-2.0
+	
+	Unless required by applicable law or agreed to in writing, software
+	distributed under the License is distributed on an "AS IS" BASIS,
+	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+	See the License for the specific language governing permissions and
+	limitations under the License.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Windows;
+using System.Diagnostics;
+
+namespace WPCordovaClassLib.Cordova.Commands
+{
+    /// <summary>
+    /// Provides the ability to record and play back audio files on a device. 
+    /// </summary>
+    public class Media : BaseCommand
+    {
+        /// <summary>
+        /// Audio player objects
+        /// </summary>
+        private static Dictionary<string, AudioPlayer> players = new Dictionary<string, AudioPlayer>();
+
+        /// <summary>
+        /// Represents Media action options.
+        /// </summary>
+        [DataContract]
+        public class MediaOptions
+        {
+            /// <summary>
+            /// Audio id
+            /// </summary>
+            [DataMember(Name = "id", IsRequired = true)]
+            public string Id { get; set; }
+
+            /// <summary>
+            /// Path to audio file
+            /// </summary>
+            [DataMember(Name = "src")]
+            public string Src { get; set; }
+
+            /// <summary>
+            /// New track position
+            /// </summary>
+            [DataMember(Name = "milliseconds")]
+            public int Milliseconds { get; set; }
+        }
+
+        /// <summary>
+        /// Releases the audio player instance to save memory.
+        /// </summary>  
+        public void release(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                if (!Media.players.ContainsKey(mediaOptions.Id))
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, false));
+                    return;
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        AudioPlayer audio = Media.players[mediaOptions.Id];
+                        Media.players.Remove(mediaOptions.Id);
+                        audio.Dispose();
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK, true));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Starts recording and save the specified file 
+        /// </summary>
+        public void startRecordingAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    mediaOptions.Src = optionsString[1];
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                if (mediaOptions != null)
+                {
+
+                    Deployment.Current.Dispatcher.BeginInvoke(() =>
+                    {
+                        try
+                        {
+                            if (!Media.players.ContainsKey(mediaOptions.Id))
+                            {
+                                AudioPlayer audio = new AudioPlayer(this, mediaOptions.Id);
+                                Media.players.Add(mediaOptions.Id, audio);
+                                audio.startRecording(mediaOptions.Src);
+                            }
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                        }
+                        catch (Exception e)
+                        {
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                        }
+
+                    });
+                }
+                else
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                }
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Stops recording and save to the file specified when recording started 
+        /// </summary>
+        public void stopRecordingAudio(string options)
+        {
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            audio.stopRecording();
+                            Media.players.Remove(mediaId);
+                        }
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            }
+        }
+
+        public void setVolume(string options) // id,volume
+        {
+            try
+            {
+                string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                string id = optionsString[0];
+                double volume = double.Parse(optionsString[1]);
+
+                if (Media.players.ContainsKey(id))
+                {
+                    Deployment.Current.Dispatcher.BeginInvoke(() =>
+                    {
+                        try
+                        {
+                            AudioPlayer player = Media.players[id];
+                            player.setVolume(volume);
+                        }
+                        catch (Exception e)
+                        {
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                        }
+                    });
+                }
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into setVolume method"));
+                return;
+            }
+        }
+
+        // Some Audio Notes:
+        // In the Windows Phone Emulator, playback of video or audio content using the MediaElement control is not supported.
+        // While playing, a MediaElement stops all other media playback on the phone.
+        // Multiple MediaElement controls are NOT supported
+
+        // Called when you create a new Media('blah') object in JS.
+        public void create(string options)
+        {
+            // Debug.WriteLine("Creating Audio :: " + options);
+            try
+            {
+                MediaOptions mediaOptions;
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    mediaOptions.Src = optionsString[1];
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Error parsing options into create method"));
+                    return;
+                }
+
+                AudioPlayer audio = new AudioPlayer(this, mediaOptions.Id);
+                Media.players.Add(mediaOptions.Id, audio);
+                DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Starts or resume playing audio file 
+        /// </summary>
+        public void startPlayingAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    mediaOptions.Src = optionsString[1];
+                    if (optionsString.Length > 2 && optionsString[2] != null)
+                    {
+                        mediaOptions.Milliseconds = int.Parse(optionsString[2]);
+                    }
+
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                AudioPlayer audio;
+
+                if (!Media.players.ContainsKey(mediaOptions.Id))
+                {
+                    audio = new AudioPlayer(this, mediaOptions.Id);
+                    Media.players[mediaOptions.Id] = audio;
+                }
+                else
+                {
+                    Debug.WriteLine("INFO: startPlayingAudio FOUND mediaPlayer for " + mediaOptions.Id);
+                    audio = Media.players[mediaOptions.Id];
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        audio.startPlaying(mediaOptions.Src);
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+
+        /// <summary>
+        /// Seeks to a location
+        /// </summary>
+        public void seekToAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    string[] optionsString = JSON.JsonHelper.Deserialize<string[]>(options);
+                    mediaOptions = new MediaOptions();
+                    mediaOptions.Id = optionsString[0];
+                    if (optionsString.Length > 1 && optionsString[1] != null)
+                    {
+                        mediaOptions.Milliseconds = int.Parse(optionsString[1]);
+                    }
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaOptions.Id))
+                        {
+                            AudioPlayer audio = Media.players[mediaOptions.Id];
+                            audio.seekToPlaying(mediaOptions.Milliseconds);
+                        }
+                        else
+                        {
+                            Debug.WriteLine("ERROR: seekToAudio could not find mediaPlayer for " + mediaOptions.Id);
+                        }
+
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+
+        /// <summary>
+        /// Pauses playing 
+        /// </summary>
+        public void pausePlayingAudio(string options)
+        {
+
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            audio.pausePlaying();
+                        }
+                        else
+                        {
+                            Debug.WriteLine("ERROR: pausePlayingAudio could not find mediaPlayer for " + mediaId);
+                        }
+
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+
+
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            }
+
+
+        }
+
+
+        /// <summary>
+        /// Stops playing the audio file
+        /// </summary>
+        public void stopPlayingAudio(String options)
+        {
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            audio.stopPlaying();
+                        }
+                        else
+                        {
+                            Debug.WriteLine("stopPlaying could not find mediaPlayer for " + mediaId);
+                        }
+
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.OK));
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+            }
+        }
+
+        /// <summary>
+        /// Gets current position of playback
+        /// </summary>
+        public void getCurrentPositionAudio(string options)
+        {
+            try
+            {
+                string mediaId = JSON.JsonHelper.Deserialize<string[]>(options)[0];
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    try
+                    {
+                        if (Media.players.ContainsKey(mediaId))
+                        {
+                            AudioPlayer audio = Media.players[mediaId];
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getCurrentPosition()));
+                        }
+                        else
+                        {
+                            DispatchCommandResult(new PluginResult(PluginResult.Status.OK, -1));
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+                    }
+                });
+            }
+            catch (Exception)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                return;
+            }
+        }
+
+
+        /// <summary>
+        /// Gets the duration of the audio file
+        /// </summary>
+        
+        [Obsolete("This method will be removed shortly")]
+        public void getDurationAudio(string options)
+        {
+            try
+            {
+                MediaOptions mediaOptions;
+
+                try
+                {
+                    mediaOptions = JSON.JsonHelper.Deserialize<MediaOptions>(options);
+                }
+                catch (Exception)
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
+                    return;
+                }
+
+                AudioPlayer audio;
+                if (Media.players.ContainsKey(mediaOptions.Id))
+                {
+                    audio = Media.players[mediaOptions.Id];
+                }
+                else
+                {
+                    Debug.WriteLine("ERROR: getDurationAudio could not find mediaPlayer for " + mediaOptions.Id);
+                    audio = new AudioPlayer(this, mediaOptions.Id);
+                    Media.players.Add(mediaOptions.Id, audio);
+                }
+
+                Deployment.Current.Dispatcher.BeginInvoke(() =>
+                {
+                    DispatchCommandResult(new PluginResult(PluginResult.Status.OK, audio.getDuration(mediaOptions.Src)));
+                });
+            }
+            catch (Exception e)
+            {
+                DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, e.Message));
+            }
+        }
+    }
+}