29 Mar 2015

Auto-properties with initializers (C# 6)

C# 6

A big design trend in C# 6 is the removal of ceremony from code. Ceremony is the amount of code you need to write, to write the code that actually matters. It is the fluff that is there because it is needed by C# and not to solve your problem. Auto-properties are a great example of removal of ceremony & in C# 6 they have been improved further.

In C# 1 we would would type out the full property with the getter & setter and a field. One nice feature is you could initialise the value the field, thus giving the property a default value. For example, like this:

private int csharpOne = 42;

public int CSharpOne
{
    get { return csharpOne; }
    set { csharpOne = value; }
}

In C# 2 we got the (syntactic sugar) feature for one line properties. The compiler though would generate the field, the getter and the setter automatically in the compiled code. However, the loss of the field, meant the only way to assign a default value was in the constructor, as in the following example:

public int CSharpTwo { get; set; }

public AutoProperties()
{
    CSharpTwo = 42;
}

On one hand, the single line property is great and is an example of less ceremony adding readability, but when we need to assign a default value we add more ceremony and ultimately increase complexity and the potential for errors because there is no obvious way to see the constructor is assigning a value unless you go and check it.

C# 6 simplifies solves this with a new syntax to assign a default value:

public int CSharpSix { get; set; } = 42;

That is pretty awesome!

Tags: 
29 Mar 2015

Exceptions: What happens when an exception occurs inside a catch or inside a when (C# 6) & how smart is the compiler with whens which have a constant expressions or whens with duplicate expressions?

C# 6

Exceptions, the bit of code that makes everything break! Here are some interesting thoughts around how exceptions work, which were brought up during a recent presentation I gave on C# 6.

Note: Based on VS 2015 CTP 6, this may change by RTM.

Exceptions in a catch block

Starting off, let us look at what happens if you raise an exception in the catch block of a try…catch? This isn’t anything new to C# 6, but it is worth a recap.

public static void OldPain()
{
    try
    {
        throw new MyException { Id = 200 };
    }
    catch (MyException ex)
    {
        throw new Exception("WHAT");
    }
}
In this scenario, the first exception (MyException) is caught and then the second exception is raised. Since there is no try…catch for the second exception, it runs normally and bubbled up until it is either caught higher up or the app crashes. In this example that means an exception of type Exception will be raised.

What if we add a catch all?

As a slight variation, what happens if you add another catch below the first one? Does the second catch, catch the exception raised in the first catch block? For example:

public static void OldPain()
{
    try
    {
        throw new MyException { Id = 200 };
    }
    catch (MyException ex)
    {
        throw new Exception("WHAT");
    }
    catch (Exception ex)
    {
        // stuff
    }
}

Nope, not at all. It exits the entire try…catch scope and, so that second catch does nothing for what we are testing. In the example above, that means an exception of type Exception will be raised, same as with the first scenario.

Exceptions in When

C# 6 adds the when keyword which allows us to add a filter to our catch blocks. This feature is called Exception Filters & you may find articles using IF as the keyword, but that has changed to WHEN. Prior to C# 6, the condition to run a catch block was just the exception type. Now with C# 6, it is the exception type and, optionally, the result of the when expression. So what happens if the when expression raises an exception? For example:

public static bool Test()
{
    throw new Exception("WHAT!");
}

public static void OldPain()
{
    try
    {
        throw new MyException { Id = 200 };
    }
    catch (MyException ex)
    when (Test())
    {
    }
}

I assumed it would work in a similar way to the exceptions inside the catch block we looked at above. I was wrong. Any exception in the when condition is swallowed up! In this example, the MyException will be raised since there is no catch block which can handle it as the when has failed due to the exception being raised in test.

What if we add a catch all?

As with the first example, does adding a second catch…block here change the behaviour?

public static bool Test()
{
    throw new ApplicationException("WHAT!");
}

public static void OldPain()
{
    try
    {
        throw new MyException { Id = 200 };
    }
    catch (MyException ex)
    when (Test())
    {
    }
    catch (ApplicationException ex)
    {
        // will this be run?
    }
}

No, this scenario runs the same as before, a MyException is raised.

Constant Whens

What happens if the when expression is a constant? Is the compiler smart enough to optimise the code? To work this out I used the AMAZING .NET Reflector which means I can compare the original code, the IL which was generated and the code which was reflected back from the IL.

Starting off with the standard filter, here is what it  looks like across places. I suspect the reflected code is showing ? since the version of reflector out currently doesn’t support this.

image

Let us change the condition to be always true. Thankfully Visual Studio will detect this and warn you:

image

But what is the result of compiler?

image

It is pretty much the exact same there, with the filter existing in the IL still :/ Checking with false (and also release builds) shows no difference in any scenario :/

Duplicate whens

The last set of scenarios are around for duplicate when clauses, for example below we have two catch blocks which are the same and I know from running this that only the first one is executed.

public static void OldPain()
{
    try
    {
        throw new MyException { Id = 200 };
    }
    catch (MyException ex)
    when (ex.Id == 200)
    {
    }
    catch (MyException ex)
    when (ex.Id == 200)
    {
    }
}

And from checking the generated IL, both catches are in there too. So no optimisation around this.

As a final mad scientist idea, what if the first catch changes the condition to one the second catch can handle? Will that allow both to run? For example:

public static void OldPain()
{
    var canCatch = true;
    try
    {
        throw new MyException { Id = 200 };
    }
    catch (MyException ex)
    when (canCatch)
    {
                canCatch = false;
    }
    catch (MyException ex)
    when (!canCatch)
    {
    }
}
The answer, is nope. Once one catch handles it the rest are ignored. 
I hope you find this new syntax interesting and if you have any questions, please post them in the comments!
Tags: 
29 Mar 2015

Index Initialisers (C# 6)

C# 6

C# 6 adds in a new feature which is called Dictionary Initialisers or Index Initialisers, because of how they work internally.  In fact, the C# team can’t get it straight with roadmap page referring to dictionary while the feature description document, referring to index. While we wait for the name to be decided, what is an index initialiser and how does it work internally?

Note: This is based on VS 2015 CTP 6 and thus may change.

Adding to collections in C# 2

In C# 2 the only way we could add to a collection was with the methods provided by the collection, normally add. For example, below we are adding to a dictionary and an list using the C# 2 way.

public static void CSharp_Two_Dictionary()
{
    var config = new Dictionary<int, string>();
    config.Add(1, "hi");
    config.Add(2, "how are you");
    config.Add(3, "i am fine");
    config.Add(4, "good bye");
    foreach (var item in config)
    {
        Console.WriteLine("{0} = {1}", item.Key, item.Value);
    }
}

public static void CSharp_Two_List()
{
    var config = new List<string>();
    config.Add("hi");
    config.Add("how are you");
    config.Add("i am fine");
    config.Add("good bye");
    foreach (var item in config)
    {
        Console.WriteLine(item);
    }
}

Collection Initialisers in C# 3

C# 3 added support for collection initialisers, where we can use braces to add the items. When using collection initialisers, the parentheses for the constructor become optional - for the example below I have omitted them.

This is just syntactic sugar, i.e. the compiler is rewriting this to use the Add method of the collection. In short it ends up the same as the example above when it is run - it is just easier and less error prone to type using collection initialisers.

The requirements collection initialisers to work are::

  1. The collection class must implement IEnumerable.
  2. The collection class must have an add method. Almost uniquely for .NET there is no interface required, it is merely the name of the method and that it must take, at least, one parameter.
public static void CSharp_Three_Dictionary()
{
    var config = new Dictionary<int, string>
    {
        { 1, "hi" },
        { 2, "how are you" },
        { 3, "i am fine" },
        { 4, "good bye" },
    };

    foreach (var item in config)
    {
        Console.WriteLine("{0} = {1}", item.Key, item.Value);
    }
}

public static void CSharp_Three_List()
{
    var config = new List<string>
    {
        "hi",
        "how are you",
        "i am fine",
        "good bye",
    };

    foreach (var item in config)
    {
        Console.WriteLine(item);
    }
}

Index Initialisers in C# 6

C# 6 adds a new syntax option to add items to collections, where we can add items to collections in a slightly different way:

public static void CSharp_Six_Dictionary()
{
    var config = new Dictionary<int, string>
    {
        [1] = "hi",
        [2] = "how are you",
        [3] = "i am fine",
        [4] = "good bye",
    };

    foreach (var item in config)
    {
        Console.WriteLine("{0} = {1}", item.Key, item.Value);
    }
}

public static void CSharp_Six_List()
{
    // note: this will error
    var config = new List<string>
    {
        [1] = "hi",
        [2] = "how are you",
        [3] = "i am fine",
        [4] = "good bye",
    };

    foreach (var item in config)
    {
        Console.WriteLine(item);
    }
}

In the above example you’ll note that we use similar syntax to the collection initialiser (use of brace, optional use of constructor parenthesis) but the way we add items is different. We use brackets to define the index, followed by equals and the value. Internally this is different to collection initialisers since the generated code does NOT use the add method, rather it uses the collections indexer. For example, this is what the generated code the above index initialiser example would look like:

public static void CSharp_Six_Dictionary_Generated()
{
    var config = new Dictionary<int, string>();
    config[1] = "hi";
    config[2] = "how are you";
    config[3] = "i am fine";
    config[4] = "good bye";

    foreach (var item in config)
    {
        Console.WriteLine("{0} = {1}", item.Key, item.Value);
    }
}

public static void CSharp_Six_List_Generated()
{
    // note: this will error
    var config = new List<string>();
    config[1] = "hi";
    config[2] = "how are you";
    config[3] = "i am fine";
    config[4] = "good bye";

    foreach (var item in config)
    {
        Console.WriteLine(item);
    }
}

Since the compiler is generating code with indexers, the ONLY requirement for the class being added is that the class it must have an indexer and the indexer has which has a setter method. This means it can be used on anything which supports indexers. There is NO requirement that this can only be used with collections or things which support IEnumerable.

In the above example the List example will fail and the Dictionary will pass because of the subtle differences in how their indexers work. A dictionary uses the setter on the indexer as the key and will add the item if needed, while a list uses the setter on its indexer as a position and if the list doesn’t have a collection with that size it will fail with an exception.

Example non-collection usage

As mentioned this can be used outside a collection, so let us build a bit of code to assign the four roles to a team.

NOTE: This is an example, it is not meant as guidance for how you should do it. Personally, I think the end example is better handled by a constructor.

In C# 2 we may have done it like this:

public static void C_Sharp_Two_Set_Members()
{
  // code to add team members
    var team = new Team();
    team.ScrumMaster = new Member("Jim");
    team.ProjectOwner = new Member("Sam");
    team.DevLead = new Member("Phil");
    team.Dev = new Member("Scott");
}

// we will exclude role from future examples since it doesn't change in the other examples
enum Role
{
    ScrumMaster,
    ProjectOwner,
    DevLead,
    Dev
}

class Team
{
    public Member ScrumMaster { get; set; }
    public Member ProjectOwner { get; set; }
    public Member DevLead { get; set; }
    public Member Dev { get; set; }
}
// we will exclude member from future examples since it doesn’t change in the other examples
class Member
{
    public Member(string name)
    {
        Name = name;
    }

    
    public string Name { get; }
}

With C# 3 we could change this to use an object initialiser, which ultimately generates the exact same code as in C# 2:

// rest of example code remains the same
public static void C_Sharp_Three_Object_Initialiser()
{
    var team = new Team
    {
        ScrumMaster = new Member("Jim"),
        ProjectOwner = new Member("Sam"),
        DevLead = new Member("Phil"),
        Dev = new Member("Scott"),
    };
}

The one requirement for both examples is that the properties have accessible setter methods, or it will not work, so we cannot use either option with private setters for example. We could use an indexer in this scenario by adding it to the Team class and then being able to use Index initialiser syntax to assign the roles.

public static void C_Sharp_Six_Index_Initialiser()
{
    var team = new Team
    {
        [Role.ScrumMaster] = new Member("Jim"),
        [Role.ProjectOwner] = new Member("Sam"),
        [Role.DevLead] = new Member("Phil"),
        [Role.Dev] = new Member("Scott"),
    };
}


class Team
{
    public Member this[Role role]
    {
        get
        {
            switch (role)
            {
                case Role.ScrumMaster:
                    return this.ScrumMaster;
                case Role.ProjectOwner:
                    return this.ProjectOwner;
                case Role.DevLead:
                    return this.DevLead;
                case Role.Dev:
                    return this.Dev;
            }

            throw new IndexOutOfRangeException();
        }
        set
        {
            switch (role)
            {
                case Role.ScrumMaster:
                    {
                        this.ScrumMaster = value;
                        break;
                    }
                case Role.ProjectOwner:
                    {
                        this.ProjectOwner = value;
                        break;
                    }
                case Role.DevLead:
                    {
                        this.DevLead = value;
                        break;
                    }
                case Role.Dev:
                    {
                        this.Dev = value;
                        break;
                    }
            }
        }
    }
    public Member ScrumMaster { get; private set; }
    public Member ProjectOwner { get; private set; }
    public Member DevLead { get; private set; }
    public Member Dev { get; private set; }
}

Hopefully this explains the new syntax in C# 6 and gives you good ideas on where and how it works. If you have any ideas of how Index Initialisers could be used, let me know in the comments below!

Tags: 
26 Mar 2015

We need your help!

The Developer User Group is running it’s annual survey. It is short and will help us a lot with regards to planning and ensuring we provide you with the best experience. PLEASE give us 3 min of your time to complete it: http://bit.ly/dugSurvey2015

Tags: 
20 Mar 2015

Slides from my DevDay (March 2015) talks!

First off, let me thank everyone who attended – this was one of the best events I’ve been involved in and that is all down to the great audiences we had. Not only was it fun and exciting but I learnt so much from all of you around the various pieces of technology you use and frustrations of it.

Sharp Sharp with C# 6

This is one of my favourite talks I’ve ever given. I don’t think I have ever laughed as much on stage as I did with this talk.

You can find the starting code for this on GitHub

Putting the “DOT” into .NET – Dev, Ops & Test

For Johannesburg audiences, this will look a lot different. I got so much amazing feedback & ideas that I did a lot of work on polishing and structuring it better and I am very proud of the final outcome. It still is a long talk which covers a lot (too much maybe) but it is one that I think stimulates a lot of ideas & nudges people on a very important path.

Tags: 
09 Mar 2015

CSS Media Queries + Visual Studio = Easy

CSS media queries used to scare me. The problem is that I know CSS, but media queries look so much more complex & having to rely on browser tools to help get them correct was never a great experience. Thankfully Visual Studio + Web Essentials has made great strides in making using media queries easier to use, so much so that now that I think they are kinda boring and I need a new thing to scare me… like closure Winking smile

Snippets

imageWeb Essentials has snippets for CSS media queries, and these are a great help. First there is the @media snippet which will get you setup with a basic media query. The real power though is in the device specific ones that produce a the right set of CSS & takes a lot of the searching for the right settings away.

Browser Link

I have demo’d browser link many times & written about it before – it is awesome. It gives ANY browser the ability to have a two way connection with Visual Studio. That means the browser can send data to Visual Studio, useful for detecting things that only happen when you render the DOM. Browser Link + Visual Studio can also send data to the browser, for example telling the browser to refresh because the page has changed. Since it works with ANY browser, you can have multiple browsers open and work with all of them at once. Browser link isn’t an ASP.NET feature, it is a web + Visual Studio feature, so if you are using PHP or pure HTML (like I do in the video below) it just works.

For media queries, browser link can read the browser dimensions into Visual Studio, this means all you need to do is set the browser to the right size & press Ctrl+Space on the right property of the media query and it will show you the dimension the browser is at that very moment! It means that getting the exact right size of the browser window for sizing is trivial, since you can work visually in your browser and have all the power in your tools.

Check out this video for how it works!

Have you got any awesome features in Visual Studio that are kinda hidden? Share them in the comments.

Tags: 
06 Mar 2015

The one that got away: A Windows Phone bug that can not be solved

Clipboard01A project I was recently working on ran up against an interesting bug and, unfortunately, it was a bug we had to ship the app with in the end. My main reason for sharing this is in the hope that should you find this same bug that you know you are not alone and maybe it gives you some ideas what you can do. Not only did we find this bug, but we have been able to confirm this happens to a number of other apps in the store.

The Issue

The app itself is an audio streaming app, except it is not real streaming, it is actually HTTP progressive downloading and playing the file as it downloads. The problem we had is that when it finished playing one file, it would not load the next file. Part of the pain for us is that this is a pretty hard scenario to identify as it has these requirements for the bug to raise it’s ugly head:

  1. It is related to network only. If the file was on disk already it would work every time.
  2. It only happens when on battery. Plug the phone in or the emulator (which is always “plugged-in”) and it won’t show the issue.
  3. The screen must be locked & off. Any interaction with the device causes the problem not to appear.
  4. If it is playing a file, it will finish that file fine. The issue only happens when we skip to the next file
  5. It will not raise any errors or exceptions – it just silently does not play the next file.
  6. This is using background audio, so it is not that the app is being suspended.

We tried everything as a team and could not solve it, so we escalated to Windows phone support. This was the first time I dealt with premier Windows phone dev support, and while they cost a lot, they know their stuff and could help out to confirm out understanding and give us some ideas to work around the problem.

Root Cause

The cause is this: when the phone is on battery and there is no interaction, the phone lowers the signal strength of the antennas. This is to save battery, but it also means that your HTTP connections could be too slow to work properly and so the audio won’t play.

Workarounds

This does not seem to happen with the Windows Phone 8.0 Silverlight apps, which have a different way of handling background audio, however moving from Universal apps to that maybe too costly (it was for us). The other option is to use real streaming and it is less impacted by this and also you can do a lot of smart server side stuff to ensure it keeps running.

Future

This happened on Windows phone 8.1 and it looks like it still happens on Windows 10 for phone. The official response is “by design”, although I think it is more a unexpected side effect of a number of design decisions; but it could change. If you think it should change, please vote on the user voice item for this so that the product team can see enough people care about resolving it.

Tags: 
05 Mar 2015

What is in your bag?

DSC_9406The developers I know who refer to themselves as “craftsman” will, at length, tell you how methodology, principals & practise are all that matters to becoming a successful developer – tools are not important. Often they say that from behind a Mac Book Air, running Visual Studio with Resharper or some other combination of best of breed tooling. None of them code in notepad oddly.

Everyone really does care about their tools and I am totally behind the idea that you are more than your tools, but good tools help which is why I want to share what is in my bag and why it is there.

Daily Driver

DSC_9409

My daily development machine is a Lenovo Thinkpad T440s – it is the best machine I’ve ever worked on. Weight? It is basically air. It handles app & web dev with no issue. Has a backlit keyboard that is turned off 95% of the time but in those rare moments of darkness, I can turn it on with a keyboard combination. Great performance overall. The touchpad is the best I’ve ever seen, and considering I think touchpads are evil, that says a lot.

One thing that really stands out is the touch screen – I can’t imagine modern development being done without one. It is essential for testing on web & apps.

Why do I carry it?

Simple – it is what I use to do my job! Smile with tongue out and it gives me a place to put stickers.

Audio Out

DSC_9413DSC_9416DSC_9426

I carry three sets of headphones with me. My primary ones are a set of super comfy large Steel Series ones. They have a built in mic, which is serviceable but since the laptop doesn’t have an audio in jack there isn’t much use. Thankfully the mic slides into the headphones so it is never in the way. When you have headphones on for hours, comfy wins for me and these are them.

I also carry a, company supplied, Jabra headset. This has a USB connection so the audio in works plus it is designed to work with Lync – so it has a bunch of cool tricks on the control dial. Not great for comfort or quality, but for a meeting where I want to keep my hands on the keyboard it is okay.

Last is my tiny Sennheisers – these don’t get used often as they are the backup. 

Both my sets have something to wrap the cables with – the big ones using the fantastic apple core which I got at JSinSA.

Why do I carry it?

You need to focus, and having music or podcasts will help. It also means less disturbance to your co-workers.

The issue with large headphones I use at home & work is I may leave them at home and then could be stuck with no audio the next day; so the small Sennheisers run as backup for me. This means they seldom leave the bag but having a small high quality backup has come in handy many times.

Audio In

DSC_9440

I have a small Samson mic that connects via USB. The audio quality is okay. Considering it is a sub R900 ($90) mic it is pretty good for that price range and it is a million times better than the laptops built in offering. It has three nice features, first a clip/stand/base. In the picture it is standing on it’s base, which it can fold flat on to. It can also use the clip to attach to the top of the laptop screen as the mic is on a ball joint and swivel pretty much to any direction (check the link for it, they show off that really well). This stand gives it so much versatility.

Second is the switch on the side, which lets it switch from front facing only to a omni directional mic. The omni directional mic is great for the daily standups where the team & client may not be together, as it gets a lot more audio into the conversation.

Last is the cable, it is stupid long – we often pass it around during the stand ups & it handles the length of our boardroom table with ease.

Why do I carry it?

Meetings; be they a stand up or more formal meeting, having something to capture audio is an essential for a modern developer.

Storage

DSC_9438DSC_9460

Nothing too fancy here. A large Seagate, mostly for backups. I also have a tiny plastic box which contains a LOT of USB sticks. Since I switched to carrying the USB sticks in a box, I lose less of them so now I have an issue of having too many… if that could ever happen.

Why do I carry it?

You will lose data. Have backups. Simple as that.

The USB sticks are great for sharing stuff & if they break or get lost there is no issue.

Mouse

DSC_9447

I’ve written about my mouse before, (and it is the exact same mouse still - it is 6 years old now) and I stand by that – the Logitech Performance Mouse MX is the best mouse you can get & you owe it to your hands to be happy.

Why do I carry it?

Touch pad and touch screen do not beat the performance a real mouse will bring.

Bags

DSC_9429

My laptop bag is a Targus (it isn’t exactly that bag, but it is close). The bag isn’t anything special but Targus as a company is. With my last Targus bag, the zip broke (from squeezing too much in) and all they wanted to ship me a new bag for free was a photo and the service tag removed. They believe their bags will last and they are prepared to back it up that belief. That one interaction has made me a very loyal customer.

I also have some smaller bags worth mentioning:

  • First is a Targus hard drive bag, nice and padded. It fits the hard drive, its USB cable and my small headphones easily.
  • Second is the hard shell case which the Samson mic came with. It is great but had no space for the cable (which is a stupid oversight). Thankfully my last Samson mic came with a bag, so the cable and mic/shell go in that bag now.
  • Last is my, SUPER DIRTY, organiser. It has three pouches and lets me easily store my laptop charger and mouse in a easy to find bag (I can pull it out my laptop without looking). It also doubles as a handy mouse pad which is why it is so filthy.

Why do I carry it?

Ignoring the laptop bag & its obvious use. The hard drive bag & mic bag keeps the devices safe – especially since they are carried to and from the office daily & then on many trips. The organiser is just brilliant, I cannot imagine not having it. Being able to be setup quickly because I am not digging in my bag looking for my power cable is great.

Writing

DSC_9455

To take notes, I use a Lego Moleskin – it is awesome, best paper I’ve ever seen. I carry a few pens with me & of course a few whiteboard markers.

Why do I carry it?

I take a lot of notes, every single meeting. I seldom read them. The reason to take them is two fold, first it helps me remember as I am combining listening & an action which helps my brain reinforce the ideas a lot better than merely listening (doing is better than consuming). Second it gives me confidence that, if something is forgotten, I can find it.

Always carry your own whiteboard markers, since meeting rooms are often missing them.

Odds and Ends

DSC_9444DSC_9448DSC_9457

I carry a few odd things in the bag too. First is a couple of microfiber clothes and a deck of planning poker cards. I also carry a mifi device & a USB graphics card. The USB graphics card let’s me output to USB and has connectors for a few different types of screens. Lastly is some battery packs.

Why do I carry it?

The microfiber clothes is for one reason: Touch Screen.

The reason to carry planning poker cards is because we use them all the time in my teams. I have enough for 6 or 7 people with me so it handles a team well.

The mifi is legacy, before my phone had a wifi hotspot, the mifi it did that job. It is still useful to create a small wifi network for working with others if the main network fails.

The USB graphics card is to handle scenarios where projectors refuse to work with my laptop or if I need another output (for example, video recording on one, projector on the other output).

Battery packs because of Eskom.

Power strip

DSC_9463

The best thing I’ve put in my bag in the last 12 months is a power strip.

Why do I carry it?

Plugs can often be at a premium and this covers me & two more people, plus it has space for two prong plugs like cellphone chargers. It also means that when I travel overseas, I buy one plug converter and then slap this into that and everything is so each to setup – no more plugging my cellphone into my laptop to charge. It is so useful, I wonder why I didn’t carry one before.

What’s Missing?

What is missing in my bag? At the moment I think there are a few items missing:

  • Network cable: I think a good quality network cable is worth having. I am tired of either missing cables or cables where the clip is damaged.
  • A stylus: Drawing is more important than ever for a developer, and I think some sort of good stylist would help improve it.

That is what is my bag? Is there anything you think I am missing? Let me know in the comments!

Tags: 

Pages

dontclickme