Count line of code for a JavaScript projectIdeas on shortening this if-elsif chain with embedded if-elsifPerl parsing codeCounting words from standard input in SwiftParsing users from a list of commands for email notificationsMatching whitespace and non-whitespace characters with RegExRegular Expression to Remove CommentsMatching Fasta file header and section of sequence, printing each header only onceTrimming unicode whitespace, control characters, and line breaks with regexAverage spam confidence
Tips for attracting more math majors in a liberal arts college mathematics department
Multiple devices with one IPv6 to the Internet?
Term for anticipating counterarguments and rebutting them
why we need self-synchronization?
Does 'a window' close the possibility to be one and only one window in the room?
Proof that if covariance is zero then there is no linear relationship
What's the most profitable use for an elemental transmuter?
Noise reduction using multiple recordings of the same signal
What happens to a Bladesinger reincarnated as a Human?
Is it bizarre that a professor asks every student for a 3 inch by 5 inch photograph?
Is the ''yoi'' meaning ''ready'' when doing karate the same as the ''yoi'' which means nice/good?
How wavy is an array?
Antonym for “boilerplate” or “cookie-cutter”
How can an immortal member of the nobility be prevented from taking the throne?
How do I figure out how many hydrogens my compound actually has using a mass and NMR spectrum?
Command which removes data left side of ";" (semicolon) on each row
How much caffeine would there be if I reuse tea leaves in a second brewing?
Coworkers accusing me of "cheating" for working more efficiently
Why does Bane's stock exchange robbery actually work to bankrupt Bruce Wayne?
How could a sequence of random dates be generated, given year interval?
A partially ugly group with a casual secret
How TikZ uses $ for calculations of relative coordinates?
In Cura, can I make my top and bottom layer be all perimiters?
Novel in which space traders train a spearman army for a decaying medieval empire
Count line of code for a JavaScript project
Ideas on shortening this if-elsif chain with embedded if-elsifPerl parsing codeCounting words from standard input in SwiftParsing users from a list of commands for email notificationsMatching whitespace and non-whitespace characters with RegExRegular Expression to Remove CommentsMatching Fasta file header and section of sequence, printing each header only onceTrimming unicode whitespace, control characters, and line breaks with regexAverage spam confidence
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty
margin-bottom:0;
$begingroup$
Here is my bash script that I just wrote to count line of code for JavaScript project.
It will list number of:
- Comment lines
- Blank lines
- All lines
Here is my script:
#!/bin/bash
fileExt="*.js"
allFiles=$(find ./ -name "$fileExt")
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)
allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)
echo -e "nTotal comments line is: $commentLines.n
Total blank lines is: $blankLines.n
nTotal all lines is: $allLines."
Let me explain it a little bit:
First, we need to list all files that end with ".js" within the project:
allFiles=$(find ./ -name "$fileExt")
Second, we count all comment lines:
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
There are 2 types of comment lines in JavaScript:
Line start with only space and
//
or only//
Example:
//this is a comment line
// this is a comment line
// this also is a comment lineAll above are comment lines, and we got 3 lines total here. But the following is not comment lines:
function foo(params 1) // return void
The line contains
// return void
is not considered as a comment, so we do not need to count it.And for the kind of comment line. I using the regex with
perl
to print all comment lines that match with regex:/(^s+//s*w+)/sg
Multi-line comment (JSDOC):
Example:
/**
* return something
* @param object obj
* return void
*/So we need to count all number of lines that start from the line with
/**
and end with*/
, we have 5 lines here.I use this regex to match:
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles
So the total number of comment lines is the sum of two types comment lines above.
Third
We need to count blank lines.
I use the following command to match:
grep '^[[:space:]]*//' -r --include $fileExt | wc -l
Finally
We need to count all lines:
echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2
I wonder if my solution is good enough or not.
regex bash shell perl sh
$endgroup$
add a comment
|
$begingroup$
Here is my bash script that I just wrote to count line of code for JavaScript project.
It will list number of:
- Comment lines
- Blank lines
- All lines
Here is my script:
#!/bin/bash
fileExt="*.js"
allFiles=$(find ./ -name "$fileExt")
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)
allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)
echo -e "nTotal comments line is: $commentLines.n
Total blank lines is: $blankLines.n
nTotal all lines is: $allLines."
Let me explain it a little bit:
First, we need to list all files that end with ".js" within the project:
allFiles=$(find ./ -name "$fileExt")
Second, we count all comment lines:
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
There are 2 types of comment lines in JavaScript:
Line start with only space and
//
or only//
Example:
//this is a comment line
// this is a comment line
// this also is a comment lineAll above are comment lines, and we got 3 lines total here. But the following is not comment lines:
function foo(params 1) // return void
The line contains
// return void
is not considered as a comment, so we do not need to count it.And for the kind of comment line. I using the regex with
perl
to print all comment lines that match with regex:/(^s+//s*w+)/sg
Multi-line comment (JSDOC):
Example:
/**
* return something
* @param object obj
* return void
*/So we need to count all number of lines that start from the line with
/**
and end with*/
, we have 5 lines here.I use this regex to match:
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles
So the total number of comment lines is the sum of two types comment lines above.
Third
We need to count blank lines.
I use the following command to match:
grep '^[[:space:]]*//' -r --include $fileExt | wc -l
Finally
We need to count all lines:
echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2
I wonder if my solution is good enough or not.
regex bash shell perl sh
$endgroup$
add a comment
|
$begingroup$
Here is my bash script that I just wrote to count line of code for JavaScript project.
It will list number of:
- Comment lines
- Blank lines
- All lines
Here is my script:
#!/bin/bash
fileExt="*.js"
allFiles=$(find ./ -name "$fileExt")
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)
allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)
echo -e "nTotal comments line is: $commentLines.n
Total blank lines is: $blankLines.n
nTotal all lines is: $allLines."
Let me explain it a little bit:
First, we need to list all files that end with ".js" within the project:
allFiles=$(find ./ -name "$fileExt")
Second, we count all comment lines:
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
There are 2 types of comment lines in JavaScript:
Line start with only space and
//
or only//
Example:
//this is a comment line
// this is a comment line
// this also is a comment lineAll above are comment lines, and we got 3 lines total here. But the following is not comment lines:
function foo(params 1) // return void
The line contains
// return void
is not considered as a comment, so we do not need to count it.And for the kind of comment line. I using the regex with
perl
to print all comment lines that match with regex:/(^s+//s*w+)/sg
Multi-line comment (JSDOC):
Example:
/**
* return something
* @param object obj
* return void
*/So we need to count all number of lines that start from the line with
/**
and end with*/
, we have 5 lines here.I use this regex to match:
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles
So the total number of comment lines is the sum of two types comment lines above.
Third
We need to count blank lines.
I use the following command to match:
grep '^[[:space:]]*//' -r --include $fileExt | wc -l
Finally
We need to count all lines:
echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2
I wonder if my solution is good enough or not.
regex bash shell perl sh
$endgroup$
Here is my bash script that I just wrote to count line of code for JavaScript project.
It will list number of:
- Comment lines
- Blank lines
- All lines
Here is my script:
#!/bin/bash
fileExt="*.js"
allFiles=$(find ./ -name "$fileExt")
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
blankLines=$(grep '^[[:space:]]*//' -r --include $fileExt | wc -l)
allLines=$(echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2)
echo -e "nTotal comments line is: $commentLines.n
Total blank lines is: $blankLines.n
nTotal all lines is: $allLines."
Let me explain it a little bit:
First, we need to list all files that end with ".js" within the project:
allFiles=$(find ./ -name "$fileExt")
Second, we count all comment lines:
commentLines=$((perl -ne 'print "$1n" while /(^s+//s*w+)/sg' $allFiles;
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles) | wc -l)
There are 2 types of comment lines in JavaScript:
Line start with only space and
//
or only//
Example:
//this is a comment line
// this is a comment line
// this also is a comment lineAll above are comment lines, and we got 3 lines total here. But the following is not comment lines:
function foo(params 1) // return void
The line contains
// return void
is not considered as a comment, so we do not need to count it.And for the kind of comment line. I using the regex with
perl
to print all comment lines that match with regex:/(^s+//s*w+)/sg
Multi-line comment (JSDOC):
Example:
/**
* return something
* @param object obj
* return void
*/So we need to count all number of lines that start from the line with
/**
and end with*/
, we have 5 lines here.I use this regex to match:
perl -0777 -ne 'print "$1n" while /(**.*?*/)/sg' $allFiles
So the total number of comment lines is the sum of two types comment lines above.
Third
We need to count blank lines.
I use the following command to match:
grep '^[[:space:]]*//' -r --include $fileExt | wc -l
Finally
We need to count all lines:
echo $allFiles | xargs wc -l | tail -n 1 | cut -d " " -f 2
I wonder if my solution is good enough or not.
regex bash shell perl sh
regex bash shell perl sh
edited Jun 2 at 2:20
Jamal♦
32.1k12 gold badges123 silver badges231 bronze badges
32.1k12 gold badges123 silver badges231 bronze badges
asked May 31 at 4:11
chau giangchau giang
1015 bronze badges
1015 bronze badges
add a comment
|
add a comment
|
2 Answers
2
active
oldest
votes
$begingroup$
fileExt="*.js"
allFiles=$(find ./ -name $fileExt)
This is a bug. The wildcard in $fileExt
will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:
$ touch a.js b.js
$ fileExt="*.js"
$ find ./ -name $fileExt
find: paths must precede expression: `b.js'
find: possible unquoted pattern after predicate `-name'?
You need to quote the variable. Better yet, use the globstar
option to populate an array and eliminate find
altogether:
fileExt="js"
shopt -s globstar
declare -a allFiles=( **/*.$fileExt )
grep … "$allFiles[@]" # to use the array
This regex does not match blank lines:
grep '^[[:space:]]*//'
Just /*
is enough to start a multi-line comment in JavaScript (not /**
).
The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:
#!/bin/bash
shopt -s globstar
exec perl -nle '
BEGIN
@ARGV=grep -f, @ARGV or die "no matching filesn";
$comment = $blank = 0;
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END print "$comment comment lines; $blank blank lines; $. total lines"
' **/*.js
At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:
#!/usr/bin/perl -wnl
BEGIN
use strict;
use File::Find;
my $ext="js";
my @dirs=( @ARGV ? @ARGV : '.' );
@ARGV=();
find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
our ($comment, $blank) = (0, 0);
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END
print "$comment comment lines; $blank blank lines; $. total lines";
$endgroup$
1
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
2
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
add a comment
|
$begingroup$
General
Run shellcheck
on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e
(prefer printf
instead) and a dodgy use of $((
where $( (
would be safer.
I recommend setting -u
and -e
shell options to help you catch more errors.
Flexibility
Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:
dirs=("$@:-.")
Finding files
allFiles
will include directories and other non-regular files, if they happen to end in .js
. We need to add a file type predicate:
allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)
Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find ./ -name "$fileExt" -type f -print0)
It may almost be simpler to set globstar
shell option and then remove non-regular files from the glob result.
Counting comment lines
I didn't follow your Perl code, but I have an alternative approach using sed
:
- convert all lines from initial
/**
to final*/
to begin with//
instead, - then keep only the lines beginning with optional whitespace then
//
:
sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
(Actually, that's a lot less pretty than I'd hoped!)
Blank lines
Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$'
instead, to match lines that contain only (optional) whitespace.
All lines
Again, over-complicated: just cat
the files together and then use wc -l
.
Printing
I find it easier to visualise output formatting if we simply use a here-document:
cat <<EOF
Total comments lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
exit
Modified code
#!/bin/bash
set -eu
fileExt='*.js'
dirs=("$@:-/usr/lib/nodejs/lodash")
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)
commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
"$allFiles[@]" | wc -l)
blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
allLines=$(cat "$allFiles[@]" | wc -l)
cat <<EOF
Total comment lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).
Single-pass version using awk
A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk
program. Note that with no arrays, we can make this a POSIX shell program:
#!/bin/sh
set -eu
fileExt='*.js'
find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;
++all
if ($0 ~ "/\*") incomment = 1
if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")
END print "Total comment lines is:", comment
print "Total blank lines is:", blank
print "Total all lines is:", all '
$endgroup$
add a comment
|
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/4.0/"u003ecc by-sa 4.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f221378%2fcount-line-of-code-for-a-javascript-project%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
$begingroup$
fileExt="*.js"
allFiles=$(find ./ -name $fileExt)
This is a bug. The wildcard in $fileExt
will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:
$ touch a.js b.js
$ fileExt="*.js"
$ find ./ -name $fileExt
find: paths must precede expression: `b.js'
find: possible unquoted pattern after predicate `-name'?
You need to quote the variable. Better yet, use the globstar
option to populate an array and eliminate find
altogether:
fileExt="js"
shopt -s globstar
declare -a allFiles=( **/*.$fileExt )
grep … "$allFiles[@]" # to use the array
This regex does not match blank lines:
grep '^[[:space:]]*//'
Just /*
is enough to start a multi-line comment in JavaScript (not /**
).
The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:
#!/bin/bash
shopt -s globstar
exec perl -nle '
BEGIN
@ARGV=grep -f, @ARGV or die "no matching filesn";
$comment = $blank = 0;
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END print "$comment comment lines; $blank blank lines; $. total lines"
' **/*.js
At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:
#!/usr/bin/perl -wnl
BEGIN
use strict;
use File::Find;
my $ext="js";
my @dirs=( @ARGV ? @ARGV : '.' );
@ARGV=();
find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
our ($comment, $blank) = (0, 0);
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END
print "$comment comment lines; $blank blank lines; $. total lines";
$endgroup$
1
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
2
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
add a comment
|
$begingroup$
fileExt="*.js"
allFiles=$(find ./ -name $fileExt)
This is a bug. The wildcard in $fileExt
will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:
$ touch a.js b.js
$ fileExt="*.js"
$ find ./ -name $fileExt
find: paths must precede expression: `b.js'
find: possible unquoted pattern after predicate `-name'?
You need to quote the variable. Better yet, use the globstar
option to populate an array and eliminate find
altogether:
fileExt="js"
shopt -s globstar
declare -a allFiles=( **/*.$fileExt )
grep … "$allFiles[@]" # to use the array
This regex does not match blank lines:
grep '^[[:space:]]*//'
Just /*
is enough to start a multi-line comment in JavaScript (not /**
).
The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:
#!/bin/bash
shopt -s globstar
exec perl -nle '
BEGIN
@ARGV=grep -f, @ARGV or die "no matching filesn";
$comment = $blank = 0;
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END print "$comment comment lines; $blank blank lines; $. total lines"
' **/*.js
At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:
#!/usr/bin/perl -wnl
BEGIN
use strict;
use File::Find;
my $ext="js";
my @dirs=( @ARGV ? @ARGV : '.' );
@ARGV=();
find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
our ($comment, $blank) = (0, 0);
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END
print "$comment comment lines; $blank blank lines; $. total lines";
$endgroup$
1
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
2
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
add a comment
|
$begingroup$
fileExt="*.js"
allFiles=$(find ./ -name $fileExt)
This is a bug. The wildcard in $fileExt
will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:
$ touch a.js b.js
$ fileExt="*.js"
$ find ./ -name $fileExt
find: paths must precede expression: `b.js'
find: possible unquoted pattern after predicate `-name'?
You need to quote the variable. Better yet, use the globstar
option to populate an array and eliminate find
altogether:
fileExt="js"
shopt -s globstar
declare -a allFiles=( **/*.$fileExt )
grep … "$allFiles[@]" # to use the array
This regex does not match blank lines:
grep '^[[:space:]]*//'
Just /*
is enough to start a multi-line comment in JavaScript (not /**
).
The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:
#!/bin/bash
shopt -s globstar
exec perl -nle '
BEGIN
@ARGV=grep -f, @ARGV or die "no matching filesn";
$comment = $blank = 0;
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END print "$comment comment lines; $blank blank lines; $. total lines"
' **/*.js
At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:
#!/usr/bin/perl -wnl
BEGIN
use strict;
use File::Find;
my $ext="js";
my @dirs=( @ARGV ? @ARGV : '.' );
@ARGV=();
find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
our ($comment, $blank) = (0, 0);
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END
print "$comment comment lines; $blank blank lines; $. total lines";
$endgroup$
fileExt="*.js"
allFiles=$(find ./ -name $fileExt)
This is a bug. The wildcard in $fileExt
will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it:
$ touch a.js b.js
$ fileExt="*.js"
$ find ./ -name $fileExt
find: paths must precede expression: `b.js'
find: possible unquoted pattern after predicate `-name'?
You need to quote the variable. Better yet, use the globstar
option to populate an array and eliminate find
altogether:
fileExt="js"
shopt -s globstar
declare -a allFiles=( **/*.$fileExt )
grep … "$allFiles[@]" # to use the array
This regex does not match blank lines:
grep '^[[:space:]]*//'
Just /*
is enough to start a multi-line comment in JavaScript (not /**
).
The script reads every file four times. That is slow. Since you're using Perl already, just let it count everything. Then you don't need to capture the file names at all, since they are used only once:
#!/bin/bash
shopt -s globstar
exec perl -nle '
BEGIN
@ARGV=grep -f, @ARGV or die "no matching filesn";
$comment = $blank = 0;
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END print "$comment comment lines; $blank blank lines; $. total lines"
' **/*.js
At this point we're barely using bash anymore, and the globbing can be moved inside the Perl script, using the File::Find module:
#!/usr/bin/perl -wnl
BEGIN
use strict;
use File::Find;
my $ext="js";
my @dirs=( @ARGV ? @ARGV : '.' );
@ARGV=();
find(sub -f and /.$ext$/o and push @ARGV, $File::Find::name , @dirs );
our ($comment, $blank) = (0, 0);
if ( m ^s*/* x .. m */ x or m ^s*// x ) $comment++
elsif ( m ^s*$ x ) $blank++
END
print "$comment comment lines; $blank blank lines; $. total lines";
edited May 31 at 18:56
Timo
4021 gold badge4 silver badges8 bronze badges
4021 gold badge4 silver badges8 bronze badges
answered May 31 at 5:52
Oh My GoodnessOh My Goodness
3,6801 gold badge4 silver badges22 bronze badges
3,6801 gold badge4 silver badges22 bronze badges
1
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
2
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
add a comment
|
1
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
2
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
1
1
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
Thank you a lot, this is a lot of stuffs that I did not know before, maybe this is the best answer at the moment
$endgroup$
– chau giang
May 31 at 7:58
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
$begingroup$
I understand this: grep '^[[:space:]]*//', this is my mistake!
$endgroup$
– chau giang
May 31 at 7:59
2
2
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
Pure Perl is a good approach; it does require Perl's File::Find module to do the recursion, and the clumsiness of that module is a peeve of mine. But sure, why not? Edited.
$endgroup$
– Oh My Goodness
May 31 at 14:07
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
$begingroup$
The wildcard in $fileExt will be expanded by the shell, and cause a syntax error when the current directory has more than one matching file in it => you were right. I wasn't even aware that because of using zsh and I got no problem at all. I think next time better I will use pure bash. In zsh, I even can use some command like: wc -l */.js Thank you once again!
$endgroup$
– chau giang
Jun 3 at 4:36
add a comment
|
$begingroup$
General
Run shellcheck
on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e
(prefer printf
instead) and a dodgy use of $((
where $( (
would be safer.
I recommend setting -u
and -e
shell options to help you catch more errors.
Flexibility
Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:
dirs=("$@:-.")
Finding files
allFiles
will include directories and other non-regular files, if they happen to end in .js
. We need to add a file type predicate:
allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)
Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find ./ -name "$fileExt" -type f -print0)
It may almost be simpler to set globstar
shell option and then remove non-regular files from the glob result.
Counting comment lines
I didn't follow your Perl code, but I have an alternative approach using sed
:
- convert all lines from initial
/**
to final*/
to begin with//
instead, - then keep only the lines beginning with optional whitespace then
//
:
sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
(Actually, that's a lot less pretty than I'd hoped!)
Blank lines
Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$'
instead, to match lines that contain only (optional) whitespace.
All lines
Again, over-complicated: just cat
the files together and then use wc -l
.
Printing
I find it easier to visualise output formatting if we simply use a here-document:
cat <<EOF
Total comments lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
exit
Modified code
#!/bin/bash
set -eu
fileExt='*.js'
dirs=("$@:-/usr/lib/nodejs/lodash")
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)
commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
"$allFiles[@]" | wc -l)
blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
allLines=$(cat "$allFiles[@]" | wc -l)
cat <<EOF
Total comment lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).
Single-pass version using awk
A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk
program. Note that with no arrays, we can make this a POSIX shell program:
#!/bin/sh
set -eu
fileExt='*.js'
find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;
++all
if ($0 ~ "/\*") incomment = 1
if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")
END print "Total comment lines is:", comment
print "Total blank lines is:", blank
print "Total all lines is:", all '
$endgroup$
add a comment
|
$begingroup$
General
Run shellcheck
on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e
(prefer printf
instead) and a dodgy use of $((
where $( (
would be safer.
I recommend setting -u
and -e
shell options to help you catch more errors.
Flexibility
Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:
dirs=("$@:-.")
Finding files
allFiles
will include directories and other non-regular files, if they happen to end in .js
. We need to add a file type predicate:
allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)
Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find ./ -name "$fileExt" -type f -print0)
It may almost be simpler to set globstar
shell option and then remove non-regular files from the glob result.
Counting comment lines
I didn't follow your Perl code, but I have an alternative approach using sed
:
- convert all lines from initial
/**
to final*/
to begin with//
instead, - then keep only the lines beginning with optional whitespace then
//
:
sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
(Actually, that's a lot less pretty than I'd hoped!)
Blank lines
Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$'
instead, to match lines that contain only (optional) whitespace.
All lines
Again, over-complicated: just cat
the files together and then use wc -l
.
Printing
I find it easier to visualise output formatting if we simply use a here-document:
cat <<EOF
Total comments lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
exit
Modified code
#!/bin/bash
set -eu
fileExt='*.js'
dirs=("$@:-/usr/lib/nodejs/lodash")
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)
commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
"$allFiles[@]" | wc -l)
blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
allLines=$(cat "$allFiles[@]" | wc -l)
cat <<EOF
Total comment lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).
Single-pass version using awk
A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk
program. Note that with no arrays, we can make this a POSIX shell program:
#!/bin/sh
set -eu
fileExt='*.js'
find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;
++all
if ($0 ~ "/\*") incomment = 1
if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")
END print "Total comment lines is:", comment
print "Total blank lines is:", blank
print "Total all lines is:", all '
$endgroup$
add a comment
|
$begingroup$
General
Run shellcheck
on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e
(prefer printf
instead) and a dodgy use of $((
where $( (
would be safer.
I recommend setting -u
and -e
shell options to help you catch more errors.
Flexibility
Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:
dirs=("$@:-.")
Finding files
allFiles
will include directories and other non-regular files, if they happen to end in .js
. We need to add a file type predicate:
allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)
Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find ./ -name "$fileExt" -type f -print0)
It may almost be simpler to set globstar
shell option and then remove non-regular files from the glob result.
Counting comment lines
I didn't follow your Perl code, but I have an alternative approach using sed
:
- convert all lines from initial
/**
to final*/
to begin with//
instead, - then keep only the lines beginning with optional whitespace then
//
:
sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
(Actually, that's a lot less pretty than I'd hoped!)
Blank lines
Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$'
instead, to match lines that contain only (optional) whitespace.
All lines
Again, over-complicated: just cat
the files together and then use wc -l
.
Printing
I find it easier to visualise output formatting if we simply use a here-document:
cat <<EOF
Total comments lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
exit
Modified code
#!/bin/bash
set -eu
fileExt='*.js'
dirs=("$@:-/usr/lib/nodejs/lodash")
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)
commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
"$allFiles[@]" | wc -l)
blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
allLines=$(cat "$allFiles[@]" | wc -l)
cat <<EOF
Total comment lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).
Single-pass version using awk
A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk
program. Note that with no arrays, we can make this a POSIX shell program:
#!/bin/sh
set -eu
fileExt='*.js'
find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;
++all
if ($0 ~ "/\*") incomment = 1
if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")
END print "Total comment lines is:", comment
print "Total blank lines is:", blank
print "Total all lines is:", all '
$endgroup$
General
Run shellcheck
on this script - almost all variable expansions are unquoted, but need to be quoted. That will also highlight the non-portable echo -e
(prefer printf
instead) and a dodgy use of $((
where $( (
would be safer.
I recommend setting -u
and -e
shell options to help you catch more errors.
Flexibility
Instead of requiring users to change to the top directory of the project, we could allow them to specify one or more directories as command-line arguments, and use current directory as a fallback if no arguments are provided:
dirs=("$@:-.")
Finding files
allFiles
will include directories and other non-regular files, if they happen to end in .js
. We need to add a file type predicate:
allFiles=$(find "$dirs[@]" -name "$fileExt" -type f)
Since we're using Bash, it makes sense to take advantage of array variables - though we'll still have problems for filenames containing whitespace. To fix that, we need to read answers to How can I store the “find” command results as an array in Bash?:
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find ./ -name "$fileExt" -type f -print0)
It may almost be simpler to set globstar
shell option and then remove non-regular files from the glob result.
Counting comment lines
I didn't follow your Perl code, but I have an alternative approach using sed
:
- convert all lines from initial
/**
to final*/
to begin with//
instead, - then keep only the lines beginning with optional whitespace then
//
:
sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
(Actually, that's a lot less pretty than I'd hoped!)
Blank lines
Here, we've used the regular expression that matches comment lines. We want '^[[:blank:]]*$'
instead, to match lines that contain only (optional) whitespace.
All lines
Again, over-complicated: just cat
the files together and then use wc -l
.
Printing
I find it easier to visualise output formatting if we simply use a here-document:
cat <<EOF
Total comments lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
exit
Modified code
#!/bin/bash
set -eu
fileExt='*.js'
dirs=("$@:-/usr/lib/nodejs/lodash")
allFiles=()
while IFS= read -r -d ''; do
allFiles+=("$REPLY")
done < <(find "$dirs[@]" -name "$fileExt" -type f -print0)
commentLines=$(sed -e '!^[[:blank:]]*/**!,!*/!s/.*/\\/'
-e '|^[[:blank:]]*//|!d'
"$allFiles[@]" | wc -l)
blankLines=$(cat "$allFiles[@]" | grep -c '^[[:blank:]]*$')
allLines=$(cat "$allFiles[@]" | wc -l)
cat <<EOF
Total comment lines is: $commentLines.
Total blank lines is: $blankLines.
Total all lines is: $allLines.
EOF
Although this makes three passes over the input files, that might be an acceptable trade-off against the complexity of a single-pass approach here (and is already the approach taken in the original code).
Single-pass version using awk
A single-pass version doesn't require us to use an array to store the filenames; we can simply stream the file contents into a suitable counting function. We could implement that counting function in shell, but it's probably easier to write a short awk
program. Note that with no arrays, we can make this a POSIX shell program:
#!/bin/sh
set -eu
fileExt='*.js'
find "$@:-." -name "$fileExt" -type f -print0 | xargs -0 cat |
awk 'BEGIN all = 0; blank = 0; comment = 0; incomment = 0;
++all
if ($0 ~ "/\*") incomment = 1
if (incomment) ++comment; if ($0 ~ "\*/") incomment = 0;
else blank += ($0 ~ "^[[:blank:]]*$"); comment += ($0 ~ "^[[:blank:]]*//")
END print "Total comment lines is:", comment
print "Total blank lines is:", blank
print "Total all lines is:", all '
edited Jun 3 at 10:19
answered May 31 at 13:18
Toby SpeightToby Speight
32.9k7 gold badges46 silver badges142 bronze badges
32.9k7 gold badges46 silver badges142 bronze badges
add a comment
|
add a comment
|
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f221378%2fcount-line-of-code-for-a-javascript-project%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown