Monday, September 24, 2018

Learning Ember in VS Code -- The First Event!


This is my continuing efforts to work with the Ember JS (www.emberjs.org) Framework. The expectation is to build a simple wish list of items.  Part one started the Ember application, part two started our first route and today we're actually going to have the application do something by having it respond to a mouse click.


Currently, the application shows a list. Not exactly ground breaking, or very useful.  So, what we need is to make the system respond to user interaction. Since this is the web, that interaction is a click event.  

To accomplish this, we add an action to the list item element in the items template.  The action helper takes in the name of the function to run, and the paramters for that function. for this function we'll name it "showItem" (and notice the casing for expected JavaScript styling) and pass it the item object that's referenced in the #each helper.

1
2
3
4
5
6
7
<h2>List of Items</h2>

<ul>
    {{#each model as |item|}}
    <li {{action "showItem" item}}><cite>{{item}}</cite></li>
    {{/each}}
</ul>

The default behavior for the action helper is to add a click event listener to the associated HTML element. This means that clicking the LI element will call the showPerson function from the items route class.

This means we need to modify the items route class file to add this function definition. For now, all we'll do is use an alert dialog to display the book title, later we'll make changes to display more information about the item. 

 1
2
3
4
5
6
7
8
9
10
11
12
import Route from '@ember/routing/route';

export default Route.extend({
    model(){
        return ['Friday', 'Dragon Riders of Pern', 'Foundation', 'Ringworld', 'RAMA'];
    }
    , actions: {
        showItem(item) {
            alert(item);
        }
    }
});

So, now our application is actually doing something.
Ember Alert
Next time, we'll be introducing how to share things appropriately. 

Monday, September 17, 2018

Learning Ember in VS Code -- The First Route


This is my continuing efforts to work with the Ember JS (www.emberjs.org) Framework. The expectation is to build a simple wish list of items.  Part one started the Ember application, while today's section works on adding the first route to the system, where we display a list of items.
The first thing to do is modify the Application.hbs file (found in app/templates/application.hbs) and replace its contents with the below. 

1
2
3
<h1>Wish List</h1>

{{outlet}}

Now, we want to add a route to the system, specifically a route which provides a list of products that need to be shown. Luckily, Ember has a number of generators that make the creation of boilerplate code for common tasks simple and easy.  What this means in practice is that we need to run the below command inside our current Ember application's directory


1
ember generate route items

This command generates the template seen when the user visits the "/items" route, the actual route logic in the application router, and a route object which fetches the model to be used by the template. And you get a unit test. 
So, our first step is to go manipulate the template.  Open the "items.hbs" file found in app/templates and and an h2 tag with the text "Items."  An {{outlet}} line should already exist, and needs to remain for right now. 
After saving, you will be able to navigate to http://localhost:4200/items, and see the new page.
Of course, a template is not much use without the model to display the details of.  So, let's open up the items.js file from the "app/routes" folder.
The boilerplate has an import statement, and the standard extension statement.  We need to add a "model" method. The important part here is that the model method supports any library that uses JavaScript promises. For now, though, we just want to return a simple array.  So, modify the code until it looks like the below:

1
2
3
4
5
6
7
import Route from '@ember/routing/route';

export default Route.extend({
  model() {
    return ['Friday', 'Dragon Riders of Pern', 'Foundation', 'Ringworld', 'RAMA'];
  }
});

Once that's changed, then the model is returning an array of items. In this case, a list of book titles.  Our next step is to tell Ember  how we want to display the array. We need to return to the items template, and add the code to make the program loop through the array and print its contents. 

1
2
3
4
5
6
7
<h2>Items</h2>

<ul>
    {{#each model as |item|}}
    <li><cite>{{item}}</cite></li>
    {{/each}}
</ul>

So, using the "each" helper, we create a list of book titles, also notice the use of the "CITE" tag to emphasis that his is a title. 

Monday, September 10, 2018

Learning Ember in VS Code -- Getting Started


This is a headache and a half.  I mean, I've just spent the past 15 years building ASP.Net applications utilizing WebForms, and was quite happily doing so.  But, an upcoming project has needs; and those needs aren't best served by the traditional WebForms model of ASP.Net.  So, I took a look around and started brainstorming. 

And discovered three big ones. 
  1. React JS (www.reactjs.org)
  2. Angular JS (www.angularjs.org)
  3. Ember JS (www.emberjs.org)

Angular JS has been replaced with just Angular (www.angular.io), which is more monolithic than before. Not a good idea for dealing with initially learning these things. 

But also looking at things, Facebook creates React and Google creates Angular, and Microsoft has .NET starter projects for both.  Which leads to good thoughts towards them. They appear more stable than other options.  But at the same time, they're made by Facebook and Google; and I'm certain those organizations use them in their own applications, which means that their needs are the primary driving force behind both libraries.

Which means that Ember kind of wins in my opinion.

In truth though, all three are kind of the same. You have to have Node.js installed, and then you can use NPM to get the relevant frameworks.  

Building a simple website is just as easy, as it follows a simple paradigm:
  1. Use NPM to perform base configuration 
  2. Add Class to handle things 
  3. Make class do something 
  4. compile and display in browser 

And while that's the 50,000 foot view, that's basically all there is in getting the page to say "Hello World." 

Of course, there's specific details involved, and like I said, I choose Ember.  

First thing is to install it. Which is really just launching Visual Studio Code, opening the terminal (CTRL+`) window and entering the following command: 
    npm install -g ember-cli 

Or just go to the marketplace, or more specifically this page: https://marketplace.visualstudio.com/items?itemName=felixrieseberg.vsc-ember-cli

To begin, open the embedded terminal found within VS Code (CTRL + `) and enter the command to generate a new Ember project (I'm calling mine "ember-learn":
    ember new ember-learn 

What happens, is that the Ember CLI creates a directory in your current working folder named whatever you called your project, and sets up a new Ember application inside of it. 

Once that's done, use the CD command to go into the folder.  

VS Code Example 1Then, since we're using VS Code, use the "Split Terminal" command to create a new terminal window. This is useful, as you will be able to interact with NPM and the EMBER CLI from one window, and have Ember serving the application from the other.  

Once you've split the terminal window, CD to the new folder from that second window and then enter the command:
    ember serve

Note: if you get a message stating "Running without permission to symlink will degrade build performance" then run either VS Code (or your command window) as an Administrator. 

Pointing a browser at the provided localhost port (http://localhost:4200) will get you the compiled website. 

VS Code Example 2

But since I'm wanting a "Hello World" thing, the page currently doesn't say that.  So we need to do a bit of editing to get there. 

And that means making an edit at the root of the application.  Ember provides a template for things that are always shown on the page. This file (application.hbs) is found in the "app/templates" folder. 

VS Code Example 3
I just replaced everything there with the following lines: 
1
2
3
4
<h1>Learning Ember</h1>
<h2>Hellow World</h2>

{{outlet}}
You need the "{{outlet}}" bit, as that's where the nested routes will be rendered.  Important bit there.

Anyways, the system should have detected the change, recompiled, and reloaded the page while you were saving.  



Monday, September 3, 2018

Simple Programmer -- Blogging Course


After my realization regarding the technical debt I was accruing, I made a greater effort to consume information about programming and being a programmer on both hard and soft skills.  One of the ways I did this was turning over my commute time (roughly 40 minutes each way) to listening to programmer based podcasts rather than the radio, and a second way was I bought a couple of books on development.  

What's amusing is that both things led me to John Sonmez.  At this time, I can't remember exactly which podcast it was, but they had an interview with him regarding learning, just being a good programmer and his blog/company Simple Programmer (https://simpleprogrammer.com). And I had also purchased his book The Complete Software Developer's Guide (https://www.amazon.com/dp/B073X6GNJ1) on my Kindle.

So of course I read the book and in the process surrendered my email for some additional content. Which of course got me on a mailing list. 

So here I am, reading this book, listening to podcasts, a number of which focused on "soft skills" and other things just trying to get caught back up, when an item from that mailing list appears offering me the option of enrolling in a email-based blogging course (https://simpleprogrammer.com/blog-course). 

I couldn't argue with the cost (Free!), so I thought why not. 

I mean I have a programming blog, and have had one for a decade now. The first post on it was December of 2006 and I posted quite regularly for the next 5 years, generating a bit over 200 posts until life (2 young kids and a wife) and work apparently overwhelmed my posting schedule.  As an unrelated aside, I also had a SF/Geek-life blog that had nearly twice that many posts in the same time frame. 

So, I had this blog that had not had any new content in seven years, I knew that the best way for me to internalize new information and knowledge was to write about it, and I had just signed up for a blogging course for programmers. 

I'm not going to lie, there is nothing truly new in this course that I'd not seen previously.  It's a solid, well thought out presentation of those elements, and condensed for ease of consumption. 

But I'm also fairly certain that I'm not quite exactly the desired audience as I had ran a blog in the past, and had let it lapse as the time I spent on it was rededicated to my family and completing customer projects at work.  And while I have no complaints regarding the extra time that it gave me with my kids, I also realized that writing the blog was something that kept me learning, and kept my brain engaged. 

Scott Berkun has a book entitled The Dance of the Possible: the mostly honest completely irreverent guide to creativity, and has this to say about creativity:
The word create is a verb. It’s an action. Creativity is best thought of in the same way—it’s something you can use while involved in an activity, like painting, writing, debating or dancing.
Berkun, Scott. The Dance of the Possible: the mostly honest completely irreverent guide to creativity (p. 9). Berkun Media LLC. Kindle Edition.
And this is what the blog was for me. It kept me creative and engaged. It was a verb aspect of how I learned about my craft.

Which is why I think every developer needs one, or a podcast, or a twitch stream, or something that allows them to create and to internalize as they learn.

Monday, August 20, 2018

Using PLUpload with ASP.Net


It's a fairly common use case scenario in which one must allow their users to upload files into a web system for various means. Of course, in the situations I find myself, I need to allow this to happen, and I don't necessarily have a maximum size allowed for the file to be processed.  It's been a while since I last looked into uploading files, and even then I just used the traditional Input Type='File' control that's a part of the standard suite of HTML4 form elements.

Of course I had to push up the number of bytes that were allowed up at any given time, but it was still the simple file upload control. 

Fast forward a few years, and I knew there had to be a better solution. Or at least I hoped there was. 

Prayer was involved as well.  Just saying. 

Anyways, I stumbled into a nice deep hole which involved things like chunking, iFrames, Silverlight and Flash movies.

With a day of research and writing JavaScript already behind me, I  decided that running face first into the brick wall of the exterior of the office would be more productive than continuing the path I was on.  

So, I started looking for controls. 

And quickly found the Telerik suite of controls. Of which I wanted just the one. Sadly, they don't sell them that way. To use the Telerik upload control, I would have to buy the other dozen or so controls I did not need, want or would ultimately use.  And the DevExpress version was bundled in the exact same way. 

So, I continued my search. 

And found PLUpload (https://www.plupload.com/).

A quick download, 10 minutes of reading documentation, and then about two hours of coding, I was streaming chunks of data up to my development web server, and into the database. 5 more minutes, I was then generating a link which I could click that would stream those chunks back to me as the image they started life out as. 

My .ASHX had a fairly straightforward logic built into it, and looked like this: 
 Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        context = context
        Request = context.Request
        Response = context.Response
        sessionId = Request.Cookies("uploadSessionId").Value
        If Request.Files.Count > 0 Then
            Dim fileUpload As HttpPostedFile = Request.Files(0)
            Dim fileName As String = fileUpload.FileName
            If String.IsNullOrWhiteSpace(fileName) Or String.Equals(fileName, "blob") Then
                fileName = If(Request("name"), String.Empty)
            End If 'String.IsNullOrWhiteSpace(fileName) Or String.Equals(fileName, "blob")
            Dim tstr As String = If(Request("chunks"), String.Empty)
            Dim chunks As Integer = -1
            If Not Integer.TryParse(tstr, chunks) Then chunks = -1
            tstr = If(Request("chunk"), String.Empty)
            Dim chunk As Integer = -1
            If Not Integer.TryParse(tstr, chunk) Then chunk = -1
            ' If there Then are no chunks sent the file Is sent As one this likely a plain HTML 4 upload (ie. 1 single file)
            If chunks = -1 Then
                fileName = IO.Path.GetFileName(fileName)
                If Not onUploadStart(0, 1, fileName) Then Return
                If onUploadChunk(fileUpload.InputStream, 0, 1, fileName) Then
                    onUploadComplete(fileName)
                    WriteSucessResponse()
                End If ' onUploadChunk(fileUpload.InputStream, chunk, chunks, fileName)
                Return
            Else ' chunks = -1
                If chunk = 0 Then
                    If Not onUploadStart(chunk, chunks, fileName) Then Return
                End If
                If onUploadChunk(fileUpload.InputStream, chunk, chunks, fileName) Then
                    If chunk >= chunks - 1 Then
                        onUploadComplete(fileName)
                    End If ' chunk >= chunks - 1
                    WriteSucessResponse()
                End If ' onUploadChunk(fileUpload.InputStream, chunk, chunks, fileName)
                Return
            End If ' chunks = -1
        End If ' Request.Files.Count > 0
    End Sub

Basically, I check for something on the FILES upload, and check how many chunks are supposed to be sent for this file, and which chunk this particular file item is.  The behavior is slightly different for a file that has a single chunk (if chunks = -1), but the basic steps are:
  1. If the first chunk, do upload start (in this case, create a record in the db indicating a file is upload, and the user its associated with)
  2. Save the uploaded chunk somewhere 
  3. if this is the last chunk, tell the db that all chunks are uploaded

Then performing the actual file saving aspects, went something like this:

    Private Function onUploadChunk(fs As IO.Stream, chunk As Integer, numberOfChunks As Integer, fileName As String) As Boolean
        Dim newFileName As String = ""
        Dim stream As IO.Stream
        Try 
            // set newFileName from DB
            Dim uploadFilePath As String = IO.Path.Combine(Me.fileLocationPath, String.Format("{0}.{1}",newFileName , chunk.ToString("#000")))
            If IO.File.Exists(uploadFilePath) Then IO.File.Delete(uploadFilePath)
            stream = New IO.FileStream(uploadFilePath, IO.FileMode.OpenOrCreate, IO.FileAccess.Write)
            fs.CopyTo(stream, 16384)
        Catch ex As Exception
            ' Need to set status on this file to bad, as  a chunk failed to upload....
            WriteErrorResponse(ex.Message, 100, True)
            Return False
        Finally
            If stream IsNot Nothing Then stream.Dispose()
        End Try
        Return True
    End Function

Again, fairly straightforward code.  Though a few thinks, my logic records the file that this is, into the database, that means that the file that I'm saving to the file-system, only has a GUID for a name. Then the chunks are given an extension of which chunk they actually are. 

Now, I just need to find the best solution for scanning the files as they're uploaded into the network. 



Monday, August 13, 2018

Technical Debt


 Wikipedia defines technical debt as: 
A concept in software development that reflects the implied cost of additional rework caused by choosing an easy solution now instead of using a better approach that would take longer. 
Which is as good of a definition for that as I've seen.  But it doesn't tell the whole story. 

But it's not the definition I think of when I reference it.  And I know that this will get people all sorts of bent out of shape, but when I hear technical debt, I also consider it more along the lines fo this: 

The implied cost of additional work caused by stagnating on the learning of technical concepts, processes, standards or behaviors. 

You can accrue technical debt by choosing the easy solution, instead of the best solution.  But at times, customers can only afford the easy solution now. 

You can accrue technical debt by building project after project using the sames methods and methodologies time after time.  And never looking at newer frameworks and just how other people are doing things.  By not learning things like .NET Core or Node.js because ASP.Net Webforms just work. 

And that's the type of technical debt that I've recently realized that I've been accruing.  I've not learned these new things, because what I've been doing works.  What I'm doing, how I'm building software, is not wrong, it's just I'm blind to the possibility that it's not the best solution for the issue I'm solving.  

Which in turn, drives that initial definition of choosing an easy solution now instead of a better approach that may take longer. 

Monday, October 31, 2011

eComic 2012

Well, I'm in the process of ripping apart eComic and rebuilding it from scratch.

The two biggest aspects that will be changed (from the user's POV) are the inclusion of comic properties and library functions. 

eComic 2012
Well, not so much library functions as card catalog functions. Additionally, I'm modifying the UI to allow multiple tabs of comics being open (again--I keep going back and forth on this), and structuring it around a UI layout which I'm highly familiar with: Visual Studio.

As you can see from the image to the right there, it contains the tabbed interface, plus allows for the LIBRARY to reside in an tab all its own, as well as the PROPERTIES element to be always available.

I'm also keeping the ribbon menu, as I really like Ribbon menus. I'm trying to decide if I want to continue using the circle style application menu (as it exists in the previous version), or go with the square one as shown in the image.  I'm not going to lie, I made the icon with the thought that it would fit within the circle-style application menu.

The first aspect of a LIBRARY system that I implemented is the FAVORITES screen. This will also be the start-up screen when a user comes into the application. Each favorite is click-able, and when clicked loads the associated comic into the reader.

The FAVORITES screen will also be the basis for the lists screen (and search results screen) once I get all the library tools built.

I also made the system much more MVVM friendly. 

In the previous version, MVVM was there, but there was still a lot of manual control of the displayed page. Basically, the Reader control was responsible for both loading the pages into the ComicBook class, and controlling which page was selected at any given moment.

I've now made that all controlled via the ComicBook class via Databinding to the relevant list controls.  Sure, I can manually modify that with a next/previous and Go To functions, but the primary navigation is now controlled entirely via binding processes.

My next steps are to get the LIBRARY working, and to determine if I want this system to watch files, or if I want it to just control the files that are associated with it. There's pros/cons associated with both paradigms, and I'm not sure which is best. 

Sadly, I fear I may have to install iTunes and waltz through it, and figure out what it's doing with its media functionality.

The Kindle software makes more sense (everything's in its folders) but it also has the benefit of being the front-end of a store. The primary way you get content into Kindle is by purchase via KindleStore, and that's just not the case for my software; as the primary way you'd get content for eComic is to either a) download it, or b) media shift the comics that you've purchased.

Additionally, the Zune library works this way, by creating folders and what not on an as-needed basis in a way that makes sense to the software. And that sense tends to be: \\\.mp3

I'm not sure that would work for me, as I have so many fields to consider: Series, Issue Title, Alternate Series Title (i.e. Story Arc Title), Volume, Book Number, Artist, Writer, Publisher and finally Publish Date.

Oh well, I'm sure I'll figure out some sort of solution.


Blog Widget by LinkWithin