Saturday, November 30, 2013

You have to go out of your way to get keydown logic to work in JavaScript within Firefox.

$(function() {
   document.onkeydown = function() {
      switch (window.event.keyCode) {
         case 37:
            if (whatever) {

 
 

Per this the blob above had to be refactored into the blob below. What is above accomodated IE 10, Chrome, and Safari. What is below accomodates IE 10, Chrome, Safari, and now Firefox too.

$(function() {
   document.onkeydown = function(event) {
      var key;
      if (window.event) {
         key = window.event.keyCode;
      } else {
         key = event.which;
      }
      switch (key) {
         case 37:
            if (whatever) {

Thursday, November 28, 2013

source/via in Twitterland

Partway down this you will see:

 
 

How do I get "via [MyApp]" appended to updates sent from my API application?

The source attribution of a Tweet is set by the name of the application used to create it. If you register an application we will use it's name and URL as the source for any Tweet it creates. Application names must be unique so if the application name you wish to use is taken, please choose another.

 
 

...I had a good idea yesterday, or so I thought. I thought of writing an app that allowed one to tweet while using the source field for the next few characters beyond the 140 character limit. It looks like there are safeguards to keep someone from doing what I schemed to do however. :P

CORS stands for Cross-Origin Resource Sharing

Use CORS rules in ASP.NET Web API implementations to allow other domains to access your API. In this example we allow everyone:

var response = Request.CreateResponse<Whatever>(HttpStatusCode.OK, whatever);
response.Headers.Add("Access-Control-Allow-Origin", "*");
return response;

You have to explicitly allow other domains or they are shut out. Thinktecture IdentityModel is, I believe, a helper for making the CORS stuff less awkward to use amongst other things. The security stuff for the ASP.NET Web API is underwhelming me hence far. I attended a talk once were one asked about how to protect an ASP.NET Web API method from being hit over and over again by an outsider (from a bot at the browser/ping level), and honestly the reality is that security hole is the same security hole that every plain Jane web site has too. The way to fight a denial of service attack is to block offending IPs. A distributed denial of service attack is a bigger, rarer, more beautiful thing that probably won't happen to you. If you need to authenticate someone hitting an API that does a POST, PUT, or DELETE, you will have the same Session stuff you have in just changing from one controller action to another in an MVC app. Meh. Happy Thanksgiving everyone!

SSIS Hello World

I watched a video presentation last night on how to do a "Hello World" in an SSIS application. It answered a lot of questions I would not have answered for myself without someone holding my hand. The dummy use case was to take a bunch of records for contacts out of a .csv (commas separated value) file and put them in a database table. The contacts in the .csv had zip codes but lacked city and state values so those had to be drummed up by using a lookup table from a database as a step midstream in the chain of events. Packages contain task flows in SSIS. A package is typically a .dtsx file, but it could also be something stored at an MSSQL database. To use SSIS you will need BIDS (Business Intelligence Development Studio) installed. If you type "component services" at the start menu you should be able to see a list of services running. Hopefully you will see "SQL Server Integration Services 10.0" running. If so, you are golden. The next thing to do is to start BIDS. Go to "Project..." under "New" under "File" and make a new "Integration Services Project." The screen will be split. There will be four tabs across the top. The first two are "Control Flow" and "Data Flow." The lower fifth or fourth of the screen will be a subsection called "Connection managers" independent of the tabbed area. Right-click in "Connection managers" to make a "New Flat File Connection..." and fill out the dialog box which appears. The "Advanced" part of the dialog will allow you to assign column names to columns... and data types too. When you are done make a second connection. Pick "New OLE DB Connection..." this time and make a connection to a database where records will ultimately be put. Add a "Data Flow Task" at the "Control Flow" tab by pulling it out of the "Control Flow Items" panel. You may right-click in the task to massage its properties. Next go to the "Data Flow" tab, which show come up within the context of the "Data Flow Task" you just made. If you renamed the "Data Flow Task" you should see the name at the "Data Flow" tab. We will next drag three different controls into the "Data Flow" tab. The first task drug in from the side panel will be a "Flat File Source." Somehow the new task gets associated by default with the first of the connections. Perhaps because there is only one flat file connection. In watching the video, it seemed automatic. This association is crucial and cornerstone to our process. Again, you may right-click in this task to tweak its properties. The task will have a green arrow and a red arrow descending from it. The green arrow represents a happy pass scenario in which we read from the .csv file and then go on to what is appropriately next. The red arrow represents where we should go in the event of trouble, failure, drama, and heartache. Drag a "Lookup" into the Data Flow tab next. Drag the green arrow from the other task to the "Lookup." Tweak the "Lookup" into getting the state and city by right-clicking it and messing with the dialog box which appears. This task will use the OLE DB Connection. Finally, drag in an "OLDB Destination" task and make the green arrow that now comes off of the "Lookup" go to the "OLDB Destination" task. This task will have a red X on it until you configure it by, yes, right-clicking upon it and then monkeying with settings in a dialog box. The input setting needs to be "Match Output" and the output setting needs to be the OLE DB Connection. You will have to configure what "columns" from the .csv file map to which columns in the database, etc. Pick "Start Debugging" from the "Debug" menu to test and all three of the tasks in the chain should turn green. The "testing" will actually write to the database too. It is the real thing. The example in this blog posting is completely plagiarized from another source. :P

Wednesday, November 27, 2013

Acronyms!

MDMMobile Device Management
B2EBusiness to Employee Applications
MADPMobile Application Development Platform
MBaaSMobile Backend as a Service
MAMMobile Application Management
MCMMobile Content Management

optional parameters at JavaScript function signatures

If a signature takes in five variables and you only hand in three then the last two will end up falsey.

User Account Control

in Windows 7, navigate to: Control Panel > Large icons > User Accounts > Change User Account Control settings ...to increase this security. I learned today that we sign .dlls as a Microsoft Partner so that if this UAC setting is cranked up high that we will be less likely to be deemed scary.

clean up CSS manipulations in Dojo by pulling stuff up to the stylesheet (be less hacky/nasty)

Following up on this, I just replaced this:

domStyle.set(legend, "display", "none");

 
 

...with the following. You might be able to imagine what domStyle and domClass correspond to at the AMD define signature.

domClass.add(legend, "displaynone");

 
 

In my stylesheet I have:

.displaynone {
   display: none;
}

 
 

Now I feel clean and proud of myself.

dojo/dom-class in contrast to dojo/dom-style is for setting classes in lieu of styles at elements.

Yes, you need to have both things in an AMD signature to do both things. Hiss.

Tuesday, November 26, 2013

Add/remove child elements to/from a table in Dojo.

In the define signature of an AMD module I associate "dojo/dom-construct" with domConstruct and then I do the following with domConstruct:

var tr = domConstruct.create("tr", {}, this.table);
var foo = domConstruct.create("td", { innerHTML: "foo" }, tr);
var bar = domConstruct.create("td", { innerHTML: "bar bar bar bar bar bar bar bar bar
      bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar bar",
      nowrap: "nowrap" }, tr);
var baz = domConstruct.create("td", { innerHTML: "baz" }, tr);
var qux = domConstruct.create("td", { innerHTML: "qux" }, tr);

 
 

Per this a good way to turn around and drop all of the children pushed into this.table would be like so:

while (this.table.hasChildNodes()) {
   this.table.removeChild(this.table.lastChild);
}

Find children inside a DOM node in JavaScript.

Here we are starting with a table which has one row (inside a tbody) containing numerous cells. Each table detail has first a div in it and then another element. We are collecting just the divs into an array!

var colorKeys = [];
var tableRows = legend.childNodes[0].childNodes[0].childNodes;
for (i = 0; i < tableRows.length; i++) {
   colorKeys.push(tableRows[i].childNodes[0]);
}

Get an attribute value from a SVG element in JavaScript.

alert(pieChart.surface.rawNode.getAttribute("width"));

Make the background of a dojo chart transparent by altering SVG attributes!

The comments at the bottom of this suggest that you may do so like so:

programmersChart.surface.rawNode.childNodes[1].setAttribute('fill-opacity','0');

 
 

This put me on the right track, but I had to do a little bit more including removing a stroke around the chart. My stuff:

var pieChart = new Chart(chartNode);
pieChart.setTheme(theme);
pieChart.addPlot("default", {
   type: Pie,
   fontColor: "black"
});
pieChart.addSeries("series",chartData);
pieChart.render();
pieChart.surface.rawNode.childNodes[1].setAttribute('fill-opacity','0');
pieChart.surface.rawNode.childNodes[2].setAttribute('stroke-opacity','0');
pieChart.surface.rawNode.childNodes[3].setAttribute('fill-opacity','0');

 
 

I am using a piechart and it has the Claro theme. I don't know if that biases what must be dressed up yet. My define signature has this stuff in it:

  • dojox/charting/Chart
  • dojox/charting/themes/Claro
  • dojox/charting/plot2d/Pie
  • dojox/charting/DataChart
  • dojox/charting/widget/Legend

 
 

The second, third, and fourth items I'm dressing up are rect tags. At a high level the piechart's SVG looks like this:

<svg>
   <defs>
there is a bunch of stuff inside here</defs>
   <rect></rect>
   <rect></rect>
   <rect></rect>
   <g>
there is a bunch of stuff inside here</g>
</svg>

 
 

Again, this is keeping it simple, the rect tags all have a bunch of attributes decorating them. I don't know why the middle one gets a border but not a background color. Whatever.

Monday, November 25, 2013

the free Window Resizer plugin for Google Chrome

...seems fun! It gives you a button at the browser you may quickly press to resize to:

  1. 320 x 480
  2. 480 x 800
  3. 640 x 960
  4. 768 x 1280
  5. 1024 x 768
  6. 1366 x 768
  7. 1280 x 800
  8. 1366 x 768
  9. 1280 x 1024
  10. 1680 x 1050

HIBC

...is a standard for creating/using bar codes.

Friday, November 22, 2013

Overpower a class from an element wrapping the element that uses it.

.foo .bar
{
   display: none;
   cursor: default;
}

 
 

If we decorate a div with foo and that div contains elements decorated with bar... we won't be able to see them!

Thursday, November 21, 2013

the squiggly red line

ReSpeller is a plugin for ReSharper which does spellchecking in Visual Studio. It was mentioned by a coworker who moreover asserted that most IDEs do spellchecking and that Visual Studio is an outlier in that regard. Well now Visual Studio does spell checking too I suppose. It was mentioned that you may type a name in camelCase and ReSpeller will be able to make sense of the camel casing to sanity check the spelling.

Wednesday, November 20, 2013

showing percentages with a single decimal point in JavaScript

reshapeData: function(data) {
   var totalRecords = 0;
   data.forEach(function(datum){
      totalRecords = totalRecords + datum.data;
   });
   var reshapedData = [];
   data.forEach(function(datum){
      var description = datum.label;
      if (totalRecords > 0) {
         var percentage = (datum.data/totalRecords)*100;
         if (percentage > 10) {
            description = description + " (" + percentage.toPrecision(3) + "%)";
         } else {
            description = description + " (" + percentage.toPrecision(2) + "%)";
         }
      }
      reshapedData.push({y: datum.data, text: description});
   });
   return reshapedData;
}

the "Cannot use 'in' operator to search for 'x'" error and dojox piecharting

SOMEHOW I managed to finally get past the "Cannot use 'in' operator to search for 'x'" error. You do not need to use the x value whatsoever in a dojox pie chart, so I just leave it out below. However, if I put it back in it does not seem to break my code. I had an error somewhere and I no longer know what it is. Er, I guess I never knew. All I knew is it wasn't working. At any rate, I finally have working code now and it follows. If you hit this same heartache, keep fighting! Others have been where you are now.

define([
   "dojo/_base/lang",
   "dojo/_base/declare",
   "dojo/dom",
   "dojox/collections/Dictionary",
   "dojo/dom-style",
   "dojo/data/ItemFileReadStore",
   "dojox/charting/Chart",
   "dojox/charting/themes/Claro",
   "dojox/charting/plot2d/Pie",
   "dojox/charting/DataChart"
], function (
   lang,
   declare,
   dom,
   Dictionary,
   domStyle,
   ItemFileReadStore,
   Chart,
   theme,
   Pie,
   DataChart
) {
   var app;
   return {
      init: function() {
      },
      destroy: function() {
      },
      beforeActivate: function(current, data) {
         chartData = [
            { y: 15, text: "Buchanan" },
            { y: 30, text: "Coolidge" },
            { y: 13, text: "Fillmore" },
            { y: 20, text: "Garfield" },
            { y: 37, text: "Nixon" },
            { y: 11, text: "Polk" },
            { y: 27, text: "Taft" }
         ];
         var pieChart = new Chart("chartNode");
         pieChart.setTheme(theme);
         pieChart.addPlot("default", {
            type: Pie,
            font: "normal normal 11pt Tahoma",
            fontColor: "black",
            labelOffset: -30,
            radius: 80
         });
         pieChart.addSeries("series",chartData);
         pieChart.render();
      }
   };
});

Sunday, November 17, 2013

You cannot read from App.config in a supporting project. Boo hoo.

I have just come to a painful realization that makes a lot of the silly stuff I've tried and failed finally make sense. The trick I use here when reading from App.config in a unit test project will not work if you are attempting to read from App.config in a project that is not the UI project or first project to load (the bootstrapper project or the project you have "Set As Startup Project") in a Visual Studio solution but is instead a project that is inherited from somewhere downstream. You will get an error like this:

The key 'YOURNAMEHERE' does not exist in the appSettings configuration section.

 
 

I think the expectation is that I would just put the key I needed in Web.config (or its "first project" counterpart) in lieu of needing a different configuration file in another project. Perhaps this is a perfectly legitimate expectation. So, what is my problem? In the infrastructure project of an onion architecture implementation wouldn't it be cool to keep a configuration file THERE in lieu of summoning specifications out of the Web.config in a different project? All of the external dependencies are in the infrastructure project and not the UI project. Why should the connection string to the database be kept in the UI project when that is not the project that needs it? Beyond any debate about whether or not my logic herein makes good sense, I would like to offer that I have found a workaround. One may publish (Build Action is Content and Copy to Output Directory is Copy always) a .txt file from the infrastructure project to bin folder upon every build and scrape it like so:

private string[] ReadFromFlatFile()
{
   string path = System.AppDomain.CurrentDomain.BaseDirectory;
   path = path + "bin\\ApplicationNotes.txt";
   string text = System.IO.File.ReadAllText(path);
   return text.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None);
}

 
 

Your solution may be more elegant than mine above obviously.

 
 

Addendum 9/24/2018: What is above really shows off how to split a string with a string instead of a char. For example, this test would pass:

string copy = "Dirty dwarves dwell in dirty dwellings like dweebs.";
string[] parts = copy.Split(new string[] { "dw" }, StringSplitOptions.None);
Assert.AreEqual(parts.Length, 5);
Assert.AreEqual(parts[0], "Dirty ");
Assert.AreEqual(parts[1], "arves ");
Assert.AreEqual(parts[2], "ell in dirty ");
Assert.AreEqual(parts[3], "ellings like ");
Assert.AreEqual(parts[4], "eebs.");

Friday, November 15, 2013

ng-click in Angular

<a style="cursor: pointer;" ng-click="review(state.id)">{{state.status}}</a>

 
 

If you make an "a" tag like this, you will not immediately get the pointer cursor style so you may want to add it. The ng-click in Angular lets you run a function back in your controller when you click an "a" tag. An example of such a function:

$scope.review = function(obj) {
   $state.go("review", {status: obj});
}

 
 

This function would require you to have $scope and $state specified at your controller's signature.

assetControllers.controller('statusCtrl', ['$scope', '$state',
   function statusCtrl($scope, $state) {

 
 

The act our function facilitates is to allow one to pass a "status" parameter to a controller. In app.js I have defined "status" and also "search" as parameters one may hand stuff into (for "review") like so:

.state('review', {
   url: "/review?search&status",
   templateUrl: "templates/search.html",
   controller: "searchCtrl"
})

Expected response to contain an array but got an object.

If you are getting this Angular error then you need to use a .get from $resource in lieu of .query as suggested here, refactoring something like this:

var composite = "";
Assets.query({id: "whatever"}, function(outerData) {
   outerData.forEach(function(innerData) {
      composite = composite + innerData[0];
   });

 
 

...to something like this:

var composite = "";
Assets.get({id: "whatever"}, function(outerData) {
   for (var key in outerData) {
      if ((key).indexOf("$")) {
         composite = composite + outerData[key];
      }
   }

 
 

...note that we are now looping through a dictionary in lieu of an array.

Thursday, November 14, 2013

diving into Angular

<form role="form" ng-init="search()" ng-submit="search()">

 
 

Above, upon both loading and submitting the form, we will run this function in the appropriate controller:

$scope.search = function() {
   $scope.statuses = whatever;
}

 
 

Farther down our view we may loop through our data like so:

<tr ng-repeat="state in statuses">
   <td>
      <a ui-sref="detail.whatever({stateId: state.id})">
         {{state.label}}
      </a>
   </td>
   <td>
      {{state.data}}
   </td>
   <td>
      {{state.percentage}}%
   </td>
</tr>

Wednesday, November 13, 2013

iMessage

iMessage is the messaging service that iOS devices use to talk to each other. When you send a text to another user who has an iPhone you are not really sending a text because your phone is smart enough to send an iMessage instead. The iMessage communication is free. It is represented at your iPhone by a bright blue bubble instead of the green bubbles for texting. You can iMessage to regular Apple laptops too. This is yet another thing I've learned in working with smart people at my job.

I am finally using a CSS grid!

Twitter Bootstrap/SB Admin stuff:

<div class="row">
   <span class="col-lg-1">
   </span>
   <span class="col-lg-4">
      <div class="flot-chart">
         <div class="flot-chart-content" id="flot-chart-pie" style="z-index:100;"></div>
      </div>
   </span>
</div>

 
 

The grid seems to be twelve columns wide so I am filling a third of the screen's vertical space with my chart while "indenting" it a twelfth of the way in from the left edge!

Invalid dimensions for plot, width = null, height = null

...is an error I ran into trying to take the charting page in SB Admin and strip away everything but the pie chart. The /js/flot/chart-data-flot.js has all of the wireups for the awesome Flot Charts and I had to strip away the ones I destroyed back at charts.html to get rid of the error.

Hadoop

At the Austin .NET Users Group on Monday I saw Brock Reeve speak on Hadoop which is an ETL in which data gets mapped to key value pairs, shuffled, and then reduced. You write rules for Hadoop in Java and Facebook hated that so they wrote a tool called Hive which sits on top of Hadoop and lets you hand in SQL which gets recompiled to the Java rules. Stuff is kept midstream in HDFS (Hadoop Distributed File Systems) mostly, but one may also use cloud services like H3. Translate from HDFS to SQL Server with Scoop.

Tuesday, November 12, 2013

If you need a "method" within a Razor view you may nest a new helper within the view to accomplish as much.

@helper HideDesk(Fixture fixture){if (fixture == Fixture.Desk)
   {<text>Table</text>}else{<text>@fixture.ToString()</text>}}

 
 

Could be used like this:

@Html.Raw(String.Format("<div id=\"item13\" style=\"background-image:
   url('/Content/{0}.png');\"></div>", HideDesk(@Model.Fixture13)))

 
 

Note that I jammed the helper onto one line to ensure no extra spacing sabotaged my effect.

Destroy a workspace to get Jenkins to refresh files from a repository.

Your options are that or make a dummy commit to get rid local dirtiness after destroying some bad commits at the repository. A dummy commit is ghetto though.

Let NuGet get the missing dependencies for you.

In Visual Studio 2012 at: TOOLS > Options... > Package Manager > General ...check the checkbox for "Allow NuGet to download missing packages during build" to do just that.

Running tests from Grunt doesn't seem too tough to do.

"Up top" we have...

mocha: {
   test: {
      src: ['whatever.html'],
      options: {
         log: true,
         reporter: 'Dot',
         run: false
      }
   }
},

 
 

Farther down...

grunt.loadNpmTasks('grunt-mocha');

 
 

Farther down yet is a task to be called in a target:

grunt.registerTask('test', 'mocha');

Sunday, November 10, 2013

Check to see if an arrow key has been pressed in JavaScript!

Stealing this from here:

<script type="text/javascript">
   $(function () {
      document.onkeydown = function () {
         switch (window.event.keyCode) {
            case 37:
               alert('left');
               break;
            case 38:
               alert('up');
               break;
            case 39:
               alert('right');
               break;
            case 40:
               alert('down');
               break;
         }
      };
   });
</script>

Kayak

..."allows you to easily create TCP clients and servers" per its GitHub page.

script injection attacks in one page JavaScript apps

...is something that came up in conversation at a team outing Friday. Just hand in a script tag in a form field. Can you application deal with it? Yikes.

Saturday, November 9, 2013

RedirectToAction

...is the way to go to a different action in a different controller:

return RedirectToAction("Error", "Info");

Navigate hierarchies of what was once JSON when deserializing with Newtonsoft in C#.

To cast the value of "bar" to a string when "bar" sits inside "foo" which sits inside the greater JSON object you are to deserialize in C#:

JObject jObject = (JObject)JsonConvert.DeserializeObject(serialization);
string bar = jObject["foo"]["bar"].ToString();

The term metadata refers to "data about data".

Wikipedia tells us this.

I saw Tristan Slominski speak at JavaScript Austin on Kademlia DHT.

This talk was technically a talk on approaching distributed systems in the JavaScript space with Tristan Slominski making his way through a presentation touching on the Lambda Architecture of Nathan Marz, indeed.com's Boxcar, and course the fallacies of distributed computing which are:

  1. the network is reliable
  2. latency isn't a problem
  3. bandwidth isn't a problem
  4. the network is secure
  5. topology won't change
  6. the administrator will know what to do
  7. transport cost isn't a problem
  8. the network is homogenous
  9. the system is atomic/monolithic
  10. the system is finished
  11. business logic can and should be centralized

 
 

...but the reality was that while we skimmed other topics the evening focused on a heavy geek out on Kademlia DHT (distributed hash tables) and how the nodes within a DHT find each other and speak with each other. I'm not complaining though. It was very interesting to learn about how the technology driving BitTorrent worked under the hood. There is an exponential/logarithmic relationship between the number of nodes a system can support and the amount of neighboring nodes that anyone one node needs to know about. The variable k is specified to represent the number of comrades that any one participant knows of data of, and as this is a setting you drive in configuration, there is thus a need to really understand how DHTs work when using them. The data for the "friends" is stored at a node that has the friends. The snapshot may be old however. Here is how updating data works: A vector clock number gets incremented on each node when it is updated. When another node polls to make sure that its cache of what it thinks its friends have is up to date, it bases its need to update or not on the snapshot of the vector clock it has for a friend and the actual vector clock of the friend which may be greater. If it is greater, then the data cache at the polling node is updated. This concept is called gossip. Scuttlebutt reconciliation is the specific implementation of gossip here. Merkle trees are a way to nest hashes in hashes. These were mentioned too while phi accrual is for failure detection.

Friday, November 8, 2013

mocha stubs!

I had a dojo widget which procured log data from a dependency handed in at the AMD module's signature and then dumped gunk into a textarea from which a user could browse or copy/paste.

loggingLogger.readLogs(options).then(lang.hitch(this, function(logs) {
   var text = logs.map(function(log) {
      
//more mechanics here
      this.logViewerTextArea.innerHTML = whatever;

 
 

How may we test to ensure that while the textarea starts empty it ultimately gets content? Well, one pain point here turned out to materialize in the fact that the act happens within a promise. This did not cause heartache in mocha testing when tests were ran from an HTML test runner, but in Grunt...

  1. the promise caused false positives in testing until it was forcing back in test with mocha's done()
  2. the tests then crashed the build process as there was no Web SQL database to look into for logs

 
 

Alright, the first step is to "abstract way" loggingLogger so that it may be stubbed.

logger: function() {
   return loggingLogger;
}

 
 

In another refactoring we use the abstraction, replacing loggingLogger with logger. Note that this change and the one above both have to happen in the widget itself.

this.logger().readLogs(options).then(lang.hitch(this, function(logs) {
   var text = logs.map(function(log) {

 
 

In C# one stubs by writing methods which consume interfaces at their signatures and, then in testing, handing in dummy objects which inherit from the interfaces (in lieu of external dependencies which inherit from the interfaces), but in JavaScript one just replaces methods to external dependencies at a greater JavaScript object that one needs to test. An object to stub gets handed into a "factory" which then hands the object back out. During the trip through, the object is given some love. This is like a trip through an assembly line in a factory sure enough, wherein the subject will be spruced up. Think of the visitor pattern in C#.

//factory for stubbing LogViewer methods
define(["dojo/Deferred"], function(Deferred) {
   "use strict";
   function testLogViewerSetup(LogViewer) {
      
      
//stubbing out promise for populating log data
      LogViewer.logger = function() {
         var dummyReadLogs = {
            readLogs : function(options) {
               var deferred = new Deferred();
               
               
//faking log data
               LogViewer.logViewerTextArea.innerHTML = "data";
               setTimeout(function(){
                  deferred.resolve([]);
               }, 1);
               return deferred.promise;
            }
         }
         return dummyReadLogs;
      }
      
      
//end of factory
      return LogViewer;
   }
   return {
      testLogViewerSetup: testLogViewerSetup
   };
});

 
 

Note that I am putting "data" in the logViewerTextArea where I may do so without delving into the asynchronous realm. Also note the empty array in .resolve([]) which allows me to not care about having to fake log.map which would otherwise be a pain point if the promise handed anything else back. My test:

describe("when whatever", function() {
   var widget;
   var textarea;
   
   before(function() {
      widget = new LogViewer();
      widget = LogViewerFactory.testLogViewerSetup(widget);
      widget.callTheThingWhichCallsTheLogger();
      textarea = widget.logViewerTextArea;
   });
   
   it("should populate data", function() {
      assert.isTrue(textarea.innerHTML.length > 0);
   });
});

A method in JavaScript is a function that hangs off an object as a property.

This per: this!

Thursday, November 7, 2013

Specifying the .js in a define path for AMD module dependencies...

...means you are calling a specific path, not a relative one.

mocha done callback stuff

In mocha testing, you may use the "done" callback to test asynchronous code. This may come with some pains as Derick Bailey explains at his blog, but I was able to refactor the last of the two tests I show off here using "done" like so:

describe("when refresh is called twice yet some time apart", function() {
   var firstPromise;
   var secondPromise;
 
   before(function(done) {
      widget = new LogViewer();
      widget.postCreate();
      firstPromise = widget.refresh();
      firstPromise.then(function(){
         secondPromise = widget.refresh();
         done();
      })
   });
 
   it("should procure two separate promises", function() {
      assert.isFalse(firstPromise === secondPromise);
   });
});

 
 

This ensures that the test is really running in Jenkins/Grunt builds and not just making a green checkmark in the HTML test viewer that happens by way of a promise returned outside of anything your CI process might see.

 
 

Addendum 12/7/2018: The done trick is legit in Jasmine tests too.

Check to see if two JavaScript promises are the same promise in mocha testing with strictly equals.

var widget;
 
describe("when refresh is called back to back", function() {
   before(function() {
      widget = new LogViewer();
   });
 
   it("should not double load data", function() {
      var firstPromise = widget.refresh();
      var secondPromise = widget.refresh();
      assert.isTrue(firstPromise === secondPromise);
   });
});
 
describe("when refresh is called twice yet some time apart", function() {
   before(function() {
      widget = new LogViewer();
   });
 
   it("should procure two separate promises", function() {
      var firstPromise = widget.refresh();
      firstPromise.then(function(){
         var secondPromise = widget.refresh();
         assert.isFalse(firstPromise === secondPromise);
      });
   });
});

 
 

The widget is a dojo widget shaped in part like so to ensure that it will not spin up a promise at the refresh function if one is already in play:

postCreate: function() {
   this.refreshPromise = null;
},
 
refresh: function() {
   if(!this.refreshPromise) {
      
some stuff here...
      this.refreshPromise = whatever.doAct(options).then(lang.hitch(this, function(items) {
         
guts of the magic...
         this.refreshPromise = null;
      }),
         function(error) {
            this.refreshPromise = null;
      });
   }
   return this.refreshPromise;
}

Wednesday, November 6, 2013

Shelve in TortoiseHg

At: Repository > Shelve...
You will get an interface for moving edited files to the shelf and back from it which is so easy that I do not need to explain it. If a file is shelved, it behave as if you reverted it until you unshelve it.

May I cast my string to an integer in JavaScript?

One way to find out is like so...

if (!isNaN(parseInt(myThingInStringFormat))) {
   var useMeDownstream = parseInt(ahNewMeterValue);

 
 

Floats (as strings) will be rounded to integers in this approach. A good way to check if you may cleanly round what might be a float to an integer without dropping anything but zeros is:

var testing = parseFloat(ahNewMeterValue);
if (testing % 1 == 0) {
   alert('precision means nothing');
} else {
   alert('precision matters');
}

In time entry circumstances do not have the duration of an activity calculated off of inputs for the moment one got started and the moment one finished up.

This does not take lunch breaks into account. This system gets really silly when a task straddles several days as the worker is not working twenty-four hours without break, etc.

blue flash

A better way to solve the problem I was trying to solve here in Chrome is to only make divs that float with absolute positioning clickable if they do not sit inside of another div. Otherwise the div they sit within may turn blue.

a jQuery hack to get Chrome to stop holding a selection

...is to hide a form field out of sight (absolute positioning with a negative margin) and update it.

$("#deselecttrick").focus().val("deselecttrick");

update an HTML control by name in jQuery

$("[name='" + foo + "']").val(bar);

Tuesday, November 5, 2013

To change tabs to spaces in Sublime...

  1. select copy
  2. click on "Tab Size" at the lower right
  3. pick "Convert Indentation to Spaces" at the menu which pops up

when pushing an integer into a Web SQL Database column that expects a string...

...you may end up with a one point precision on your "integer"

When a function returns a promise.

var foo = iReturnPromise(bar, baz);
var qux = iDoSomethingElse(foo);

 
 

...will not work! (assuming iDoSomethingElse expects an object and not a promise) Instead, the way to skin this cat is...

 
 

var fooPromise = iReturnPromise(bar, baz);
fooPromise.then(function(foo) {
   var qux = iDoSomethingElse(foo);
});

Cast everything in a C# enum to a space separated string!

public static string Render()
{
   var values = Enum.GetValues(typeof(Fixture));
   string spool = values.Cast<object>().Aggregate("", (current, value) => current + value +
         " ");
   return spool.Trim();
}

Monday, November 4, 2013

There does not seem to be a good way to decorate a textarea with readonly and still be able to "select all" on its contents in iOS.

I went Googling for a way around this problem today and found some pseudosolutions, but none of them panned out.

overflow-y: scroll;

...as a CSS style will put a vertical scrollbar on a div. overflow-x: scroll; will moreover put a horizontal scrollbar on a div. Please note that the addition of overflow-y: scroll; alone will also empower horizontal scrolling if you have a string of unbroken copy that is wider than the div itself present within the div such as, perhaps, supercalifragilisticexpialidocious.

Saturday, November 2, 2013

sniff and set HTML element styles with jQuery

$(function () {
   var loop = function () {
      var style = $("#brain").attr('style');
         if (style == "display: none;") {
            $("#brain").attr('style', "display: block;");
         } else {
            $("#brain").attr('style', "display: none;");
      }
   };
   var interval = setInterval(loop, 2000);
});

Styles.Render versus Scripts.Render

@Styles.Render("~/Content/css")
&
@Scripts.Render("~/bundles/modernizr")

 
 
 
 

...will both go fishing in BundleConfig.cs in the App_Start folder of an ASP.NET Web API with MVC Visual Studio 2013 project. Where they will find...

 
 
 
 

bundles.Add(new StyleBundle("~/Content/css").Include(
   "~/Content/bootstrap.css",
   "~/Content/site.css"));

&
bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
   "~/Scripts/modernizr-*"));

 
 
 
 

...respectively. It is important to note the difference in the HTML that Styles and Scripts spit up to the browser however. The stuff above gives us back...

 
 
 
 

<link href="/Content/bootstrap.css" rel="stylesheet"/>
<link href="/Content/site.css" rel="stylesheet"/>

&
<script src="/Scripts/modernizr-2.6.2.js"></script>

 
 
 
 

...respectively.

Friday, November 1, 2013

mytextarea.setSelectionRange(0, mytextarea.value.length);

...is another way to NOT solve this problem. Hiss.

It turns out there is a way to spin a timer to wait for a JavaScript promise to resolve, you just have to use a piece of the DOM as a middleman.

widget.kickOffPromiseToUpdateTextArea();
var loop = function(){
   var textarea = widget.ourTextArea;
   var characterCount = textarea.innerHTML.length;
   if (characterCount != 0) {
      clearInterval(interval);
      alert('made it!');
      goDoSomethingElseWithFeedBack(textarea.innerHTML);
   } else {
      alert('not yet!');
   }
};
var interval = setInterval(loop, 6000);