Mangular.js

I recently started having a look at AngularJS to replace HTML + jQuery spaghetti code, and it is pretty neat. I looked at the todo example on the main website and as simple as it may be, I do think Mangler.js can simplify it a bit more, and I’m tempted to coin the term “Mangular.js”.;) Here’s how.

The original Angular.js todo app

This code comes straight from the AngularJS website’s main page, look over there if you need explanation.

<!DOCTYPE html>
<html ng-app="todoApp">
<head>
	<title>AngularJS ToDo</title>
	<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
	<script>
	
angular.module('todoApp', [])
	.controller('TodoController', ['$scope', function($scope) {
		$scope.todos = [
			{ text: 'learn angular', done: true },
			{ text: 'build an angular app', done: false }
		];

		$scope.addTodo = function() {
			$scope.todos.push({ text: $scope.todoText, done: false });
			$scope.todoText = '';
		};

		$scope.remaining = function() {
			var count = 0;
			angular.forEach($scope.todos, function(todo) {
				count += todo.done ? 0 : 1;
			});
			return count;
		};

		$scope.archive = function() {
			var oldTodos = $scope.todos;
			$scope.todos = [];
			angular.forEach(oldTodos, function(todo) {
				if (!todo.done) $scope.todos.push(todo);
			});
		};
	}]);

	</script>
	
	<style>
		.done-true {
			text-decoration: line-through;
			color: grey;
		}
	</style>
</head>
<body>
	<h2>Todo</h2>
	<div ng-controller="TodoController">
		<span>{{remaining()}} of {{todos.length}} remaining</span>
		[ <a href="" ng-click="archive()">archive</a> ]
		<ul class="unstyled">
			<li ng-repeat="todo in todos">
				<input type="checkbox" ng-model="todo.done">
				<span class="done-{{todo.done}}">{{todo.text}}</span>
			</li>
		</ul>
		<form ng-submit="addTodo()">
			<input type="text" ng-model="todoText" size="30" placeholder="add new todo here">
			<input class="btn-primary" type="submit" value="add">
		</form>
	</div>
</body>
</html>

Simplification using Mangler.js

.todo

Instead of having a simple array to store the todo items, wrap it in a managed Mangler object:

$scope.todos = Mangler([
	{ text: 'learn mangular', done: true },
	{ text: 'build a mangular app', done: false }
]);

HTML and Angular templates

In line with the above changes, you have to change all references to the todo array to todo.items. This affects the {{todos.length}} template tag and the ng-repeat="todo in todos" directive.

.addTodo()

Nothing has to change here, as the todo Mangler object supports the .push() method, just like an array.

.remaining()

Instead of a manual loop, simply use the .find() method to return a sub-set of your items:

$scope.remaining = function() {
	return $scope.todos.find({ done: false }).length;
};

The .find() method returns an array of all items matching the filter, returning the .length property simply counts them in a single line.

.archive()

Using the same condition as above, the Mangler object’s .filter() method removes non-matching items from the .items array:

$scope.archive = function() {
	$scope.todos.filter({ done: false });
};

The shorter Mangular.js todo app

Mangler.js can greatly simplify working with JavaScript objects and arrays, you no longer have to write multiple lines of code for simple operations. Here’s the shortened code:
Read more ›

Share Button
Posted in Blog Tagged with: , ,

Mangler.js javascript aggregators

Mangler.js‘ new .aggregate() function helps you do calculations on sets of values with the least amount of coding.

Syntax

As usual, it comes in two flavours: as a static utility function or as a Mangler object method:

Mangler.aggregate(collection, aggregator, options);
Mangler(array).aggregate(aggregator, options);

Parameters:

  • collection: Any array or iterable object to get the values from.
  • aggregator: String identifier of the built-in aggregator function to use. You can also pass your own aggregator function.
  • options: An object with optional parameters. If a string is passed, it is handled as the value option.

Options:

  • value: Rather than using the values in the collection directly, use Mangler.getpath() to get its sub-item.
  • group: Path of the field to use as a group identifier to process the data in batches. Can also be a custom function that returns the group name.

Simple examples

var numbers = [6, 10, 20];
var object = { one: 1, two: 2, three: 3 };

