7zip Helper Batch File

7zip is an open source archive utility. 7zip has a nice GUI to create basic archive but you need to switch to command line if you want to include/exclude folders. It is boring to type same command repetitively if you have to take zipped backup periodically.

This tiny little batch file (backup.bat) creates password protected 7z archive of the specified folders in the folder where it resides. You don’t type your password in the batch file so you don’t give away the password. You can also specify names of the folder you want to exclude from the archive. As an example, by default, backup.bat archives folders named – Source & doc, and excludes bin,obj, and temp/test folders (see customization section below to know how to change).

Usage

Copy backup.bat file in the folder which has the subfolders you want to archive. Navigate to the folder in explorer and open command prompt in the same folder (shift+right click > Open command prompt here…) . Type backup.bat at the command prompt and follow the instructions. Pay attention to instructions which appear on your screen.

Requirements

7zip (http://www.7-zip.org/)
Powershell (Windows7 up, all versions have powershell by default)
7zip executable path in global path variable
Screenshot (19)

Customize

Following is the default 7zip command in the batch file –

7z.exe a -t7z yyyymmddhhmm_filename.7z Docs source -mhe=on -p%password% -xr!bin -xr!obj -x!temp/test

“Docs Source” specify the two folders – docs and source, to archive. You can add/change folders to include here. “-xr!bin -xr!obj -x!temp/test” specify 3 folders to exclude from archive – bin, obj, and temp/test. “r” switch in obj and bin denotes that bin and obj folder could be anywhere in the folder structure.

C# | .NET : Smart Duration Class

C# | .NET : Smart Duration Class

[Originally posted on 11 October 13]

Sometimes you need to have start and end dates, validate whether these dates define valid duration, or determine overlapping duration/timespan in two given duration(s)? I wrote an MVVM ready, equitable, duration class which does all the above and a little more. :-). I call this class TimeDuration. Let’s go through the code of the class.

TimeDuration implements two interfaces,  IEquatable and INotifyPropertyChanged. In later parts we will see the implementation of methods for IEquatable, let’s see INotifyPropertyChanged implementation first.  It has System.ComponentModel and a PropertyChangedEventHandler type public event PropertyChanged. It has a private method onPropertyChanged with a return type void. The complete INotifyPropertyChanged implementation looks like this:

using System;
using System.ComponentModel;

namespace Demo.DateExtentions
{
    public class TimeDuration : IEquatable, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void onPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

The class encapsulate two basic information elements – start time and end time. To expose this information class has two public DateTime type properties; Start and End. To notify views when the basic information changes in VM the class calls onPropertyChanged method from inside settters of both these properties. The implementation code looks like this:

        DateTime start;
        DateTime end;
        public DateTime Start
        {
            get { return start; }
            set
            {
                if (start != value)
                {
                    start = value;
                    onPropertyChanged("Start");
                }
            }
        }
        public DateTime End
        {
            get { return end; }
            set
            {
                if (end != value)
                {
                    end = value;
                    onPropertyChanged("End");
                }
            }
        }

The class initializes DateTime structured in the constructor so that object based on this class is ready for use on initialization. Constructor looks like so:

        public TimeDuration()
        {
            start = new DateTime();
            end = new DateTime();
        }

(Fields could have been initialized at the time of defining the field and not have the constructor at all.)
Duration represents a time span, so TimeDuration class has a TimeSpan type public property named Duration. This property returns the difference of start and end times. Code is like this:

        public TimeSpan Duration { get { return end - start; } }

This part makes the class a smart duration class. TimeDuration is capable of telling intersecting duration/timespan between two given durations. Following figure illustrates intersecting durations:
DurationFigure

In the figure above AB, CD, EF, and GH represent durations. Class returns information regarding CB in the context of AB and CD, where starting part of CD overlaps with end part of AB. The method returns overlap duration if one duration completely falls inside of another duration, as in AB and EF, where EF completely lies inside AB. The third scenario is where tail part of one duration overlaps with head part of another duration as in AB and GH where overlap is occurring at AH. Following is the code to return appropriate type, TimeSpan or TimeDuration, after checking the intersection.

