© Karl Beecher 2018
Karl BeecherBad Programming Practices 101https://doi.org/10.1007/978-1-4842-3411-2_2

2. Layout and Structure

Karl Beecher1 
(1)
Berlin, Germany
 

Objectives

In this chapter, you’ll learn:
  • How to make your code difficult to read

  • Why unstructured programming helps you write worse code than structured programming does

  • How to make a mess of documentation

Prerequisites

Before reading this chapter, make sure you’re familiar with:
  • Basic Java programming, including the following:
    • Using methods and parameters

    • if statements and basic looping

    • Writing simple comments and JavaDoc

  • Some form of source-code editor

  • The difference between source code and binary code

Introduction

The way you lay out your code has consequences for how understandable it is. This applies both to purely stylistic factors (like where to place things) and to the code’s executable structure (like whether or not you use subroutines). In both cases, we’ll see how to make a mess of it and render the code incomprehensible.

The information offered by the layout and structure can be augmented by code comments. This chapter will also show you how to ensure your comments do more harm than good.

Make Spacing Poor and Inconsistent

Some of the most popular programming languages today are so-called free-form languages .1 That is to say, the layout of the code makes no difference to the computer—things like the spacing between words, the number of empty lines, and the indentation. So long as your program contains no syntax errors, you can write executable code using any physical layout you want.

Of course, your colleagues will not be so accommodating. They’ll expect you to follow certain rules and conventions because code that is laid out badly is harder for them to understand.

Here lies your first opportunity to cause chaos.

On the Level

Let’s start with this example:

public class Main {
    public int number;
    public void assignIfPositive(int a) {
        if (a > 0) {
            System.out.println("a is positive");
            number = a;
        }
    }
}

What does the computer see? It sees that the class Main is declared first, meaning it’s at the top level of the program. It also sees that the method assignIfPositive is declared between Main’s opening and closing braces, which means that the method is nested inside the class. This is all a matter of syntax, which is important to the computer.

This is important to the programmer too, but the code’s author adds additional information that the computer doesn’t care about. The Main class is also considered to be at the top level by the programmer because it’s declared on an unindented line. The assignIfPositive method is indented one level to show it’s nested inside the Main class. The programmer also sees that the statement if (a > 0) is indented further than the declaration of assignIfPositive , which means it is a statement inside the method.

Of course, you don’t have to indent code like this. The computer would just as easily accept the program if it looked like this:

public class Main {
public int number;
public void assignIfPositive(int a) {
if (a > 0) {
System.out.println("a is positive");
number = a;
}
}
}

Worrying about indentation is just creating unnecessary work for yourself. After all, as soon as the code compiles, the work is done, right?

In fact, our first anti-rule helps guide us to this conclusion:2

Something that is not mandatory is never worth doing.

The computer would cheerfully compile this without complaint. So, why should a human complain?

Thumbs Down!

The reason your fellow programmers would complain about badly indented code is one that echoes throughout this book: source code should be treated primarily as a means for communicating with other people.

After all, the computer doesn’t really understand high-level programming languages like Java or C++. It only understands the binary code that your programs get compiled into. High-level languages are just inventions that make it more convenient for humans to write and understand programs.

Indentation makes the structure of programs more comprehensible (Van De Vanter, 2002). It acts as a visual guide for code, enabling the reader to see at a glance the individual pieces of the program and how they’re related.

It also aids in the search for bugs. Look at this slightly adapted version of the previous code:

public class Main {
public int number;
public void assignIfPositive(int a) {
if (a > 0)
System.out.println("a is positive");
number = a;
}
}

See a problem? How about if I indent the code properly?

public class Main {
    public int number;
    public void assignIfPositive(int a) {
        if (a > 0)
            System.out.println("a is positive");
        number = a;
    }
}

Now the problem should be much easier to spot. In the adapted version, the if statement has no braces, which makes it a single-line if statement .3 Therefore, the assignment to number—which should only happen if a is positive—now happens regardless of whether a is positive or not. This is not just a theoretical problem. Misleading indentation correlates with bug-prone software (Miara, 1983) and has also been the root cause of serious problems in real-world software (Wheeler, 2014).

Indentation is used in practically every modern software project on the planet. Your colleagues will expect it. Even most source-code editors add indentation automatically .