// Calculate the sum of an array of numbers
Mangler(numbers).aggregate('+');  // returns 36

// Calculate the sum of object property values
Mangler.aggregate(object, '+');  // returns 6

var products = [
	{ name: 'cherry', type: 'fruit', price: 3.00 },
	{ name: 'orange', type: 'fruit', price: 2.90 },
	{ name: 'grapes', type: 'fruit', price: 1.00 },
	{ name: 'carrot', type: 'vegetable', price: 2.00 },
	{ name: 'celery', type: 'vegetable', price: 3.50 }
];

// Calculate the average product price
Mangler(products).aggregate('avg', 'price');  // returns 2.48

// Collect all product names into an array
Mangler(products).aggregate('[]', 'name');
// returns ['cherry', 'orange', 'grapes', 'carrot', 'celery']

Built-in aggregators

  • "sum": The sum of all values. Aliases: "+", "add"
  • "mul": Multiply all values together. Alias: "*"
  • "avg": The average of all values.
  • "cnt": The number of values found. Alias: "count"
  • "min": The smallest value. Alias: "<"
  • "max": The largest value. Alias: ">"
  • "array": Returns an array of all values. Alias: "[]"

Grouping

// Count products by type
Mangler(products).aggregate('cnt', { group: 'type' });
// returns object: { fruit: 3, vegetable: 2 }

// Get the lowest prices per product type
Mangler(products).aggregate('min', { value: 'price', group: 'type' });
// returns object: { fruit: 1.00, vegetable: 2.00 }

A custom grouping function takes two parameters (key, item) and returns a group name or identifier, which will become property names of the returned object. key is the array index or object property name of the item within the collection. The following example collects product names grouped by their first letter:

var getFirstLetter = function(k, i) { return i.name[0]; };
Mangler(products).aggregate('[]', { value: 'name', group: getFirstLetter });

Returns:

{
	c: ['cherry', 'carrot', 'celery'],
	g: ['grapes'],
	o: ['orange']
}

Custom aggregators

You can pass your own function instead of an aggregator name. The aggregator function gets called for each item in the collection and updates the result. The final result has to be calculated on every call, as there may or may not be further items in the collection. It only needs to generate a single result, grouping of items is handled outside of this function.

It takes three parameters:

  • k is the key of the item in the collection, either an array index or an object property.
  • v is the value to be processed. Either the item itself, or a part of it extracted by the value option.
  • a is the aggregator object, its value is preserved between aggregator calls. The value of a.count is the number of values processed so far, including the current one (starts at 1). The result has to be put into a.result. On the first call, a.result is undefined.

This is the built-in sum aggregator as an example:

function(k, v, a) {
	a.result = a.count === 1 ? v : a.result + v;
},

Advanced aggregators

Special getters can be used to simplify aggregators and queries. This example registers a special getter to the Date type to group items automatically:

var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

Mangler.registerType(Date, {
	get: function(date, key) {
		if(key === 'dayOfWeek') {
			return days[date.getDay()];
		}
	}
});

var data = [
	{ qty: 1, date: new Date('2015-03-01') },
	{ qty: 4, date: new Date('2015-03-02') },
	{ qty: 3, date: new Date('2015-03-03') },
	{ qty: 7, date: new Date('2015-03-04') },
	{ qty: 4, date: new Date('2015-03-04') },
	{ qty: 9, date: new Date('2015-03-05') },
	{ qty: 2, date: new Date('2015-03-06') },
	{ qty: 1, date: new Date('2015-03-07') },
	{ qty: 3, date: new Date('2015-03-08') },
	{ qty: 2, date: new Date('2015-03-10') },
	{ qty: 1, date: new Date('2015-03-11') },
	{ qty: 4, date: new Date('2015-03-12') },
];

// Get total quantites per day of the week
var result = Mangler(data).aggregate('+', { value: 'qty', group: 'date.dayOfWeek' });

console.log(result);

Result:

{
	Sunday: 4,
	Monday: 4,
	Tuesday: 5,
	Wednesday: 12,
	Thursday: 13,
	Friday: 2,
	Saturday: 1
}
Share Button
Posted in Blog Tagged with: ,

Mangler.js transform, deflate and inflate

It is time for some new features, fixes and breaking changes to my Mangler.js object processing library. As I started using it in my projects myself and it seems pretty stable, it might even see an official release soon.

