Simlicity is not always so great…

While making some changes to the skills on my website I noticed a design flaw that I created while simplifying some display options.


public async Task<ActionResult> Index()
{

&nbsp;

Dictionary<string, List<Skill>> skillDictionary = await db.Skills
.GroupBy(s => s.SkillGroup)
.ToDictionaryAsync(g => g.Key, g => g.OrderBy(v=>(int)v.SkillLevel).ToList());

ViewBag.GroupedSkills = skillDictionary;
return View();
}

Super simple ey? Yes but one fatal flaw, I cannot sort the skill groups this way… This needs fixing pronto, two solutions I came up with:

  1. Adding an OrderBy and in the ordering, function pass a lambda expression to order the skill groups by the amount of ‘Advanced’ skills
  2. Adding two new Entities:
    1. SkillGroup
    2. SkillToGroupAssigement

While migrating the whole database and is always a bit scary I think I’ll go for option two it’s a lot more long lasting and allows me to custom sort Skill Groups.

Don’t load data you dont really need.

In my previous posts, we discussed my load method and how to implement a picker resulting in the following method:


private async Task LoadData()
{
if (_isDataLoaded)
return;
ModelExercises.Clear();
_isDataLoaded = true;

var modelExercises = await _workoutStore.GetModelExercisesAsync();

foreach (var modelExercise in modelExercises)
{
ModelExercises.Add(await
ModelExerciseViewModel.CreateAsync(modelExercise, _workoutStore)
);

}

var muscles = await _workoutStore.GetMusclesAsync();

foreach (var muscle in muscles)
{
Muscles.Add(muscle);
}

if (SelectedMuscle != null)
{
var selectedMuscle = from m in Muscles
where m.Name == SelectedMuscle
select m;
Muscles.Clear();
Muscles.Add(selectedMuscle.SingleOrDefault());
}

foreach (var muscle in Muscles)
{
var currentMuscle = new ExerciseGroup(muscle.Name, muscle.Name);

var foundMuscles = from e in ModelExercises
where e.PrimaryMuscles.Contains(muscle, _compareMuscle)
select e;
currentMuscle.AddRange(foundMuscles);
GroupedExercises.Add(currentMuscle);
}

}

The primary problem with this approach is in:


foreach (var modelExercise in modelExercises)
{
ModelExercises.Add(await
ModelExerciseViewModel.CreateAsync(modelExercise, _workoutStore)
);

}

Which triggers the static async method (which replaces the constructor which itself cannot be async):


public static async Task<ModelExerciseViewModel> CreateAsync(ModelExercise exercise, IWorkoutStore workoutStore)
{
_workoutStore = workoutStore;

ModelExerciseViewModel exerciseViewModel = new ModelExerciseViewModel(exercise);
exerciseViewModel.PrimaryMuscles = await GetMuscles("Primary");
exerciseViewModel.SecondaryMuscles = await GetMuscles("Secondary");
return exerciseViewModel;
}

It works… but it is super slow, on my Galaxy A52016 it took ~6sec to generate the original list and ~2sec for each filtering. Unacceptable.

Then it dawned on me… Why do I generate objects I don’t need at this time?

The original logic was: I am going to create all the objects and then use the lists of muscles I build for them for filtering.

What seemed like a good plan was loading information I did not need into the application when I have a perfectly good simple object:


public class MuscleExerciseAssosiation
{
public int MuscleId { get; set; }
public int ModelExerciseId { get; set; }
public string MuslceType { get; set; }
}

In my database based on which I can use for filtering:


public async Task<IEnumerable<MuscleExerciseAssosiation>> GetMuscleExerciseAssosiations(string muscleType, int? muscleID = null)
{
List<MuscleExerciseAssosiation> assosiations = new List<MuscleExerciseAssosiation>();
if (muscleID == null)
{
assosiations = await _connection.Table<MuscleExerciseAssosiation>()
.Where(e=>e.MuslceType == muscleType).ToListAsync();
}
else
{
assosiations = await _connection.Table<MuscleExerciseAssosiation>()
.Where(e => e.MuscleId == muscleID && e.MuslceType == muscleType).ToListAsync();
}

return assosiations;
}

Now when I can pull at will either a filtered or full list of exercises I need I can simply:


if (SelectedMuscle != null)
{
var assosiatedExercises = await _workoutStore.GetMuscleExerciseAssosiations("Primary", SelectedMuscle.Id);
foreach (var assosiation in assosiatedExercises)
{
ModelExercises.Add(modelExercises.Where(e => e.Id == assosiation.ModelExerciseId).SingleOrDefault());
}
}
else
{
muscles = await _workoutStore.GetMusclesAsync();

foreach (var muscle in muscles)
{
Muscles.Add(muscle);
}
foreach (var exercise in modelExercises)
{
ModelExercises.Add(exercise);
}

}

And thats it. Perfomance to being unoticable for both the initial load and filtering, so I am preatty proud of myself 🙂

The full new ViewModel can be found on github.

A little guide on dealing Xamarin errors

So… I  sank around 3 hours into fixing this across 2 days… Turns out there is nothing wrong with the Picker, nothing wrong with my solution… The issue was within Xamarin.

Mono just got confused and was killing everything…

While digging thru the logs of the output I found out that the issue was linked to XamlFilePathAttribute so while there was no direct thread related to my issue I found this post, and it saved my life bottom line to fix a variety of issues with this class:

  • Cleanup solution
  • Close Xamarin Studio/VS
  • Remove all .bin and .obj folders in all projects.
  • Open Xamarin Studio/VS and rebuild the solution.

The Rebuild word is key be sure to