        public TimeSpan IntersectingSpan(TimeDuration other)
        {
            return getIntersection(other).Duration;
        }
        public TimeDuration IntersectingDuration(TimeDuration other)
        {
            return getIntersection(other);
        }
        private TimeDuration getIntersection(TimeDuration other)
        {
            if (this.Equals(other)) return this;
            DateTime iStart = this.Start < other.Start ? other.Start : this.Start;
            DateTime iEnd = this.End < other.End ? this.End : other.End;
            return iStart < iEnd ? new TimeDuration(iStart, iEnd) : new TimeDuration();
        }

IEquatable interface implementation:

        public bool Equals(TimeDuration compareWith)
        {
            return CompareWith.Start == this.Start && CompareWith.End == this.End;
        }
        public override int GetHashCode()
        {
            return _start.GetHashCode() ^ _end.GetHashCode();
        }

The entire SmartDuration class:

/*
 * Disclaimer
 * Unless otherwise noted, code snippets in this repository are licensed under a Creative Commons Attribution 4.0 International license (http://creativecommons.org/licenses/by/4.0/)
 * Please do not forget to credit if you choose to use code in any which way.  You can credit in any way you please as below:
        By Sanjay (https://sharpsnippets.wordpress.com/)
        By Sanjay (http://www.twitter.com/SanjayAtPilcrow)
 * Blog post about following code: http://wp.me/p2iWZr-4T
 * General Notes
 *      - This is working code, but not production code.
 *      - Code follows universal C# code convention but might not follow your company's internal convention.
 *      - Code is more of POC and thus does not have full exception handling and parameter checking.
 *      - If you choose to use the code in production, do re-code to make it production ready as per your org's engineering policy.
*/
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POCs.Sanjay.SharpSnippets.Dates
{
    public class TimeDuration : IEquatable, INotifyPropertyChanged
    {
        DateTime start;
        DateTime end;
        public DateTime Start
        {
            get { return start; }
            set
            {
                if (start != value)
                {
                    start = value;
                    onPropertyChanged("Start");
                }
            }
        }
        public DateTime End
        {
            get { return end; }
            set
            {
                if (end != value)
                {
                    end = value;
                    onPropertyChanged("End");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public TimeDuration()
        {
            start = new DateTime();
            end = new DateTime();
        }
        public TimeDuration(DateTime start, DateTime end)
        {
            start = start;
            end = end;
        }
        public bool IsValidDuration
        {
            get { return _start <= _end; }
        }
        public TimeSpan Duration { get { return end - start; } }
        public TimeSpan IntersectingSpan(TimeDuration other)
        {
            return getIntersection(other).Duration;
        }
        public TimeDuration IntersectingDuration(TimeDuration other)
        {
            return getIntersection(other);
        }
        private TimeDuration getIntersection(TimeDuration other)
        {
            if (this.Equals(other)) return this;
            DateTime iStart = this.Start < other.Start ? other.Start : this.Start;
            DateTime iEnd = this.End < other.End ? this.End : other.End;
            return iStart < iEnd ? new TimeDuration(iStart, iEnd) : new TimeDuration();
        }

        #region Equatable
        public bool Equals(TimeDuration compareWith)
        {
            return CompareWith.Start == this.Start && CompareWith.End == this.End;
        }
        public override int GetHashCode()
        {
            return _start.GetHashCode() ^ _end.GetHashCode();
        }
        #endregion //Equatable

        #region notify property changed
        private void onPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
        #endregion

    }
}

Find code on my GitHub repository.

 

C#|.NET Query String in Uri

C#|.NET Query String in Uri

In a not-so-basic-application you might have pages which are used for multiple similar purposes. You pass query string with many fields with multiple values between such pages (or web pages). In database driven apps, parameter values could be user generated and stored in the back-end and you pull more info from database on the basis of the value in query parameter. This is not the scenario of back-end driven app. This is more about “Field Names” and Values, which are part of the design and known to you while coding, and you want to manage them effectively and make the code more readable.

Let’s take an example:

You have a page in your app which loads different lists (ex: city, state, pin, salutation, etc.) and lets user select an item from the list. At different places in your app you pop this page up with required parameters to load appropriate items. The call to page looks something like this:

this.NavigationService.Navigate("/ListPicker.xaml?ListType=city",UriKind.Relative)

Let’s assume your page also has the ability for editing and you want to activate appropriate functionality (select only || edit). You would add one more parameter to your query, like so:

this.NavigationService.Navigate("/ListPicker.xaml?ListType=city&FormType=select",UriKind.Relative)

If you have many such pages, each have multiple fields and their multiple values, and you make calls to these pages from different places in your code, soon it will be very difficult to manage hard-coded query strings in Uri’s.

Here comes enum based solution:

We will have enums for fields and their values. For the purpose of this example we will keep single enum for fields and multiple enums for values for different fields. Let’s code
First define enums for fields and their values:

        internal enum QueryFields { ListPicker_FormType, ListPicker_ListType };
        internal enum ListTypes { City, States, Zip, Salutation };
        internal enum FormTypes { Select, Edit };

If you do not wish to be more detailed, you could simply build your Uri’s like so:

This.NavigationService.Navigate("/ListPicker.xaml?{0}={1}",QueryFields.ListPicker_FormType.ToString(), FormTypes.Select.ToString());
//The resultant uri - /ListPicer.xaml?ListPicker_FormType=Select

We will see below how you could parse query parameters in the called page and retrieve values in enum types.

Creating Uri as above still has string formatting which is not easy to maintain in multiple uses. To make things manageable and less error prone, let’s create a new enum for pages in the app and shift Uri building code in a single method which could be called from anywhere in the app with different field and values.

        internal enum AppPages {ListPicker, Setting, Main, etc };
        internal static Uri GetUri(AppPages appPage, params KeyValuePair<string, string>[] args)
        {
            string uriString = "";
            switch (appPage)
            {
                case AppPages.ListPicker:
                    uriString = "/Views/ListPicker.xaml";
                    break;
                case AppPages.Setting:
                    uriString = "/Views/Settings.xaml";
                    break;
                case AppPages.Main:
                    uriString = "/Main.xaml";
                    break;
                default:
                    uriString = "/Main.xaml";
                    break;
            }
            int counter = 0;
            string seperator = "?";
            foreach(KeyValuePair<string, string> query in args)
            {
                if (counter > 0) seperator = "&";
                uriString = String.Format("{0}{1}{2}={3}", uriString, seperator, query.Key, query.Value);
            }
            return new Uri(uriString, UriKind.Relative);
        }

With GetUri, you could create page navigation Uri with enums only instead of hard-coded strings:

            KeyValuePair<string, string> query_1 = new KeyValuePair<string,string>(QueryFields.ListPicker_FormType.ToString(), FormTypes.Select.ToString());
            KeyValuePair<string, string> query_2 = new KeyValuePair<string,string>(QueryFields.ListPicker_ListType.ToString(), ListTypes.City.ToString());
            This.NavigationService.Navigate(GetUri(AppPages.ListPicker, query_1, query_2));

Once you are navigated to your page, you need to parse query strings and extract enums which you could use in the page to decide page’s functionality.

At page level you need to have required enum type fields. For this example we will have two fields, one FormTypes type and other ListTypes type. A private processQuery method which accepts a dictionary sets these two fields appropriately.

        FormTypes formType;
        ListTypes listType;
        private void processQuery(Dictionary<string, string> query)
        {
            string _formTypeName = "";
            string _listTypeName = "";
            query.TryGetValue(QueryFields.ListPicker_FormType.ToString(), out _formTypeName);
            query.TryGetValue(QueryFields.ListPicker_ListType.ToString(), out _listTypeName);
            if (_formTypeName.Length != 0) formType = (FormTypes)(Convert.ToInt32(_formTypeName));
            if (_listTypeName.Length != 0) listType = (ListTypes)(Convert.ToInt32(_listTypeName));
        }

You would call processQuery method from OnNavigatedTo method of your page.

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            Dictionary<string, string> _params = new Dictionary<string, string>(NavigationContext.QueryString);
            processQuery(new Dictionary<string, string>());
        }

If you have 100’s of case statements (to choose a page) in GetUri, and you are concerned about performance, refactore the method to accept page name with path as string. With page path name directly in string, you would not need case statements. By the way, in my case with about 80+ cases to get PageName, the query creation does not take more than 50MS, which is negligible for me. More so, navigation calls are not recursive ones.

Accelerate App Reviews

Accelerate App Reviews

Asking for review in your app? It’s tricky. If not done with due diligence, on encountering your request to review, users might get annoyed and still worse, they could rate your app low even though they liked it. A simplistic solution of asking for review after N days from installation (or first use) and N days after user has chosen “remind me later”, is not an appropriate solution. Why? User might have installed your app, ran it, exited, came back after N days and they were presented with a review request message, whereas, they had only used the app once. This is not a nice experience. Asking for review when user is exiting the app is less effective because user already has something else in their mind when they are coming out of the app.

Though there is no one solution that fits all, but this is how I try to tackle this scenario in my app. It’s not the “number of days” but “total minutes user has used your app” is my criteria to decide the interval of popping review message. I keep a record of overall usage of the app, and after a designated number of minutes, I pop a request to user. You might have to go through some trial and error to come up with the right “number of minutes” when you want to request. Determine whether your app is highly immersive or a quick open and shut type of app. In an immersive app|game you might want your review requests at longer intervals. In a less immersive app, you would rather ask earlier and at a less frequency. Then, you might want to gradually decrease the interval between requests during session. Don’t forget to code your logic in such a way that you could easily tune request intervals and accumulative usage time and update your app as soon as you realize that a change in the times is required. Here is pseudo-code for indication purpose:


[THIS IS PSEUDO CODE FOR INDICATION ONLY]

constant int POP_REQUEST_AFTER_ACCUMULATIVE_USAGE (adjusting knob) 
constant int POP_REQUEST_INTERVAL (adjusting knob : Initial interval between requests in the session) 
constant int POP_REQUEST_INTERVAL_DECREASE_BY (adjusting knob : Decrease interval after every request) 
constant int POP_REQUEST_INTERVAL_MINIMUM (adjusting knob : interval should not go below this)

int AccumulativeAppUsage (persist this info in storage)
DateTime LastReviewRequest;
Int ReviewRequestInterval = POP_REQUEST_INTERVAL;

App.Start | App.Activate
	DateTime AppStart
	LastReviewRequest = DateTime.Now //reset

App.Stop | App.Deactivate
	AccumulativeAppUsage += DateTime.NOW – AppStart
	Save AccumulativeAppUsage

Page.[identify the event which triggers PopRequest method]
	PopRequest()

PopRequest()
	totalUsageTillNow = AccumulativeAppUsage += DateTime.NOW – AppStart
	if(totalUsageTillNow >= POP_REQUEST_AFTER_ACCUMULATIVE_USAGE)
	{
		If(DateTime.Now – LastReviewRequest >= ReviewRequestInterval)
		{
			Show review request
			LastReviewRequest = DateTime.Now
			If(ReviewRequestInterval > POP_REQUEST_INTERVAL_MINIMUM)
				ReviewRequestInterval -= POP_REQUEST_INTERVAL_DECREASE_BY
		}
	}

C#|.NET : Size String, Truncate Lines

Swiss Crop Circle 2009 Aerial by Kecko, on Flickr
Swiss Crop Circle 2009 Aerial, a photo by Kecko on Flickr.

I needed to truncate lines from CSV string prepared for export through mail in my app. Windows Phone mail restricts text size to 1MB. In my app’s case some CSV reports could go beyond 1MB. To make sure that the CSV report does not exceed a desired size in bytes, I created this extension method – SizeIt. SizeIt can truncate lines (and characters if required) from a given string from beginning or from end and also inserts information text line (how many lines and characters removed) in the resulting string. Following is the test form created to show what the method does to a string. In this example a 300 byte 10 line string is given as input and asked to reduce it to <200 bytes, first from beginning, and then from end.

SizeTail

SizeFront

Here is the code for the extension method:

    public static class StringBuilderExtensions
    {
        /// <summary>
        /// Sizes StringBuilder to given size
        /// </summary>
        /// <param name="sb">StringBuilder</param>
        /// <param name="bytes">Maximum Size of resultant string. Mostly the size of string will be less than max size</param>
        /// <param name="removeLinesFromBeginning">Pass true, if clipping has to happen in the beginning</param>
        public static void SizeIt(this StringBuilder sb, int bytes, bool removeLinesFromBeginning)
        {
            bool _stringReplacementHappened = false;
            bool _maxBytesAdjusted_for_lines = false;
            bool _maxBytesAdjusted_for_chars = false;
            string _insertThismessage = "";
            int _linesRemoved = 0;
            int _charsRemoved = 0;
            //try removing lines.
            while (System.Text.Encoding.Unicode.GetByteCount(sb.ToString()) > bytes)
            {
                char _alternateNewLine = '\r';
                string _workingString = sb.ToString();
                if (!_workingString.Contains(Environment.NewLine) && !_workingString.Contains(_alternateNewLine))
                {
                    break;
                }
                int _newlinelocation = sb.ToString().IndexOf(Environment.NewLine);
                int _lastNewlinelocation = sb.ToString().LastIndexOf(Environment.NewLine);
                if (_newlinelocation <= 0)
                {
                    _newlinelocation = sb.ToString().IndexOf(_alternateNewLine);
                }
                if (_lastNewlinelocation <= 0)
                {
                    _lastNewlinelocation = sb.ToString().LastIndexOf(_alternateNewLine);
                }

                if (removeLinesFromBeginning)
                {
                    sb = sb.Remove(0, _newlinelocation + 1);
                    _linesRemoved++;
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("... {0} lines removed{1}", _linesRemoved, Environment.NewLine);
                }
                else
                {
                    int _lastReturnAt = _lastNewlinelocation;
                    int _charsInLastLine = sb.Length - _lastNewlinelocation;
                    sb = sb.Remove(_lastReturnAt, _charsInLastLine);
                    _linesRemoved++;
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("{1}{0} lines removed...", _linesRemoved, Environment.NewLine);
                }
                if (!_maxBytesAdjusted_for_lines)
                {
                    bytes -= 50; //40 extra bytes for information text
                    _maxBytesAdjusted_for_lines = true;
                }
            }
            //if it's still more than the desired size
            if (System.Text.Encoding.Unicode.GetByteCount(sb.ToString()) > bytes)
            {
                int _currentBytes = System.Text.Encoding.Unicode.GetByteCount(sb.ToString());
                if (!_maxBytesAdjusted_for_lines)
                {
                    bytes -= 100;
                    _maxBytesAdjusted_for_lines = true;
                    _maxBytesAdjusted_for_chars = true;
                }
                else if (!_maxBytesAdjusted_for_chars)
                {
                    bytes -= 50;
                    _maxBytesAdjusted_for_chars = true;
                }
                int _removeChars = (_currentBytes - bytes) / 2;
                if (removeLinesFromBeginning)
                {
                    sb = sb.Remove(0, _removeChars);
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("... {0} lines and {1} chars removed{2}", _linesRemoved, _removeChars, Environment.NewLine);
                }
                else
                {
                    sb = sb.Remove(sb.Length - _removeChars, _removeChars);
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("{2}{0} lines and {1} chars removed...", _linesRemoved, _removeChars, Environment.NewLine);
                }
            }
            if (_stringReplacementHappened)
            {
                if (removeLinesFromBeginning)
                {
                    sb.Insert(0, _insertThismessage);
                }
                else
                {
                    sb.Append(_insertThismessage);
                }
            }
        }
    }

You may extend SizeIt to make it even smarter because it has following shortcomings in current version:

  • Does not truncate very closely to Max size. Will always be less than 50 bytes from max.
  • If there are only two lines and line of truncating side is huge, even a slight reduction in size will remove the complete content of the huge line, meaning loosing most of the text. This could be taken care of by firsts analyzing the string and then truncating line/character, as required
  • The logic inherently tries to remove lines first, should intelligently decide whether to remove line or chars.

Navigation Hierarchy

Avirall Time Suite is an extensive app with 60,000+ working LOC in .cs files. I have not calculated the lines of code in XAML because a major portion of them are auto-generated. Still, there is about same number of lines in XAML files, as well. Avirall has 15 pages and 3 of them have about 5 types, so in all about 30 pages show up in Avirall. During documentation I created a high level diagram of navigation hierarchy in the app. I think it gives a bird’s eye view of how the app’s control flow, kind of circulatory system. This is how it looks like :

MTTHNavigation

UI | UX By & For Dev : User Focus

UI | UX By & For Dev : User Focus

As a developer, if I need to pick a concept which I find most important in deciding the placement of information, then it is the user focus areas on screen. You want your users to find more important information swiftly so you keep those elements in the areas of the screen which get more focus and keep less important elements in areas which are less intrusive during user scanning the page. Have a look at following imaginary compartmentalization of screen areas:

Sufrace Pro 3 Screen Elements Placement UX UI

Green dots represent user focus. So, 1,2 and 5 are the areas which are going to get most focus of user. Then come 3, 6, and 9. And the least focus grabbing areas are 4, 7 and 8. The arrows show the shifting of user gaze while they are scanning your app’s page. This shifting of gaze is closely related to the focus areas. User’s focus shifts in this sequence (not very strictly but generally)
1 > 2 > 5 > 3 > 6 > 9 > 4 > 8 > 7.

This can be a great guide to plan control/element placement in your app.

Microsoft Visual Layout Guide