Spaced Out

If you want to mess up the spacing of your code, a preferable alternative to indentation might be white space . This refers to the empty space between characters in source code. It can mean the spaces between tokens4 or empty lines between blocks of code.

Like indentation, spacing makes no difference in free-form languages. The issue of white space between tokens comes partly down to legibility. However, the rules around white space tend to be looser. In code like this:

if(meal == "Breakfast" && hour >= 11){
    System.out.println("No breakfast after 11am.");
}

the condition in the if statement is pretty legible because a space exists between each token, making them more distinct.

However, white space allows for quite a bit of variation. You’ll see differing styles between projects and even between individual programmers. For example, one might favor spaces between logical operators but not comparison operators:

if(meal=="Breakfast" && hour>=11)

Meanwhile, another might be very fond of spacing, going so far as to add spaces on the inside of parentheses:

if ( meal == "Breakfast" && hour >= 11 )

In any case, spacing makes the whole thing easier to read.

Yuck! Why make things easy? Try this instead:

if(meal=="Breakfast"&&hour>=11)

That’s better . By removing all white space short of causing a compile error , all the tokens become squashed together, making it harder to read justlikethewordsinthispartofthesentence. (Van De Vanter, 2002). It may only make it slightly harder, but remember: every little bit hinders.

Tabs and Spaces

In your quest to cause chaos in your coding projects, you should bear in mind the idea of variation. It might be surprising to learn that alternating between practices arbitrarily can really mess things up.

A good example is the mixing up of tabs and spaces when adding white space. Indented code can be pushed along a line either by a series of individual spaces or by a tab character. One space pushes the line along by a single character, whereas the width of a tab character can vary depending on the editor someone is using to view the code. For example, one editor might set tab spacing to a value of 4, meaning it will push a line indented by a tab character along four spaces. Another editor might have tab spacing set to 2, so it will display tab-indented code by pushing it along two spaces.

Here comes the fun part: arbitrarily mixing up the use of tabs and spaces. In the following example, I’ve marked where the lines were indented by tabs or by spaces.5

public void guessTheNumber(int guess) {
••••int a = 0;
••••while (a < 10) {
••••••••a = a + 1;
‣   ‣   if (a == guess)
‣   ‣   ‣   System.out.println("You guessed right!");
••••}
}

That’s how it would look in an editor with a tab width of 4 (which makes sense, seeing as the space-indented lines have four leading spaces). Now, see the difference it makes for someone whose editor has a tab width of 2:

public void guessTheNumber(int guess) {
    int a = 0;
    while (a < 10) {
        a = a + 1;
    if (a == guess)
      System.out.println("You guessed right!");
    }
}

The code is now potentially confusing . Your colleague may give the code only a cursory glance and believe that the while loop and the if statement occupy the same level of nesting . Or they may sense a problem, causing them to stop and expend effort trying to understand it (before going on to hunt down the fiend responsible).

Either way, being inconsistent is another nice little method for sprinkling a bit of chaos over your code. Another anti-rule for us note down is as follows:

Be inconsistent!

Thumbs Down!

Professional programmers greatly value consistency. In fact, you’ll see that plenty of coding handbooks and style guides recommend something like “the exact choice of layout rules is less important than applying them consistently .”

A project’s coding standards tend to pick one option from several possibilities and mandate it. For example, Rule 5 in the Java Coding Standards of the European Space Agency says, “Do not use tab characters in implementation files , use plain spaces instead” (ESA, 2004).

Modern editors and IDEs even come with built-in functionality for enforcing spacing and indentation rules. These programs can format your code automatically, structuring the code layout in specific ways. Some code-review tools can even be made to automatically reject submissions that don’t adhere to standards.

Clutter the Code

Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away.

—Antoine de Saint Exupéry (1939)

Programming is hard, even for experienced veterans. It requires the management of great complexity and the ability to hold a lot of constantly changing information in one’s head all at once.

Naturally, this requires a great deal of concentration. Anything that distracts or confuses the programmer threatens to break that concentration, and a programmer who cannot concentrate risks making mistakes. You could distract your colleagues while they’re trying to work by playing loud music or by gently yet persistently prodding the side of their head with a stick. But there’s no need to be so overt. The good news is that you can actually distract them just by writing code!

Programmers like clean, uncluttered code. Cluttered code has a lot of extra crap that doesn’t need to be there, which is very distracting to a programmer who is trying to concentrate.

Unused Stuff

Distract those reading your code by declaring things but then never using them. For example, a reasonable person expects that a declared variable will be used at some point, so seeing unreferenced variables trips them up. Consider this:

public double applySecretFormula(
        int a, int b, int c, int d) {
    return (a^2 / (b + 1)) * c;
}

The function references three variables (a, b, and c), but the list of parameters includes a fourth: d. Now, anyone looking at this code is going to be stopped in their tracks. What’s d doing there? Is it a mistake in the parameter list? Or is the secret formula incomplete? Or did it used to include d in the past but now no longer uses it, meaning someone forgot to remove it from the parameter list? The code doesn’t readily reveal the answer.

Dead Stuff

Another form of clutter is unreachable code , also known as dead code . This is code that is actually impossible to reach under any circumstances. Since it serves no purpose, unreachable code merely wastes space, both in the computer’s memory and the reader’s brain.

It can be recognized quite easily in some forms; for example:

public int applyDiscount(int quantity) {
    if (quantity > 10) {
        return price - 10;
    }
    else {
        return price;
    }
    System.out.println("Discount checked!");
}

In this case , there is no way to reach the println statement, because every possible path through the method ends up at a return statement before the println can be reached. But this would be an easy example to catch. Code-analysis tools could pick it up, and, in the case of Java, the compiler would treat this as a compile-time error .

If you want to introduce unreachable code , you should do so in a much more subtle and harder to detect fashion; for example:

public void doProcessRandomly() {
    double n = Math.random();
    if (n > 10) {
        // All code inside the if-block is dead
    }
}

Can you see the problem here? The compiler certainly can’t. As far as the compiler is concerned, the built-in method Math.random returns a double value. However, what the compiler doesn’t know and cannot work out is that Math.random is written in such a way that it will only ever return a number between 0 and 1. No matter how many times you run the code, n will never exceed 10, thus none of the code inside the if block is reachable because n must exceed 10 before the code in the if block gets executed.

Disabled Stuff

Being told to remove code from a program might make you nervous. You might have grown attached to that bit of code. Or you might fear forgetting all about it after deletion. What if it needs to be put back again in the future?

Can’t you just take it out, but at the same time leave it in?

Sure you can! Just turn the code into comments and hope that your project is not one of those that prohibits this practice.

Thumbs Down!

In all these cases, the advice from your colleagues will usually be the same: if it’s useless, remove it. Any code that contributes nothing to the execution of a program is seen as wasteful clutter or, even worse, a potential bug. Programs with unnecessary code in them correlate with higher rates of defects (Card et al., 1986).

Don’t worry too much about accidentally deleting something that turns out to be useful. You can always rescue it from a previous version stored in your version-control system .

You do use version control, don’t you?

Write Bad Comments

Things like layout, spacing, and clutter contribute to the comprehensibility of your code. They’re also fairly systematic, so much so that automated tools can enforce rules around them.

Comments also affect how well your code can be understood. However, writing them is a much more creative endeavor. Automated tools can’t write them for you or, more important, tell you when they’re done badly.

This makes them potentially dangerous. Write them well, and the reader’s understanding is improved. Write them badly, and the reader will be confused, misled, and greatly annoyed.

I think you know where this is leading.

No Comment!

The least labor-intensive way of writing bad comments is to not write them at all. As the old anti-wisdom says,

If it was hard to write, then it should be hard to read.

If you want to make trouble, writing code without comments should be the first thing to try. When you submit your code, leave out any explanation of how it works. You never know—you might get away with it!

Thumbs Down!

The point of a comment is to clarify the code. But if your code does something very simple and obvious, a comment is probably unnecessary. Leaving out the comments on a piece of code like this will be fine:

public void getWeight() {
    return weight;
}

After all, everyone knows what a getter method is.

However, code like the following is not at all obvious:6

for (i = 0; i < numbers.length; i++) {
    for (int j = 1; j < (numbers.length - i); j++) {
        if (numbers[j - 1] > numbers[j]) {
            Integer temp = numbers[j - 1];
            numbers[j - 1] = numbers[j];
            numbers[j] = temp;
        }
    }
}