Transform

Formerly known as .toCase, it transforms strings between snake_case, camelCase and TitleCase. It no longer takes an array of tokens as input, but can transform a whole array of strings, or even the property names of a passed object. Option properties have also been renamed to transform for all functions that supported toCase.

// By default, auto-detects source transform
// These both return "FooBarBaz"
Mangler.transform('foo_bar_baz', 'title');
Mangler.transform('foo_barBaz', 'title');

// You can specify source and target transforms to avoid guess-work
// This example ignores the primary snake_case detection
// Returns "Foo_barBaz"
Mangler.transform('foo_barBaz', { from: 'camel', to: 'title' });

// When processing multiple strings, you can set an ignore list
var o = { one: 1, two: 2, three: 3 };
Mangler.transform(o, { to: 'upper_', ignore: ['two'] });
// returns o, which is now: { ONE: 1, two: 2, THREE: 3 }

It supports the following transformations:

  • "_": The default sNake_cAse transformation.
  • "upper_": ALL_UPPERCASE_SNAKE_CASE
  • "lower_": all_lowercase_snake_case
  • "title": CapitalisedTitleCase
  • "camel": usualCamelCase
  • ".": dot.delimited.words

Deflate

Formerly called .flatten(), this functionality is not new. It takes a JavaScript object and completely squashes its nested objects and arrays into a single level.

// Example object:

var o = {
	user: {
		id: 'jsmith',
		name: 'John Smith',
		roles: ['Admin', 'User']
	}
};

When called without options:

Mangler.deflate(o);

Result:

{
	user_id: "jsmith",
	user_name: "John Smith",
	user_roles_0: "Admin",
	user_roles_1: "User"
}

Optionally, it can be limited to only take a certain number of iterations from the root.

Mangler.deflate(o, { limit: 1 });

Result:

{
	user_id: "jsmith",
	user_name: "John Smith",
	user_roles: ["Admin", "User"],
}

By default it generates snake_case property names for deflated items, specify the transform option to use one of the above text transformations.

Mangler.deflate(o, { transform: 'camel' });

Result:

{
	userId: "jsmith",
	userName: "John Smith",
	userRoles0: "Admin",
	userRoles1: "User"
}

Object properties will be deflated in-place, clone the object first if you need the original structure, or reverse it with…

Inflate

Reverses the effect of deflate. When called on the first two results above without options, it restores the original object.

Mangler.inflate(o);

With the limit option, you can limit processing to a certain number of levels, starting from the last word of the property name:

Mangler.inflate(o, { limit: 1 });

Result:

{
	user: {
		id: "jsmith"
		name: "John Smith"
	},
	user_roles: ["Admin", "User"]
}

You can also use the transform option to run the resulting property names through .transform(), and the from option to change how words are detected in property names. Both of these options default to snake_case.

Conclusion

As usual, you can call all the above methods on Mangler() object collections as well to apply them to all items, just leave out the first parameter.

If you have any feature suggestions, please let me know in the comments below.

Share Button
Posted in Blog Tagged with: ,

Android 5.0 silent mode missing

The long awaited Android 5.0 update for my Galaxy S5 has finally arrived in an official update. I wasn’t impressed by the battery-sucking change to put a white background on everything, but hey, I’m adaptable, I can live with that.

However after one (1!) day of use I realised that the silent mode has been removed. The sound icon in the notification area used to cycle between sound/vibrate/mute, now it’s just sound/vibrate. The only way to go silent is to switch to vibrate, then go to sound settings and manually take off the vibration intensity. There has probably been some API changes associated with it as well, as many widgets on the Play Store are broken too.

So my question is: who in their right mind would authorise a change to take out a basic feature that’s been in all my mobile phones since my very first one in 2001? If somehow it got into the RC by accident, how many Google testers does it take to identify this as an issue? Of course there are some toggle widgets that’s been updated to work with Android 5.0, but why would I need to monkey-patch a basic feature like that?

UPDATE: Apparently due to public outrage, Android 5.1 will have silent mode back as before, but as the update goes to manufacturers, then mobile providers, it might take a couple of months for the update to be available on your device.