ReBuild

And not just try to debug it again like I did. Now everything works perfectly:

The simplest of things…

In Xamarin Forms 2.3.4 they added a Bindable picker to the XAML as per this documentation:
https://blog.xamarin.com/new-bindable-picker-control-for-xamarin-forms/

But cut my dick off and call me daisy but I cannot get it to work… I made a list dedicated to it:


public ObservableCollection<string> MuscleGroups { get; private set; } = new ObservableCollection<string>();

Filling it in nice and proper


var muscles = await _workoutStore.GetMusclesAsync();
foreach (var muscle in muscles)
{
MuscleGroups.Add(muscle.Name);
}

Bound it in XAML:


<Picker ItemsSource="{Binding MuscleGroups}" SelectedItem="{Binding SelectedMuscle}" />

But it crashes as soon as I try to load the page, its been two hours after a long day of doing Python in the office, I need a break… Going to fix it tommorow.

It’s not horrible: Lightworks

So when most people try to create a montage they use Windows Movie Maker it, however, lack a lot of features. While Adobe Premiere or Sony Vegas are not super expensive most of us do montages 1-3 times per yer at most. So the ~70 EUR price tag is a bit steep. Luckily there are alternatives I use one of them Lightworks.

My favorite part is how closely it resembles the aformentioned Vegas and Premiere:

Lightworks1.png

So you have your clip viewer your full audio processed output clip sources and most importantly timelines.

Triming videos is easy:

Lightworks2

You click the beginning watch till you want to stop the crop (or scroll you can view it at a variety of speeds from frame to frame to 300%). Then select the endpoint. After that, with one click you can insert your crop into the video with one click (the two buttons on the right).

What is missing/hard to find, I did miss the opportunity to easily change each audio tracks volumes, I ended up with poorer audio than I’d like :(. The free version also limits you to 720p.

Overall with its similarities to the top products on the market it allowed me to create this in ~4h of work (from the install to the final product).It’s nothing earth shattering but we liked and is a nice memoir.

Loading a DataFrame from BOX API in python

As a temporary data source I want to use CSV files stored on box.com, and with this documentation it is super easy to do so!

I have made a class BOXFile.py:


from boxsdk import Client, OAuth2
from boxsdk.network.default_network import DefaultNetwork
from boxsdk.network.logging_network import LoggingNetwork
from boto.dynamodb.condition import NULL

class BOXFile:
 def __init__(self, CLIEND_ID, CLIENT_SECRET, ACCESS_TOKEN):
 self._oauth2 = OAuth2(CLIEND_ID, CLIENT_SECRET, access_token=ACCESS_TOKEN)
 self._client = Client(self._oauth2, LoggingNetwork())
 self._file = None

 def GetUserInfo(self):
 my = self._client.user(user_id='me').get()
 print my.name.encode("utf-8")
 print my.login.encode("utf-8")
 print my.avatar_url.encode("utf-8")
 def GetFile(self, fileID):
 self._file = self._client.file(fileID)
 return self._file.content()

On the object construction it logs requires login details into BOX (at this time to the DEV environment) and creates an _client property that we will be using in our further examples.

The Two methods: GetUserInfo and GetFile are first of many methods that I will code into the class as my needs grow.

So now lets get implementing first I am going to need some libraries:

from Model.BOX import BOXFile as bf
import pandas as pd
import io

Pandas I am going to use to create a DataFrame with the Data the io will convert the output from box into something pandas can read and of course the class needs to be implemented

boxfile = bf(CLIEND_ID='XXX', CLIENT_SECRET='XXXX', ACCESS_TOKEN='XXXXX')
csvFile = boxfile.GetFile('164280827785').decode("utf-8")
ioFile = io.StringIO(csvFile)

Like in the example I create an instance of the class loading OAuth2 and exposing the GetFile Method for myself, I get a CSV file and decode it, to turn it into an ioFile for Pandas, lastly:

df = pd.read_csv(filepath_or_buffer = ioFile, delimiter = ";")
print(df)

lastly we create our DataFrame using read_csv and print it!

Next we will encapsulate the whole process in two interacting classes.

Implementing IEqualityComparer for custom object comparison

I had a simple snippet of code:


foreach (var muscle in muscles)
{
var currentMuscle = new ExerciseGroup(muscle.Name, muscle.Name);

var foundMuscles = from e in ModelExercises
where e.PrimaryMuscles.Contains(muscle)
select e;
currentMuscle.AddRange(foundMuscles);
GroupedExercises.Add(currentMuscle);
}

However where e.PrimaryMuscles.Contains(muscle) refused to generate any results. To me, it was logical that the muscles are the same (they Shared and ID and a Name), but to the compiler they were different. Obviously, they were equal in properties but not the same object… Silly me. So the problem is stated the stage is set.

Thankfully .Contains() has an overload that takes two parameters an object and an IEqualityComparer, great! Let’s get implementing!


private IEqualityComparer<Muscle> _compareMuscle { get; set; } = new MuscleComparer();

private class MuscleComparer : IEqualityComparer<Muscle>
{
public bool Equals(Muscle x, Muscle y)
{
bool id=false;
bool name=false;
if (x.Id == y.Id)
id = true;
if (x.Name == y.Name)
name = true;
return id && name;
}

public int GetHashCode(Muscle muscle)
{
int hCode = muscle.Id ^ muscle.Name.Length;
return hCode.GetHashCode();
}
}

So a very simple interface of two methods Equals and GetHashCode quick implementation and now our app returns a proper segmented view:

Perfect, it does, however, take a performance hit after this change (the load takes ~2seconds) so I might want to look at making it faster somehow.