In this case, comments would clarify its purpose greatly. If your code looks complicated (and it should be, if you’re following the advice in this book!), you’re unlikely to get away with leaving out the comments.

You can suck a lot of the fat out of the process of writing comments by using tools to help you. For example, comment generators can read the code and set up some skeletal comments for you. Your job is then to fine-tune what the generator produces.7 Another useful tool is a documentation generator. This extracts information from the code—including but not limited to the comments—and uses it to generate documents describing the code, typically in HTML or PDF format.8

Code Parroting

So, your attempt to sneak through some commentless code failed? Never fear. There is still plenty of scope to do it wrong.

The next worst thing to writing no comments is to simply write comments that parrot the code. For example, if your colleagues respond to the preceding example with a comment like “Needs more comments!” then fine—give ’em what they want.

Here are some comments explaining what’s happening inside the if block:

if (numbers[j - 1] > numbers[j]) {
    // numbers[j - 1] is assigned to temp
    Integer temp = numbers[j - 1];
    // numbers[j] is assigned to numbers[j - 1]
    numbers[j - 1] = numbers[j];
    // temp is assigned to numbers[j]
    numbers[j] = temp;
}

Do you see how wonderfully useless the comments are? Notice how they add no semantic information to the code whatsoever? Comments like this reach an admirable level of unhelpfulness.

Thumbs Down!

Good comments clarify the code and explain the meaning behind it. They add information. The comments in the previous example didn’t do that. They simply stated what each step did without giving any context.

Individual steps are typically not what the reader is concerned about (a programmer knows an assignment when they see one). What normally troubles them is knowing what groups of operations are doing and what goal they’re all working together to achieve. Useful comments are ones explaining at this level (Shneidermann, 1979).

A more useful way to comment the previous example might be as follows:

// Compare the values of two consecutive numbers.
// Swap their positions in the numbers array if
// the earlier is greater than the latter.
if (numbers[j - 1] > numbers[j]) {
    Integer temp = numbers[j - 1];
    numbers[j - 1] = numbers[j];
    numbers[j] = temp;
}

So would a summary explanation of the whole routine:

// Sorts the values in the numbers array into
// ascending numerical order using a bubble
// sort algorithm.
for (int i = 0; i < numbers.length - 1; i++) {
    for (int j = 1; j < (numbers.length - i); j++) {
        // etc...

Out of Sync

So, you tried to write commentless code , but they caught you. Then, you tried to be facetious and add useless comments, but even that was rejected. Have they got you pinned down now? Is there no other way to use comments badly?

Actually, there is something else, perhaps the most evil possibility of them all. Think of it this way: a comment is supposed to explain a piece of code, but what if the explanation in the comment doesn’t match the behavior of the code? This inconsistency indicates one of two potential problems: 1) the code is incorrect, or 2) the comment is incorrect (Tan, 2012).

This is a nicely messy situation to introduce; first, because you now have two possible problems to consider (and don’t forget, both could be true!). And second, because it would be easy to sneak the inconsistency into the codebase.

Look at this example:

/**
@param message The message to be displayed. If null,
    an empty message is displayed.
*/
public void displayMessage(String message)
{
    if (null == message) {
        message = ""
    }
    System.out.println(message);
}

Good so far. Now, let’s say the method functionality is changed at a later point, specifically so that a null message parameter will no longer print an empty message. However, the comment is left untouched.

/**
@param message The message to be displayed. If null,
    an empty message is displayed.
*/
public void displayMessage(String message)
{
    if (null == message) {
        return;
    }
    System.out.println(message);
}

Regrettably (for everyone else at least), it’s all too easy to miss that the comment and the code now no longer match. In review, your colleague may well concentrate on what has changed, but overlook what hasn’t changed. The displayMessage method now no longer works with null values, but anyone relying on the comments when using the method will be misled.

Even good programmers , who earnestly try to write programs well, can easily make this kind of mistake.

Avoid Structured Programming

Layout describes the appearance of your code, aspects of which make little or no difference in the way a program is executed (use of tabs, placement of tokens, amount of whitespace, and so on). Structure describes how the executable parts of your program are arranged. Like the layout, you get to choose your program’s structure, and it can end up clear or convoluted.