Thankfully Samsung created an update for the Galaxy S5 5.0 branch, which reverted silent mode changes, along with all the priority contact stuff. While the quick fix is quite welcome, this hybrid Android version might introduce some extra incompatibilities to the already fragmented platform.

Share Button
Posted in Blog Tagged with: , ,

Assembly number guessing game

The re-write of the x86 Assembly version of NumGuess was long overdue. 15 years ago when I wrote the original code I didn’t think about standardisation or guidelines, just wanted to make it work. As the NumGuess project took off and received numerous contributions, the old assembly code became the weakest link.

A couple of weeks ago I decided to jump back into 16 bit x86 assembly programming to bring it in line with the rest of the project. It was clear from the start that it needed a complete re-write as the whole code was useless. Nibbling away at it in my free time, it is finally complete. Today I give you not just the guideline compliant 286 DOS code, but an improved 386 DOS version that uses 32 bit registers as well, which pushes the total number of NumGuess implementations to 40.

Random number generator

The original had no such thing. As the limit was hard-coded to 100, it simply queried the current time, which was accurate to 100th of a second. With the guideline’s requirement of a dynamic limit, that was no longer feasible, and an RNG was needed that gave believable randomness.

I chose MINSTD, which is a simple Lehmer RNG with a multiplier of 48271, which conveniently fits into a word register, the largest on the 16-bit platform I was aiming for. Unfortunately I still had to do some arithmetic calculations for up to 47 bits, which needed some extra work-arounds and code branching on 286.

The largest number it generates is 2147483646, one less than the maximum positive value of a 32 bit signed integer. This is the current limitation for all numbers in both versions.

The 386 version

The 386 version is just a simple improvement on the 286 one, taking advantage of the 32 bit registers that are available. To avoid using protected mode and keep it simple, it still uses 16-bit segments, but with the simplified calculations the code is about 140 lines shorter.

Conclusion

To compile the code, you’ll need the DOS versions of either TASM or MASM. The easiest way is the Tasm for Windows project on SourceForge, which bundles it with DOSBox. Compile and link with the following commands to generate an executable:

tasm num_286
tlink num_286

If you prefer MASM, you can download it from here, then:

masm num_286.asm
ml num_286.obj

Enjoy the latest addition to the NumGuess family, comments and suggestions are welcome. If you find a bug, please submit an issue on GitHub.

Share Button
Posted in Blog Tagged with: , ,

Android Studio vs Eclipse folder structure

With the recent stable release of Android Studio in December, it has replaced Eclipse as the standard Android development environment. All developers are advised to migrate to it, as the ADT Eclipse plugin will not be maintained and updated, and as of now, it is no longer supported.

In this article I’ll have a quick look at the differences in the folder structure of the two IDEs.

Eclipse workspaces and Android Studio projects

Android Studio changes the terminology a bit. In Eclipse, you had workspaces with a number of projects and library projects in them. In Android Studio, this becomes a project with a number of modules and library modules. Apart from the names, they’re pretty much the same thing, but thanks to the mandatory Gradle build system, it tends to be more organised.

Many libraries no longer need to be copied into your workspace. Simply add a reference to the module’s build.gradle file, state the required version, and it will be automatically fetched from the remote repository, compiled and included without having to worry about it. No more hunting for Android support library JARs in the SDK folders, and no more manual Eclipse project opening nightmare. Many third party libraries can be included in the same way with Gradle, which saves a lot of clutter. Your project folder will be neat and clean, and really only contain your own code.

Folder structure

Here’s a list of folders where your code and resources are stored compared to Eclipse:

What is it? Eclipse Android Studio
Android manifest [project] [module]/src/main
Assets [project]/assets [module]/src/main/assets
Java source files [project]/src [module]/src/main/java
Resources [project]/res [module]/src/main/res
Included JARs [project]/libs [module]/libs

In the next article I’ll have a look at migrating your Eclipse project to Android Studio.

Share Button
Posted in Blog Tagged with: , , , ,

NumGuess JScript and VBScript

Two more NumGuess versions have been added bumping the total up to 39. This time it’s JScript and VBScript versions with complete Windows Script Host support. They can be run with cscript.exe for console, or wscript.exe for annoying pop up windows.

The VBScript version is almost the same as the VB.NET one, with small modifications of error handling and console input.

