FreeCodeCamp and Learning Node: Make It Modular

This one drove me nuts, I’ll admit it.  The directions were sparse, but eventually I figured it out.  You can’t just copy-paste from the previous exercise where we filtered I/O, though at first it seems like you can.  Turns out there’s a lot of extras thrown into this one, such as error checking.

Okay, let’s look at the Instructions and hints:

 

MAKE IT MODULAR (Exercise 6 of 13)

This problem is the same as the previous but introduces the concept of modules. You will need to create two files to solve this.

Create a program that prints a list of files in a given directory, filtered by the extension of the files. The first argument is the directory name and the second argument is the extension filter. Print the list of files (one file per line) to the console. You must use asynchronous I/O.

You must write a module file to do most of the work. The module must export a single function that takes three arguments: the directory name, the filename extension string and a callback function, in that order. The filename extension argument must be the same as what was passed to your program. Don’t turn it into a RegExp or prefix with “.” or do anything except pass it to your module where you can do what you need to make your filter work.

 

The callback function must be called using the idiomatic node(err, data) convention. This convention stipulates that unless there’s an error, the first argument passed to the callback will be null, and the second will be your data. In this exercise, the data will be your filtered list of files, as an Array. If you receive an error, e.g. from your call to fs.readdir(), the callback must be called with the error, and only the error, as the first argument.

You must not print directly to the console from your module file, only from your original program.

In the case of an error bubbling up to your original program file, simply check for it and print an informative message to the console.

 

These four things are the contract that your module must follow.

   » Export a single function that takes exactly the arguments described.
   » Call the callback exactly once with an error or some data as described.
   » Don’t change anything else, like global variables or stdout.

» Handle all the errors that may occur and pass them to the callback.

The benefit of having a contract is that your module can be used by anyone who expects this contract. So your module could be used by anyone else who does learnyounode, or the verifier, and just work.

 ─────────────────────────────────────────────────────────────────────────────

## HINTS

Create a new module by creating a new file that just contains your directory reading and filtering function. To define a single function export, you assign your function to the module.exports object, overwriting what is already there:

 

module.exports = function (args) { /* … */ }

 

Or you can use a named function and assign the name.

To use your new module in your original program file, use the require() call in the same way that you require(‘fs’) to load the fs module. The only difference is that for local modules must be prefixed with ‘./’. So, if your file is named mymodule.js then:

var mymodule = require(‘./mymodule.js’)

 

The ‘.js’ is optional here and you will often see it omitted.

 

You now have the module.exports object in your module assigned to the mymodule variable. Since you are exporting a single function, mymodule is a function you can call!

Also keep in mind that it is idiomatic to check for errors and do early-returns within callback functions:

     function bar (callback) {
       foo(function (err, data) {
         if (err)
           return callback(err) // early return
         // … no error, continue doing cool things with `data`
         // all went well, call callback with `null` for the error argument
         callback(null, data)
       })

}

Let’s tackle the module first.  Basically, by module, we mean a separate file.  The hints give you module.exports = function (args) { /* … */ }, except it turns out that’s not as helpful as it looks.

 

First thing to realize is that since you’re going to be calling the fs.readdir and path packages, you need them to be required at the beginning of the file.  That’s the easy part!

Next, we add the line given above.  Now, you see the part in parentheses that says args?  Yeah, well, the directions state that you need to have the module export a function that takes THREE arguments and that is very clearly only ONE.  So, what would those arguments be? The directions tell us: “the directory name, the filename extension string and a callback function, in that order.”

 

So, let’s add those:

var fs = require('fs');
var path = require('path');
module.exports = function (filename, extsn, callback) {

});

 

So far, so good.  But, what do we put inside that function?

First, the directions tell us not to modify the extension in the main program, and we know from the last exercise that we’ll need a dot in front of it when we run the path.extname() method.  So let’s add a dot:

extsn = "." + extsn;

Next, we need to read the directory.  We did this in the last assignment, so we’ll just copy that over:

fs.readdir(filename, function callback(err, list) {
 /* do stuff here */
});

We need to handle any errors that pop up, so we’ll add the error catching routine the specify above:

fs.readdir(filename, function callback(err, list) {
 if(err) {
 return callback(err);
 }
 /* do stuff here */
});