Before we get to the next lesson, a quick bit of history. In the elder days of programming (1970s and earlier), many languages were unstructured. Controlling the flow of execution through an unstructured program was achieved using very simple if statements and unconditional jumps (a.k.a. goto statements). Individual statements had labels or line numbers. A goto statement would immediately transfer control to the referenced statement.

If you ever read Choose Your Own Adventure books, they work along similar lines (“If you stay to fight the goblin, go to page 231. If you decide to flee, go to page 193”).

For example, consider this program written in an old language called BASIC.9 It goes through the numbers 1 to 10 and prints out whether each one is odd or even.10

10 let x = 1
20 if x > 10 then goto 90
30 if x mod 2 = 0 then goto 60
40 print x, " is odd"
50 goto 70
60 print x, " is even"
70 let x = x + 1
80 goto 20
90 print "Finished"
You can picture the flow of control through this program by drawing a simple flow-control diagram, like in Figure 2-1.
../images/455320_1_En_2_Chapter/455320_1_En_2_Fig1_HTML.gif
Figure 2-1

Flow of control through the example BASIC program

In the diagram, each node represents a statement, and the arrows show the flow of control between those statements. This is a very small program, but already the flow of control is getting complicated. Its structure is ad-hoc, and there are lots of potential pathways from the beginning to the end of the program.

Larger unstructured programs consisting of thousands of statements tended to have so many goto statements that they became known as spaghetti code, since the lines on their control-flow diagrams ended up resembling a hellish tangle of spaghetti strands.

Structured programming emerged in reaction to the unbridled use of goto statements (Dijkstra, 1968). It argued that all programs could (and should) be written using only a small set of standard structures, like sequences, decisions, and loops. Those structures are modeled in Figure 2-2. An individual node in these diagrams can represent not just individual instructions, but whole collections of statements (i.e., blocks).
../images/455320_1_En_2_Chapter/455320_1_En_2_Fig2_HTML.gif
Figure 2-2

Fundamental programming structures

In a language like Java, these structures are available as things like if statements and for loops . The earlier unstructured program could be rewritten without gotos in a structured language like Java, as follows:

for (int x = 1; x <= 10; x++) {
    if (x % 2 == 0) {
        System.out.println(x + " is even");
    }
    else {
        System.out.println(x + " is odd");
    }
}
Its resulting flow-control diagram (Figure 2-3) is simpler because fewer independent paths exist through the code.
../images/455320_1_En_2_Chapter/455320_1_En_2_Fig3_HTML.gif
Figure 2-3

Control-flow diagram of the Java program

Jump Around

After this history lesson, you might be eyeing the goto statement keenly, your mouth watering at the mess you could make with it. To hell with the structured stuff, you might think.

But hold your horses! Unstructured programming has been largely banished from the programming world. Structured programming has been entrenching itself since at least the 1960s. Fighting against it is therefore going to be hard.

Under normal circumstances, my first piece of anti-advice would be to use goto statements as much as you can. However, goto occupies a special place in the programming hall of infamy, generally despised and regarded as a touchstone of bad programming practice. Many coding standards forbid its use entirely (for example, see National Weather Service, 2007; JPL, 2009) or strongly recommend against it.

Consequently, any attempt to use goto these days is likely to be crushed swiftly. In fact, some of today’s most popular languages (like Java and Python) don’t even include a goto statement, their designers having been mindful of its reputation. Even projects that allow goto statements tend to use it only in strictly-defined scenarios (see for example, kernel.org, 2017).

In this case, I will therefore make an exception and recommend that you don’t bother trying to use goto instructions, because it’s probably a waste of your time. Instead, I recommend you try to work within the bounds of structured programming and abuse its fundamental structures. This book has whole chapters dedicated each of them. To learn how to be dastardly with decisions, read Chapter 4. To see how you can make your colleagues loopy with loops, read Chapter 5. Subroutines, which are also discussed briefly in the next section, get a more complete treatment in Chapter 6.

Routine Work

Another fundamental structure in structured programming is the subroutine . This is a unit of code you can call on to perform a task. They are available in several forms, including procedures, functions and—in the case of an object-oriented language like Java—methods.

If you don’t organize your code into subroutines, then your program ends up as a huge wall of text. This fits nicely with one of the anti-rules of programming:

In general, bigger is better.