The JScript version was a bit more tricky. On the up side, it includes and uses the JavaScript library, which is JScript compatible. On the down side, Microsoft somehow forgot to add input box support for wscript, so it has to be invoked from a VBScript part. This is why the file extension had to be changed to .wsf and the code itself is embedded into XML.

For the record, there were two more work-arounds proposed on the internet for the above issue, none of them worked:

  • The first one involved creating a ScriptControl ActiveX object to run VBScript code directly from JScript via eval. It looked like a fairly clean solution, but it doesn’t work in 64 bit mode, and on my machine it didn’t work in forced 32 bit mode either.
  • The second proposal was to create a hidden Internet Explorer instance, load an empty page and directly call window.prompt(). Unfortunately due to IE security improvements, it crashed with access denied, and I just ended up with an unkillable hidden IE process.

So yes, the JScript version is not ideal, but it works. If wscript support is not needed, the JScript part works fine in a .js file as well.

And as always, we’re always open to new contributions.

Share Button
Posted in Blog Tagged with:

End of 2014 report

Another year has gone by and CodeBin blog is celebrating its second birthday today. Yay! I’d also like to wish all my readers a happy and prosperous new year! This is the usual recap of all that’s happened here.

Apart from a few moderately popular posts about LibGDX and Android stuff, the most popular post this year was about upgrading the Eclipse development IDE to the latest version. With this many hits, I think it’s time for developers to think about making it more straight-forward and automatic in the future.

CodeBin also went social in February last year with Facebook and Twitter accounts, and although the follower and like counters are still under the double-digit mark, it was more as an experiment and development excercise than anything else. Anyways, if you feel like social networks is the best way to keep track of my posts, it’s there if you need them. 😉

The NumGuess project has seen some nice pull request with a couple of extra contributors, and it’s already a bigger and nicer project than I would have expected 15 years ago when I wrote the first line of code. Thank you all for your hard work!

The most ambitious project in 2014 was undoubtedly Mangler.js. While it is still not feature complete and lacks up to date documentation, it has helped me shorten some javascript code at work, and anyone is free to try and use it.

That’s about it, let’s see some random analytics stats.

Visitors

The site’s popularity has seen significant increase, I had about 10 times more visits compared to the year before. Many thanks to all my 31,051 visitors with 47,540 page views.

Most popular posts and pages

Other (7.2%)

Projects

OpenPrince (33.2%)
Mangler.js (22.3%)
NumGuess (18.3%)
FakeTileAO (17.9%)
EsoInt (4.8%)

Ostudio

C64 Games (38.9%)
Ostudio (22.4%)
Kill Bill (12.7%)
Ocamel (8.2%)
Oscorch (6.7%)
Otron (3.7%)

Visitor sources

Google search (89.4%)
Direct traffic / unknown (7.3%)
Semalt (0.6%)
Bing (0.3%)
StackOverflow (0.2%)
Yahoo (0.2%)
Other (2.0%)

Browsers

Chrome (58.9%)
Firefox (28.3%)
Safari (4.8%)
Internet Explorer (4.3%)
Opera (2.1%)
Other (1.6%)

Platforms

Desktop (95.5%)
Mobile (3.4%)
Tablet (1.1%)
Share Button
Posted in Blog Tagged with: ,

NumGuess R Project contribution

R language logoNumGuess program #37 has arrived as an unexpected contribution by Gergely Daróczi, this time in the form of an R script.

It’s very nice and clean code, paying great attention to the guideline from the start. The R language is mainly used for statistical computing and graphics, and now for guessing numbers as well. For more information about the language, check out the R-project website.

As always, if you can code in something that’s missing, the project is always open for contributions.

Share Button
Posted in Blog Tagged with:

Happy Holidays!

I’d like to take this opportunity to wish all my readers merry Christmas and happy holidays! Due to the popularity of last year’s riddle, I’d refrain from doing another one. If you’re desperate, just look up the old post and leave a comment, it’s not too late to be the first to submit the correct answer.;)

As this blog is getting close to its second birthday, stay tuned as I plunge into the analytics and give you this year’s highlights and most popular posts soon.

Share Button
Posted in Blog

If you find something useful, please feel free to buy me a cup of coffee.