If there’s no error, we want to run the filtering routine.  I had the routine add the files that matched extensions to a new array, called ansArray (Answer Array) and the function returns that.  The filter is similar to what we did before, using a loop and comparing the extension retrieved by path.extname() to the extsn variable we passed to the function.  If they match, we push the item into the array.  So, we have:

fs.readdir(filename, function callback(err, list) {
     if(err) {
         return callback(err);
     } else {
         for (var item = 0; item < list.length; item++) {
            if (path.extname(list[item]) === extsn) {
                ansArray.push(list[item]);
            }
         }
     /* do stuff here */
});

To return ansArray, we use the other line they give us in the hints – callback(null, data):

return callback(null, ansArray);

That’s it.  Here’s the complete mymodule.js :

MODULE (mymodule.js):
var fs = require('fs');
var path = require('path');
var ansArray = [];

module.exports = function (filename, extsn, callback) {
extsn = "." + extsn;
fs.readdir(filename, function (err, list) {
if(err) {
return callback(err);
} else {
for (var item = 0; item < list.length; item++) {
if (path.extname(list[item]) === extsn) {
ansArray.push(list[item]);
}
}
return callback(null, ansArray);
}
});
};

After all that, the main program itself is relatively simple.  First, we assign the directory path (element[2] of process.argv) to a variable called filename (because I never got around to changing it from the previous exercise), and then we assign the extension for which we are hunting (element[3] of process.argv) to a variable called extsn.  Finally, as noted in the hints, we require mymodule.js.

Next, we call mymodule, which is a single function, and we call it with three arguments, as specified.  We send it the directory path, the extension on which to filter, and a callback function.  We handle any error it passes back to us.  Then we print out the results using a loop and iterating through list.  Here’s the program:

 

PROGRAM (program5.js)

var filename = process.argv[2];
var extsn = process.argv[3];
var mymodule = require('./mymodule.js');

mymodule(filename, extsn, function(err, list) {
if (err) {
console.log(err);
}
for (var j = 0; j < list.length; j++) {
console.log(list[j]);
}
});

And there we go!  See you next time!

Advertisements

FreeCodeCamp and Learning Node: Filtered LS

This one is similar to the previous two exercises except that instead of a file, we’re reading a directory’s contents.  So, we can use those as a jumping-off point.  The filter itself is simple as well – I didn’t call an outside function like I would with a program in the browser.  Hold that thought, though….we’ll see it again later!

As usual, if you haven’t at least attempted this one, GO TRY IT FIRST!  The description below makes it seem like I put this together easily and quickly, but truthfully, it took me awhile to get it, and there were a few false starts and rabbit trails.  So don’t get discouraged if you don’t get it right away!

For now, let’s take a look at the directions and hints for this exercise:

FILTERED LS (Exercise 5 of 13)

  Create a program that prints a list of files in a given directory, filtered by the extension of the files. You will be provided a directory name as the first argument to your program (e.g. ‘/path/to/dir/’) and a file extension to filter by as the second argument.
  For example, if you get ‘txt’ as the second argument then you will need to filter the list to only files that end with .txt. Note that the second argument will not come prefixed with a ‘.’.
  Keep in mind that the first arguments of your program are not the first values of the process.argv array, as the first two values are reserved for system info by Node.
  The list of files should be printed to the console, one file per line. You must use asynchronous I/O.
 ─────────────────────────────────────────────────────────────────────────────
 ## HINTS
  The fs.readdir() method takes a pathname as its first argument and a callback as its second. The callback signature is:
function callback (err, list) { /* ... */ } &amp;amp;amp;nbsp;

where list is an array of filename strings.

Documentation on the fs module can be found by pointing your browser here:

file:///home/ubuntu/.nvm/versions/node/v4.4.3/lib/node_modules/learnyounode/node_apidoc/fs.html

You may also find node’s path module helpful, particularly the extname method.

Documentation on the path module can be found by pointing your browser here:

file:///home/ubuntu/.nvm/versions/node/v4.4.3/lib/node_modules/learnyounode/node_apidoc/path.html

The documentation link, as I’ve mentioned before, is

https://nodejs.org/dist/latest-v6.x/docs/api/

So, we’re going to start this one the same as last time, with the require statement for fs.  Then, they got a little sneaky.  If you actually go to the documentation page for path, you’ll see that it needs its OWN require statement.  They don’t tell you that, so get in the habit of checking the documentation!

Next, process.argv[2] is … well, actually, here it’s a directory path, so I should have named it dirPath or something.  Anyway, I copied it from before.  They note above that element[3] in the arguments is the extension we’re filtering for, so I assigned that (process.argv[3]) to the variable extsn.  They also note that the extension will come without a “.” added to it, so I added that as well.  So far we have:

var fs = require('fs');
var path = require('path');
var filename = process.argv[2];
var extsn = "." + process.argv[3];

Okay, we’re done declaring variables.  On to the meat of the program!  We next add the fs.readdir() function with the same arguments we gave the fs.readFile() function before:

var bufFile = fs.readdir(filename, function callback(err, list) {&nbsp;
});

As noted above, filename is really the directory path.

 

We need to make sure there’s no error – if(!err) – and then we need to loop through each of the files in the directory.  It’s not immediately clear, but the files are contained in ‘list’ in the fs.readdir() method above.  So, we loop through list.

path.extname() pulls off the the last three characters of the filepath and the dot (that’s why we needed to add a dot to extsn).  So, as we loop through each item in list, we’ll compare the item’s extension as returned by path.extname() to extsn and if they’re the same, we’ll write the file’s name to the console.

for (var item = 0; item &lt; list.length; item++) {

 if (path.extname(list[item]) === extsn) {
 console.log(list[item]);
 }

 

And that completes the program!  Here’s the whole thing, for reference:

var fs = require('fs');
var path = require('path');
var filename = process.argv[2];
var extsn = "." + process.argv[3];

var bufFile = fs.readdir(filename, function callback(err, list) {
if(!err) {
for (var item = 0; item < list.length; item++) {

if (path.extname(list[item]) === extsn) {
console.log(list[item]);
}
}
}
});

See you next time!

Theology 101: A Little Aquinas, Part 4

Last time we looked at Aquinas’ thoughts on law and morality, as well as sex.  Today, we’re going to look at War, including Jus ad Bellum and Jus ad Bello, and how Aquinas looked at women, as well as what he night have though of some of today’s controversial issues.

Chapter 7: Just War and Double Effect

In this chapter, Renick discusses Jus ad Bellum, Jus in Bello, and double effect.  He notes that  in 1991, before Gulf War I, George Bush (41) stated the reasons for going to war against Iraq (which at the time had occupied Kuwait).  These reasons described why he felt it was a just war.  For it to be so, it needed a just cause, to be declared by a legitimate authority, to be a last resort, and to have a just intent.  Bush listed reasons why each of these criteria was satisfied.

A war, while seemingly as far from moral as it can get, can be just according to international law, if it follows the rules Bush cited in his speech.  If this is thought to be an oxymoron, it can be compared to the actions the Nazis in World War II, or perhaps the Khmer Rouge, among others.  No, “morality,” Renick writes, “places important restraints on actions even during the heat of combat.” Aquinas played a major role in codifying this.

 

Christians have had to reason about just war since the 4th Century, when they went from being a persecuted group to the official religion of the Roman Empire.  Before that, they considered themselves pacifists.  After, they asked themselves if standing by while innocent people were slaughtered was in line with loving your neighbor – obviously, history shows they decided that intervening was the right thing to do.

Augustine was one of the first to give an affirmative and “taught that it was acceptable, even mandatory, for Christians to use violence – if they did so in a limited fashion and in order to protect the innocent.”  As a matter of fact it was Augustine that first coined the term “Just war”.  Eight centuries later, Aquinas developed this concept to the form we see today.

He deals first with Jus ad bellum – Latin for “right or justice (at the time of) war.”  This describes the “criteria that must be met before one can rightfully go to war.”  There are three, all of which must be met in order to begin hostilities:

  1. Just cause – Aquinas: “A just war is…one that avenges wrongs, when a nation or state has to be punished for refusing to make amends for wrongs inflicted by its subjects, or to restore what it has seized unjustly.”
  2. Just authority – referring to the leaders of countries, he writes, “Just as it is lawful for them to have recourse to the sword in defending the common weal against internal disturbances…so too it is their business to have recourse to the sword of war in defending the common weal against external enemies.”
  3. Just intent – restoring justice is the correct reason, not, as Aquinas wrote, “the passion for inflicting harm, the cruel thirst for vengeance…the lust of power, and such like things.”

Next, he dealt with jus in bello, or “right/justice in war” – what you can do during conflicts.  It is here that Aquinas introduces the concept of “double effect”.  Renick writes, “Double effect is a moral concept that has found its way into our contemporary civil and criminal legal codes, has emerged as a cornerstone of medical ethics, and has become a sticking point in the modern abortion debate.  It also establishes the basic standard for determining how one must treat noncombatants in times of war.”

Writes Aquinas: “Nothing hinders one act from having two effects.”   One effect can be good and the other bad – what does one do in this situation?  A simple example in going to the dentist.  To fix your bad tooth she must cause you pain in the short term.  A bigger example is saving the baby or saving the pregnant mother, or bombing a chemical factory next to a school.

Historically, there are Christians that followed the principle of do no harm.  This Aquinas found to be impractical – consider the dentist case.  If she does no harm and refuses to pull your tooth, you will end up worse off than if she in the short term causes you pain.  Aquinas then says, if one effect is intended “while the other is beside the intention…Moral acts take their species according to what is intended, and not according to what is beside the intention, since this is accidental.”  The dentist intends good – fixing your tooth – and not evil (the pain of the drilling).  However, if she is sadistic and causes you pain on purpose, then her intent is wrong, and the act is wrong.  The result does not justify the intent.  This can also be seen in our modern concept of accidental manslaughter – your intent was not to kill anyone, versus 1st degree murder, where your intent certainly was to kill someone.

This is also applied to jus in bello – soldiers should never intend to kill civilians or innocents.  They may die by accident, but this is not the same as targeting them.  The example of the munitions factory by the school shows that if you bomb the factory and the school is destroyed, your intent was to stop the enemiy’s war production, not to kill children.  This is euphemistically termed collateral damage.  However, if you bomb the school to demoralize the enemy, your intent is wrong.

But, there is another dimension to double effect – the good effect must outweigh the accidental effect.  Aquinas: “And yet, proceeding from a good intention, an act may be rendered unlawful, if it be out of proportion to the end.”  If you kill hundreds of schoolchildren just to take out an enemy tank, for example, your intent was good, but the bad side was way out of proportion to what you achieved.  So, you must ask:

  1. “Do you intend the good (and not the evil) end?”
  2. “Does the good end outweigh one?”

The answer to both must be yes.

Chapter 8: Abortion, the Role of Women, and Other Noncontroversial Issues

Catholics (macengr – and most of the rest of us) see abortion as not meeting the standards of the double effect philosophy.  The end is evil – an innocent person dies, and the intent is evil – the mother doesn’t want to bear the child.  Renick then attempts to justify a certain case of abortion using Aquinas’s arguments.

This case is when the mother’s life is threatened, for example when the egg implants in the fallopian tube.  He feels that Aquinas would have said that it is morally permissible to remove the baby.  The good end is saving the mother’s life; the bad end is that the baby dies.  But here, says Renick, the intent is good – to save the mother’s life, and not to kill the baby.  The death of the baby, per the discussion above, is accidental, not intentional, and who knows, by some miracle the baby could live…Also, if nothing is done, both the mother and baby die, and if you remove the baby, only one dies, so the result is better than choosing not to do anything at all (the result is proportionate to the harm done).  Thus, Aquinas, Renick thinks, would “approve” of this abortion.

(macengr – I totally do not agree with this argument, especially because Renick uses zygote instead of baby to make his argument more convincing to the reader.)

So Aquinas, Renick thinks, is very much a modern thinker and was ahead of his time.  But there is always a catch, and Renick points out that Aquinas’ view on women were very much a product of the times, and illustrates, to Renick, a drawback of the natural law approach.

Here, Aquinas felt that women are men’s helpers by nature, and that their primary usefulness is that of childbearing.  He writes, “It was necessary for woman to be made as a helper to man; not, indeed, helpmate in other works, as some say, since man can be more efficiently helped by another man in other works; but as a helper in generation.”  Men are therefore more useful when it comes to intellectual conversation or building things, and women are bad at these by nature.  Women, Renick claims that Aquinas says, are a pale imitation of a man.  Although both genders are needed to reproduce – here Renick quotes Aquinas again: “man is yet further ordered to a still nobler vital action, and that is intellectual operation.”

Thus, Aquinas says, there is a natural hierarchy between men and women, and the male should always be in charge.  He writes, “For good order would have been wanting if some were not governed by others wiser than themselves.  So by such a kind of subjection woman is naturally subject to man, because in man the discretion of reason predominates.”  This inequality between men and women was the reason for Eve’s sin, not the result.  Aquinas is arguing that the essence of woman is to be subject to man – it’s part of God’s plan.  The sin in the garden was not only humans disobeying God’s command not to eat the fruit, but also of woman usurping the man’s authority.

Women are also, Aquinas says, only the container that human life is born in and do not contribute to their characteristics (no genetic material from the mother).  Aquinas’s views on women would go on to become very influential; although they were really a reflection of his times.  However, that men were superior to women was seen, after Aquinas, as a cornerstone of the natural law and science and it was felt to be a rational fact, even apart from the religious context.

So, Renick says, we must be careful when we use natural law, because there is a “need to distinguish between what is and what should be.”  Aquinas lived in a monastery and avoided women and had little experience with them throughout his life, spending his time in primarily male environments from the time he was five years old.  At the time he lived (the 1200s) women were seen as inferior, were subject to men, and were rarely educated.  Of course, Renick says, Aquinas would think this was the natural order of things.

However, Renick says, “using the natural law demands that we do more than report on the way things are.” Just because murder occurs all the time – and scientists believes violence may have a genetic component – doesn’t mean it is natural.  “What is is not always what should be.”  (macengr – normative vs. positive). So just because women were subject to men at the time, doesn’t mean they were supposed to be that way.  Renick feels that “Aquinas should have known better.”  Still, this is a common mistake and it is very difficult to know the difference.  Thus we must be very careful in thinking about it.

One can, Renick writes, use the natural law approach “to overcome the shackles of tradition…Aquinas’s theories can be the source of liberating justice.  They allow one to say, ‘Sure, things have always been done this way, but nature (and God) demand that we do otherwise.'” And often Aquinas did use natural law to prove this and make “great strides in human justice.”  But the danger is this: “Rather than catching a glimpse of the ways of God and nature, we may be holding a mirror up to ourselves.  We may be confusing what is natural for what is familiar and comfortable” – and the latter may be unjust.

That’s enough for today.  See you next time!

FreeCodeCamp and Learning Node: My First Async I/O

Last time we looked at a synchronous program in Node that read a file, split it into lines, and then counted the number of lines using the new line character as a guide.  Today, we’re going to do the same thing, using an asynchronous function, which is a key strength of Node.  If you don’t know what any of this means, well, first, why haven’t you tried this in the Nodeschool tutorial?  Go do that first, I’ll wait.

Next, read on!

Here are the directions and hints.  Once again, remember that the link for the documentation is https://nodejs.org/dist/latest-v6.x/docs/api/:

MY FIRST ASYNC I/O! (Exercise 4 of 13)

  Write a program that uses a single asynchronous filesystem operation to read a file and print the number of newlines it contains to the console (stdout), similar to running cat file | wc -l.

  The full path to the file to read will be provided as the first command-line argument.

 ─────────────────────────────────────────────────────────────────────────────

 # HINTS

  The solution to this problem is almost the same as the previous problem except you must now do it the Node.js way: asynchronous.

  Instead of fs.readFileSync() you will want to use fs.readFile() and instead of using the return value of this method you need to collect the value from a callback function that you pass in as the second argument. To learn more about callbacks, check out:

  [ https://github.com/maxogden/art-of-node#callbacks]

(https://github.com/maxogden/art-of-node#callbacks ).

  Remember that idiomatic Node.js callbacks normally have the signature:

     function callback (err, data) { /* … */ }

  so you can check if an error occurred by checking whether the first argument is truthy. If there is no error, you should have your Buffer object as the second argument. As with readFileSync(), you can supply ‘utf8’ as the second argument and put the callback as the third argument and you will get a String instead of a Buffer.

  Documentation on the fs module can be found by pointing your browser here:

  file:///home/ubuntu/.nvm/versions/node/v4.4.3/lib/node_modules/learnyounode/node_apidoc/fs.html

Now, it says that we are going to do the same thing as last time, only using an asynchronous method rather than a synchronous one.  That means we can use parts of the previous program we wrote.  The first line and the second line, where we call the file system method and assign the file path to a variable, will be the same.

var fs = require(‘fs’);

var filename = process.argv[2];

Line 3 is going to be wildly different, though.  We are using a different method, an asynchronous one, namely fs.readFile().  For an explanation of how the whole asynchronous thing works, the link they gave in the hints (see above) isn’t bad.  Anyway, the readFile() function takes several arguments.  First is the name and path of the file you want to read.  We saved that in ‘filename’.  Second is ‘utf8’, which means you’ll get the info back as text, similar to how we did in the previous program.  Third is where it gets a little weird.  We call an anonymous function – we’ve done this sort of thing before, in the Front End Development exercises, so it shouldn’t be too unfamiliar.  That function is called a ‘callback’ function (see the link they gave for more), and it takes two arguments.  The first is err, so if something goes wrong it will return an error.  The second is called data here, but you could call it contents or something else if you wanted to.  This will be the actual contents of your file (as opposed to the file name and path we stored in ‘filename’).  So, here’s what we have now:

var fs = require(‘fs’);
var filename = process.argv[2];
var bufFile = fs.readFile(filename, ‘utf8’, function callback(err, data) {

});

Now, two questions:

What do we put into that function?

What about the rest of the program from the previous exercise?

Glad you asked!  First, in the function, we want to convert the file to a string, then split it using the ‘\n’ as the separator.  We did this before, so that answers the second question.

I left out the final line, because I wanted to talk briefly about it, and that’s the line where we print the number of new lines to the console.  That HAS to go inside the function.  Why?  Because if you put it at the end, the console.log() will execute while the file is still being read and split.  You’ll get back undefined.  See, this is the whole thing about how asynchronous ops work.  The program can do other stuff while it’s waiting for time sucking operations to complete, and if you put console.log() outside the function, it will be all, “Hey, I can do this while I’m waiting”.  So, inside the function goes console.log(), and we end up with:

var fs = require(‘fs’);
var filename = process.argv[2];
var bufFile = fs.readFile(filename, ‘utf8’, function callback(err, data) {
var strFile = bufFile.toString();
var cnt = strFile.split(‘\n’);
console.log(cnt.length – 1);

});

And there you have it!  Our first Asynchronous I/O program!

MilSats: Afghan Nat’l Army Technicals

A Technical is, per Wikipedia, ” light improvised fighting vehicles, typically a civilian or military non-combat vehicle, modified to provide an offensive capability similar to a military gun truck. It is usually an open-backed civilian pickup truck or four-wheel drive vehicle mounting a machine gun, light anti-aircraft gun, anti-tank weapon, or other support weapon.”

3234544916_7a3a599182_o

DELARAM, Afghanistan–Afghan National Army soldiers conduct a patrol in western Afghanistan. (ANA photo by Sergeant Fathe Noori)

FreeCodeCamp and Learning Node: My First I/O

The first real challenge for the Node tutorial is learning I/O from files.  This one was a little more difficult than Baby Steps.  My solution is probably a little clumsy, but I think it’s easy to follow.  Let’s dive in!

So, here’s the learnyounode instructions for My first I/O.

 ## MY FIRST I/O! (Exercise 3 of 13)

  Write a program that uses a single synchronous filesystem operation to read a file and print the number of newlines (\n) it contains to the console (stdout), similar to running cat file | wc -l.

  The full path to the file to read will be provided as the first command-line argument (i.e., process.argv[2]). You do not need to make your own test file.

 ─────────────────────────────────────────────────────────────────────────────

 ## HINTS

  To perform a filesystem operation you are going to need the fs module from the Node core library. To load this kind of module, or any other “global” module, use the following incantation:

  var fs = require(‘fs’)

  Now you have the full fs module available in a variable named fs.

  All synchronous (or blocking) filesystem methods in the fs module end with ‘Sync’. To read a file, you’ll need to use fs.readFileSync(‘/path/to/file’). This method will return a Buffer object containing the complete contents of the file.

  Documentation on the fs module can be found by pointing your browser here:

  file:///home/ubuntu/.nvm/versions/node/v4.4.3/lib/node_modules/learnyounode/node_apidoc/fs.html

  Buffer objects are Node’s way of efficiently representing arbitrary arrays of data, whether it be ascii, binary or some other format. Buffer objects can be converted to strings by simply calling the toString() method on them. e.g. var str = buf.toString().

  Documentation on Buffers can be found by pointing your browser here:

  file:///home/ubuntu/.nvm/versions/node/v4.4.3/lib/node_modules/learnyounode/node_apidoc/buffer.html

  If you’re looking for an easy way to count the number of newlines in a string, recall that a JavaScript String can be .split() into an array of substrings and that ‘\n’ can be used as a delimiter. Note that the test file does not have a newline character (‘\n’) at the end of the last line, so using this method you’ll end up with an array that has one more element than the number of newlines.

First of all, those document addresses are useless.  Those addresses are great if you are on the Node server, but in learnyounode, you’ll get nothing.  You can actually go here to look at the cocumentation, and just search for the term you want:

https://nodejs.org/dist/latest-v6.x/docs/api/

 

For this exercise, in the column on the left, it’s File Server (FS) and Buffer that you want.

Now, if it’s not obvious, Node runs on a server.  That’s why all this stuff looks so arcane compared to HTML, CSS, and yes, writing JavaScript in the browser environment.  Node runs off a command line, too, which adds to the alien feel for Front End Developers.  I have experience with Java and this is still taking some getting used to because I did all my Java development in IDEs.  Let’s work this through.

So, the first hint they give, loading fs, does not take place on the command line – it goes in the file you are writing.  Create a new file (I covered this in the last Node Learning Node post).  Name it whatever you want – I called mine program2.js, because I didn’t want to overwrite program.js, which had my answer to the ‘Baby Steps’ tutorial.

Just copy and paste var fs = require(‘fs’), add a semicolon (hey, we’re writing JavaScript, remember?) and that will be the first line of your program.

 

That was the easy part.

 

Okay, learnyounode is GIVING us the file we need to examine – we don’t need to create one.  They are supplying it to us as a command line argument – remember from the last tutorial that the command line arguments object (process.argv) has ‘node’ as the first element, the file path as the second element, and then third (process.argv[2])and up we have whatever information we need.  So, the file information – the location of it, or path – will be process.argv[2].  Let’s assign that to a variable, and our program now looks like:

var fs = require(‘fs’);

var filename = process.argv[2];

Save early, save often.  You remember that from any word processing classes you took, right?

Next, we’ll start using the other commands given in the hints.  First is fs.readFileSync(‘/path/to/file’).  We saved the path to the file in the variable filename.  The command will return the contents of the file as a Buffer object, so we’re going to save that in another new variable we’ll call bufFile (Buffer File -I’m so original).  Here’s what our file looks like now:

var fs = require(‘fs’);
var filename = process.argv[2];

var bufFile = fs.readFileSync(filename);

We need to convert that Buffer object to a string so we can perform string operations on it.  We’ll do that with toString() and assign it to – you guessed it – yet another new variable, which we’ll call strFile, for String File:

var strFile = bufFile.toString();

Believe it or not, we’re almost there.  Using the split() method (I covered it in this post here) with ‘\n’ – for new line – as the separator, we’ll get an array back that will have each line in the file as a separate element.  We’ll save that in one last variable, called cnt (for count):

var cnt = strFile.split(‘\n’);

Now, as noted in the hints, the last line won’t have a new line at the end of it, and we subtract that line from the total since it doesn’t have one.  We can print it to the console now, and that finishes our program, which now looks like this:

var fs = require(‘fs’);

var filename = process.argv[2];

var bufFile = fs.readFileSync(filename);

var strFile = bufFile.toString();

var cnt = strFile.split(‘\n’);

console.log(cnt.length – 1);

If you’ll remember, I called this one program2.js, so I run it as:

learnyounode verify program2.js

And it comes back as passed!

And there you go.  Let me know if there any questions in the comments!