“Bigger is better.” That feels so emotionally satisfying, there’s just no need to even question it. Let’s see the earlier example of the bubble-sort code incorporated into a larger program that dispenses with subroutines:

Integer[] numbers = new Integer[5];
Scanner keyboard = new Scanner(System.in);
System.out.print("Enter filename> ");
String filename = keyboard.nextLine();
filename = filename.concat(".txt");
File inputFile = new File(filename);
BufferedReader reader = new BufferedReader(new FileReader(inputFile));
String text = null;
int i = 0;
while ((text = reader.readLine()) != null && i < 5) {
    numbers[i] = Integer.parseInt(text);
    i++;
}
reader.close();
for (i = 0; i < numbers.length; i++) {
    for (int j = 1; j < (numbers.length - i); j++) {
        if (numbers[j - 1] > numbers[j]) {
            Integer temp = numbers[j - 1];
            numbers[j - 1] = numbers[j];
            numbers[j] = temp;
        }
    }
}
for (i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

This wall of text . . . pardon me . . . this piece of code carries out at least four extra tasks in addition to sorting numbers.11 Understanding them requires a reader to go through the code line by line. This imposes a burden on the reader that is unnecessarily time-consuming and laborious if they’re not focusing on the details. And, being only about twenty lines long, this is considered a very small program. The problem only intensifies with longer ones.

Thumbs Down!

You can describe what a piece of code does at many levels.

At a lower level (closer to the details), you can describe what single statements do or see how the state of individual variables gets changed.

At a higher level (further away from the details), you can describe the code in terms of its purpose. The higher-level view describes code conceptually rather than in terms of the nitty-gritty.

Consider the bubble-sort code . At the lower level, you can talk about how this code maintains two indexes, i and j, each of which serves as a pointer to a specific value in the array numbers. You can explain how one for loop iterates i over the complete length of numbers one value at a time, etc. At a higher level, you can clump groups of statements together and refer to them as a whole (without reference to variables and if statements and loops and so on). Then, you could say that the code sorts an array of integers into ascending numerical order by performing a bubble sort on them.

Programmers like to be able to move easily between high levels and low levels as required. They might begin at the high level, considering only what a program is trying to do without being distracted by lower-level details. Subsequently, they might need to drill down to an interesting bit of the code to see how it works in lower-level detail (for example, to look for a bug in the code or to optimize it).

Subroutines give programmers that flexibility. Failing to put your code into subroutines grounds everyone at the lower level among the grubby, nitty-gritty details and denies them the option of viewing things at higher levels.

Large, monolithic programs like the last example can be rewritten to use subroutines. Rewriting the previous example would involve:
  • Creating several new subroutines

  • Moving the relevant portions of code into each subroutine

  • Writing a chain of subroutine calls

Perhaps like this:

Integer[] numbers = new Integer[5];
String filename = askUserForFilename();
File inputFile = openFile(filename);
readNumbersIntoArray(inputFile, numbers);
bubbleSort(numbers);
outputNumbers(numbers);
// ...
public String askUserForFilename()
{
    Scanner keyboard = new Scanner(System.in);
    System.out.print("Enter filename> ");
    String filename = keyboard.nextLine();
    filename = filename.concat(".txt");
    return filename;
}
// etc.

Now, it’s much easier to see at a glance what the program does.

Another important reason to use subroutines is to prevent the same code from being written twice. Programmers particularly hate code duplication . To see why, imagine that the last example were amended so that the code outputs the array of numbers twice: once before sorting and once after.
  • Without using subroutines, you’d have to write the code for outputting the array contents again at an earlier stage in the code.

  • With a subroutine, you’d need only add an extra call to the outputNumbers method.

Of course, that doesn’t save a huge amount of extra effort, but that’s not where the payoff comes. The payoff comes later when a change becomes necessary to the way the array contents are output. If the code responsible is in a subroutine , you only need to change it in one place. If, on the other hand, the code responsible is duplicated, you’d have to update all those copies, ensuring that each change is done exactly the same and that none of those copies is missed accidentally. You can well imagine this gets harder the more the code is duplicated and the more those duplicates are spread out.

This is the motivation behind another anti-rule for the bad programmer:

Duplicate! Spread stuff around; don’t consolidate things.

Subroutines will be discussed in more detail in Chapter 6.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.119.148