Author: Amber Colvin

  • How Many Spaces Is a Tab? Usually 2, 4, or 8

    How Many Spaces Is a Tab? Usually 2, 4, or 8

    How many spaces is a tab? Usually, a tab appears as 2, 4, or 8 columns, depending on the editor or viewer. Technically, however, a tab is one character—not a fixed number of space characters.

    The displayed width and the stored character are separate. A tab setting controls where the next tab stop appears, while inserting spaces places individual space characters in the file.

    How many spaces is a tab?

    A tab character is commonly represented as U+0009. In UTF-8, it occupies one byte, 0x09. That character does not contain instructions such as “insert four spaces.” The program displaying it decides how far to move the text.

    If the tab width is set to four columns, tab stops occur every four columns. A tab at the beginning of a line may therefore appear four columns wide. A tab typed after text that already occupies two columns may appear only two columns wide, because it moves the cursor to the next tab stop.

    Spaces behave differently. Each ordinary space is a separate character, usually U+0020, and occupies one column in a monospace font. Four inserted spaces remain four characters regardless of the viewer’s tab setting.

    In a monospace comparison, visible markers make the difference clear: one tab [⇥]X versus four literal spaces [␠␠␠␠]X. The ⇥ marker represents one tab character, while each ␠ marker represents one space. They may create the same indentation at a four-column setting, but the file contains different characters.

    How many spaces are in a tab at 2, 4, or 8 columns?

    There are no spaces “inside” a tab. The numbers 2, 4, and 8 describe common display settings:

    • 2 columns: Often used when compact indentation is important, such as in many web and configuration files.
    • 4 columns: A common general-purpose choice that provides clearer nesting without excessive horizontal movement.
    • 8 columns: A traditional default in many terminals and tools, making tabs highly visible but potentially creating wide indentation.

    A setting of four does not guarantee that every tab occupies four visible columns. It means the display uses tab stops four columns apart. The tab’s apparent width depends on its position on the line and the current display settings.

    How does tab width in spaces affect source files?

    Source files normally store the tab character itself, not its rendered width. The file may contain a sequence such as one tab, two tabs, or a mixture of tabs and spaces. An editor then renders those characters using its configured tab size.

    As a result, the same file can look different in two editors. A line indented with one tab may align at column 4 in one editor and column 8 in another. Code that relies on visual alignment, including comments or continued expressions, can become misleading when the tab setting changes.

    Project formatters and editor settings can also rewrite indentation. A formatter may convert tabs to spaces, convert leading spaces to tabs, or enforce a selected indentation size. These rules affect the characters saved to the file, not just their appearance. A file’s visual layout is therefore controlled by both its contents and the tools that interpret or format it.

    How do you keep indentation consistent across editors?

    Choose one project-wide indentation convention and configure every relevant tool to follow it. The important settings are usually named tab size, indent size, and insert spaces or insert tabs.

    • Decide whether indentation should use tabs, spaces, or a defined combination.
    • Set the editor’s tab display width to the project’s documented value, such as 2 or 4 columns.
    • Set automatic indentation to insert the chosen character type rather than relying on each editor’s default.
    • Configure the project formatter to preserve or normalize that convention when files are saved.
    • Check existing files for mixed leading tabs and spaces before applying broad conversion.

    For a spaces-only convention, a four-level indent means four literal spaces per level. For a tabs-only convention, one tab may represent one indentation level while its visual width remains configurable. Keeping those choices explicit prevents indentation from changing when the file moves between editors, terminals, and code-review tools.

  • Pseudocode: Definition, Conventions, and Example

    Pseudocode: Definition, Conventions, and Example

    Pseudocode is a language-neutral way to describe an algorithm. It uses familiar words, named variables, and indentation to show what a program should do without requiring the exact syntax of Python, JavaScript, Java, or another language.

    A clear pseudocode plan helps you check the logic, explain it to other people, and translate it into executable code later. It focuses on actions and decisions rather than punctuation or language-specific rules.

    What Is Pseudocode, and What Is It Used For?

    Pseudocode is used to plan an algorithm before implementation. An algorithm is a defined sequence of steps for completing a task, such as calculating an average, searching a list, or processing a user’s input.

    Writing pseudocode first makes the logic easier to review. You can identify missing inputs, incorrect conditions, or endless loops before dealing with the details of a programming language. It is also useful for documentation because a reader can understand the process without knowing the language used to build it.

    Effective pseudocode should:

    • State the steps in the order they happen.
    • Name the data the algorithm reads, stores, and produces.
    • Show decisions and repeated actions explicitly.
    • Use consistent indentation and control-flow terms.

    Which Conventions Make Pseudocode Readable for Sequence, Input, Output, Conditions, and Loops?

    There is no single universal pseudocode standard. Choose clear terms and apply them consistently. These conventions cover most algorithms:

    • Sequence: Put one action after another, with each step on its own line. The order of the lines represents the order of execution.
    • Input: Use INPUT to show that the algorithm receives data, such as INPUT customer_name.
    • Output: Use OUTPUT to show displayed or returned information, such as OUTPUT total.
    • Assignment: Use SET to give a variable a value, such as SET total TO 0. Some authors use an equals sign instead.
    • Condition: Use IF, THEN, ELSE, and END IF to describe a decision. Indent the actions belonging to each branch.
    • Loop: Use FOR for a known number of repetitions and WHILE when repetition continues as long as a condition remains true. Mark the loop’s boundary with END FOR or END WHILE.

    Use descriptive variable names, such as average_price rather than x. Capitalized keywords can make control flow easy to scan, but capitalization is optional. The important rule is consistency.

    How Does Pseudo Code Differ From Executable Code and Flowcharts?

    Pseudocode is not executable code. A compiler or interpreter cannot run it because terms such as INPUT and END IF do not have one fixed technical meaning. Real code must follow the grammar, data types, operators, and libraries of a chosen programming language.

    A flowchart represents an algorithm visually with symbols, arrows, and branches. Pseudocode represents the same logic as structured text. Flowcharts can make paths and decisions immediately visible, while pseudocode is usually faster to edit, search, and convert into code. Neither format replaces careful testing.

    How to write pseudocode: A Worked Example With Variables, Indentation, and Program-Code Translation

    Suppose an algorithm must read the prices of three items, calculate the total and average, and report whether the average is above 50. The following example uses sequence, input, output, a loop, a condition, and named variables:

    • START
    • SET item_count TO 3
    • SET total TO 0
    • FOR item_number FROM 1 TO item_count
      • INPUT price
      • SET total TO total + price
    • END FOR
    • SET average_price TO total / item_count
    • IF average_price > 50 THEN
      • OUTPUT “The average price is high.”
    • ELSE
      • OUTPUT “The average price is within budget.”
    • END IF
    • OUTPUT total, average_price
    • END

    To translate this into program code, map each abstract action to the target language’s syntax. For example, a Python implementation could use total = 0 for assignment, float(input()) for numeric input, for item_number in range(1, item_count + 1) for the counted loop, and if average_price > 50: for the condition. The indentation and variable relationships remain the same, but the keywords and punctuation now follow Python’s rules.

  • Ladder Logic for PLC Beginners: Read a Basic Control Rung

    Ladder Logic for PLC Beginners: Read a Basic Control Rung

    Ladder logic is a graphical language for controlling machines with a programmable logic controller (PLC). It uses relay-style symbols so you can follow a control decision from input conditions to an output.

    In PLC ladder logic, the controller repeatedly reads field inputs, evaluates instructions, and updates outputs. Learning to follow that sequence makes a basic ladder logic diagram predictable rather than a collection of unfamiliar symbols.

    Ladder logic in the PLC scan cycle

    A ladder diagram is arranged between two vertical lines called rails. The left rail represents the beginning of logical power flow, and the right rail represents the destination. Horizontal lines between them are rungs. Each rung contains instructions that determine whether an output instruction becomes true.

    The PLC does not physically send power through the drawing as a relay panel would. Instead, it evaluates each instruction as a Boolean condition. A rung is true when at least one complete path from the left rail to the output is true. A rung is false when every possible path is blocked.

    The controller generally evaluates rungs from top to bottom and instructions from left to right. The exact scan details vary by PLC, but this ordering is the essential model for following control logic.

    Contacts, coils, rails, and rungs in a ladder logic diagram

    A contact tests a Boolean value, usually an input, internal bit, timer, counter, or output status.

    • Normally open (NO) contact: This instruction is true when its referenced bit is on. It passes logic when the bit equals 1.
    • Normally closed (NC) contact: This instruction is true when its referenced bit is off. It passes logic when the bit equals 0.
    • Output coil: This instruction writes the rung result to an output or internal bit. A true coil turns its assigned bit on; a false coil turns it off.
    • Rail: A vertical boundary that frames the logical path.
    • Rung: A horizontal line containing the conditions and result for one control decision.

    “Normally open” and “normally closed” describe the instruction’s logic behavior or the associated device’s unactuated design. The drawn contact does not prove the live field device’s current state. Check the referenced input or bit to know whether the instruction is currently true.

    How ladder logic programming follows input, logic, and output stages

    Ladder logic programming follows a repeating PLC scan with three practical stages:

    1. Input read: The PLC samples connected input devices, such as push buttons, switches, and sensors, and stores their current states in an input image or memory area.
    2. Logic execution: The PLC evaluates the program, including ladder rungs, using the stored input states and current internal values. It calculates whether each contact path and output coil is true.
    3. Output update: The PLC transfers calculated output states to physical outputs, energizing or de-energizing devices such as contactors, solenoid valves, and indicator lamps.

    Because outputs are commonly updated after logic execution, a change at a push button normally affects the controlled device during the scan in which the PLC reads that change and completes the program. The next scan then uses the updated output or internal status where applicable.

    How to read ladder logic in a simple start-stop circuit

    Consider a motor-control rung with this arrangement:

    Left rail → NC Stop → (NO Start in parallel with NO Motor Auxiliary) → Motor coil → Right rail

    The parallel branch is a seal-in, or holding, circuit. The motor’s auxiliary status keeps the motor command true after the Start button is released.

    1. At rest: The Stop button is not pressed, so its physical input is on when the button uses normally closed wiring. The NC Stop instruction is therefore true. Start is not pressed, so the NO Start instruction is false. The motor auxiliary bit is also false, leaving both parallel paths open. The rung is false, and the Motor coil is off.
    2. When Start is pressed: The input read stage records Start as on. During logic execution, the NC Stop instruction remains true and the NO Start instruction becomes true. A complete path now reaches the Motor coil, so the coil becomes true. During output update, the motor output energizes.
    3. After Start is released: The Start input returns off, making its NO instruction false. The energized motor’s auxiliary bit becomes on during the relevant scan, so the parallel auxiliary contact becomes true. The rung remains true and the motor stays energized.
    4. When Stop is pressed: The Stop input changes off. The NC Stop instruction becomes false, breaking the rung before either start path can reach the coil. The Motor coil becomes false, and the output update de-energizes the motor. On a later scan, the auxiliary bit also returns off.

    This left-to-right trace is the core method for how to read ladder logic: identify each referenced bit, determine whether each instruction is true, follow every complete path, and then check which output coil receives the rung result.

  • Standard Deviation in R: Calculate It Correctly

    Standard Deviation in R: Calculate It Correctly

    Use sd() to calculate standard deviation in R for a numeric vector or a data-frame column. For standard deviation in R, the main interpretation decision is whether your data represent a sample or an entire population. R’s default result is the sample standard deviation.

    The function also returns NA when missing values are present unless you explicitly remove them during the calculation.

    Standard deviation in R with sd()

    Pass a numeric vector to sd():

    x <- c(12, 15, 14, 10, 9)

    sd(x)

    This returns approximately 2.54951. The values have a mean of 12, and R divides the sum of squared deviations by 4, which is the sample denominator: the number of observations minus one.

    You can apply the same standard deviation function to a numeric column in a data frame:

    scores <- data.frame(score = c(12, 15, 14, 10, 9))

    sd(scores$score)

    This also returns approximately 2.54951. Use scores[[“score”]] as an alternative to scores$score. Both expressions select the underlying numeric vector. By contrast, scores[“score”] returns a one-column data frame, which is not the intended input for this calculation.

    The standard deviation function in R handles missing values

    By default, sd() does not ignore missing observations:

    measurements <- c(4, 7, NA, 10)

    sd(measurements)

    The result is NA because the missing value propagates through the calculation. Add na.rm = TRUE to exclude missing values:

    sd(measurements, na.rm = TRUE)

    This calculates the sample standard deviation of 4, 7, and 10. The argument removes only the NA values; it does not replace them or estimate what they might have been.

    Use the same argument with a data-frame column:

    sd(scores$score, na.rm = TRUE)

    If no nonmissing values remain, or only one nonmissing value remains, a standard deviation cannot be estimated and R returns NA.

    Sample versus population standard deviation

    sd() uses the sample standard deviation formula:

    sqrt(sum((x – mean(x))^2) / (n – 1))

    Here, n is the number of observed values. The n – 1 denominator estimates the variability of a larger population from a sample, so do not label R’s default result as a population standard deviation.

    Use a population standard deviation when your vector contains every member of the population being measured. The population formula divides by n:

    sqrt(sum((x – mean(x))^2) / n)

    In R, calculate it directly with:

    population <- c(12, 15, 14, 10, 9)

    sqrt(mean((population – mean(population))^2))

    If missing values are possible, remove them first:

    complete <- population[!is.na(population)]

    sqrt(mean((complete – mean(complete))^2))

    You can also convert a sample result to a population result with sd(complete) * sqrt((n – 1) / n), where n <- length(complete).

    Check R standard deviation with a worked vector

    This vector makes the denominator difference easy to verify:

    values <- c(2, 4, 4, 4, 5, 5, 7, 9)

    mean(values)

    sd(values)

    The mean is 5. The sum of squared deviations from that mean is 32, and there are eight observations. Therefore:

    • Sample standard deviation: sqrt(32 / 7), which is approximately 2.13809 and matches sd(values).
    • Population standard deviation: sqrt(32 / 8), which equals 2.

    Use sd() for the usual sample estimate, add na.rm = TRUE when missing values should be excluded, and use the denominator-n formula when the data represent the complete population.

  • Append to pandas DataFrame with pd.concat

    Append to pandas DataFrame with pd.concat

    Use pd.concat to append to pandas DataFrame objects in current pandas versions. It replaces the removed df.append pattern and can combine DataFrames, dictionaries converted to rows, or batches of records. For most row additions, use ignore_index=True so the result receives one continuous index.

    pd.concat returns a new DataFrame; it does not modify either input in place. The basic pattern is pd.concat([df, new_data], ignore_index=True).

    Replace df.append with pd.concat: side-by-side legacy and current code with ignore_index

    The pandas DataFrame append method was removed in pandas 2.0. If older code contains an append call, replace it with a list passed to pd.concat.

    1. Legacy code, no longer available: df.append(new_df, ignore_index=True)
    2. Current code: pd.concat([df, new_df], ignore_index=True)

    The replacement is usually a direct change. Both operations place the rows from new_df below the rows in df. Assign the result if you need the combined object:

    result = pd.concat([df, new_df], ignore_index=True)

    Use ignore_index=True when the original index labels are not meaningful and the output should run from 0 through the number of rows minus 1. Without it, pandas preserves the existing labels. That can produce duplicate index values, especially when both inputs use the default range index.

    For example, concatenating two three-row DataFrames without ignore_index can create an index of 0, 1, 2, 0, 1, 2. This is valid, but label-based selection and joins may become ambiguous. Use result.reset_index(drop=True) later if resetting the index is more convenient.

    Append DataFrame objects with pd.concat: column alignment, missing values, and duplicate indexes

    To append DataFrame objects, pass them in order inside a list. By default, pd.concat combines rows with axis=0 and aligns columns by column name:

    result = pd.concat([sales_january, sales_february], ignore_index=True)

    Column order in the result generally follows the first DataFrame, followed by columns introduced by later DataFrames. If the inputs do not contain the same columns, pandas uses the union of their column names. A missing value appears as NaN or another appropriate missing-value marker.

    • If the first DataFrame has customer and total, while the second has customer and currency, the result contains all three columns.
    • January rows have missing values in currency.
    • February rows have missing values in total.

    This name-based alignment prevents values from being assigned to the wrong field when column order differs. If you want only columns shared by every input, use join=”inner”:

    result = pd.concat([df_a, df_b], join=”inner”, ignore_index=True)

    Use the default join=”outer” when preserving every column matters. Check the resulting dtypes after concatenation if one input contains numbers and another contains strings or missing values; pandas may broaden a column’s dtype to accommodate both.

    Duplicate index labels are retained unless you explicitly request a new index. They are not automatically errors. Preserve them when the labels identify source records, or set ignore_index=True when the combined DataFrame represents a new sequential collection.

    Add a dictionary or one row when appending to a pandas DataFrame

    A dictionary represents one row when each key is a column name and each value is that row’s value. Wrap it in a one-item list before creating a DataFrame:

    row = {“product”: “Notebook”, “quantity”: 3, “price”: 4.50}
    result = pd.concat([df, pd.DataFrame([row])], ignore_index=True)

    The list is important because pd.DataFrame([row]) creates one record. Calling pd.DataFrame(row) with scalar values does not provide enough information for pandas to determine the row index.

    Keys are matched to existing columns by name. If the dictionary omits a column, the new row receives a missing value there. If it introduces a new key, pd.concat adds a new column and fills that column with missing values for earlier rows:

    new_row = {“product”: “Pen”, “quantity”: 10}
    df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True)

    For one-row additions inside a controlled, interactive workflow, direct assignment such as df.loc[len(df)] = row can be concise. For a consistent append DataFrame workflow, converting the record and using pd.concat makes column alignment explicit.

    Build many rows efficiently with pandas concat for rows

    Do not repeatedly concatenate a growing DataFrame inside a loop. Each operation can allocate and copy the accumulated data, making a long sequence much slower than one final combination. The efficient pandas concat rows approach is to collect DataFrames or records first.

    Collect records as dictionaries, convert the complete batch once, and concatenate once:

    records = []
    for item in source:
        records.append({“id”: item.id, “status”: item.status})
    new_rows = pd.DataFrame(records)
    result = pd.concat([df, new_rows], ignore_index=True)

    This works well when each iteration produces a dictionary. If each iteration already produces a DataFrame, store those frames in a list instead:

    frames = [df]
    for batch in batches:
        frames.append(batch)
    result = pd.concat(frames, ignore_index=True)

    For an empty batch, decide whether to return the original DataFrame or concatenate it with an explicitly shaped empty DataFrame. When column types matter, define the expected columns and dtypes before processing so missing or empty inputs do not unexpectedly change the result.

  • decimal to two’s complement: Convert Signed Values at a Fixed Width

    decimal to two’s complement: Convert Signed Values at a Fixed Width

    To perform decimal to two’s complement conversion, declare the bit width first. For an 8-bit signed value, the range is −128 through +127. Positive values use ordinary binary padded with leading zeros; negative values use the invert-and-add-one method.

    For two’s complement to decimal decoding, inspect the leftmost bit. A 0 means use ordinary positive binary weights. A 1 means the value is negative, so either use a negative sign-bit weight or invert the bits, add one, and negate the result.

    Choose an 8-bit width and represent positive values such as +13

    Bit width is part of the representation because the same visible bits can have different meanings at different widths. For example, 1101 is an unsigned binary value, but an 8-bit signed representation must contain exactly eight bits.

    To represent +13 in 8-bit two’s complement:

    1. Convert the magnitude, 13, to binary: 1101.
    2. Pad on the left with zeros until there are eight bits: 00001101.
    3. Because the first bit is 0, the pattern represents a positive value.

    Check the result by adding the weights of the 1 bits: 8 + 4 + 1 = 13. Thus, the 8-bit pattern 00001101 converts back to +13.

    Convert a negative decimal value using decimal to two’s complement and binary to two’s complement steps

    For a negative decimal value, first write the positive magnitude at the declared width. Then apply the standard binary to two’s complement process: invert every bit and add one.

    Convert −13 to an 8-bit pattern as follows:

    1. Write positive 13 in eight bits: 00001101.
    2. Invert every bit: 11110010.
    3. Add one: 11110011.

    Therefore, −13 is represented as 11110011 in 8-bit two’s complement. The addition is binary addition, so 11110010 + 1 produces 11110011 without changing the width.

    The round-trip check confirms the result. Start with 11110011, invert it to 00001100, add one to get 00001101, and read that magnitude as 13. Since the original pattern had a sign bit of 1, the decoded result is −13.

    Decode two’s complement to decimal using signed bit weights

    For two’s complement to decimal conversion, use the leftmost bit as the sign bit and apply signed weights. In an 8-bit value, the weights from left to right are:

    −128, 64, 32, 16, 8, 4, 2, 1

    This makes the decoding path direct:

    • For 00001101, add the weights under the 1 bits: 8 + 4 + 1 = +13.
    • For 11110011, add the signed weights under the 1 bits: −128 + 64 + 32 + 16 + 2 + 1 = −13.

    The sign bit changes the interpretation rather than simply adding a positive 128. A leading 0 contributes no sign weight, while a leading 1 contributes −128 in an 8-bit representation. This weighted method provides a second check against the invert-and-add-one method.

    Check the 8-bit signed range, overflow, and round-trip results

    An n-bit two’s-complement representation has the range −2n−1 through 2n−1 − 1. With eight bits, that is −27 through 27 − 1, or −128 to +127. The negative side has one extra value because zero uses the positive sign pattern.

    • Valid positive limit: +127 is 01111111.
    • Valid negative limit: −128 is 10000000.
    • Overflow: +128 and −129 cannot be represented as signed 8-bit values.

    Before converting, verify that the decimal value falls within the selected range. After converting, decode the resulting bit pattern back to decimal. The positive round trip is +13 → 00001101 → +13, and the negative round trip is −13 → 11110011 → −13. If the final value differs, check the declared width, padding, bit inversion, and add-one step.

  • How to View Website Code in Any Browser

    How to View Website Code in Any Browser

    To learn how to view website code, open the page’s source rather than relying on its visible layout. On a desktop browser, the fastest options are the page’s context menu, a keyboard shortcut, or a view-source: URL.

    When you see source code, you are reading the HTML delivered by the server for that page request. This view helps you find text, metadata, linked CSS, and JavaScript references, but it is different from the live page structure shown in developer tools.

    How to view website code in a desktop browser: menus, shortcuts, and view-source

    1. Use the page menu: Right-click an empty area of the webpage and select View Page Source, View Source, or a similarly named option. Chrome, Edge, and Firefox generally provide this context-menu command on ordinary webpages.
    2. Use a keyboard shortcut: On Windows or Linux, press Ctrl+U in Chrome, Edge, or Firefox. On macOS, the shortcut varies by browser; Chrome and Firefox commonly use Option+Command+U or Command+U. If one shortcut does not work, use the context menu or address-bar method.
    3. Use the browser menu: Safari users can enable the Develop menu in Safari’s settings, then choose Develop > Show Page Source. Other browsers may place a source command under a page or developer menu, although a direct menu item is not available in every version.
    4. Use a view-source URL: Copy the page address, open a new tab, and add view-source: before the complete address. For example, enter view-source:https://example.com/page in the address bar, then press Enter. This method is useful when the context-menu command is hidden or disabled.

    The browser opens the HTML in a new tab, often with line numbers and basic formatting. The source tab is read-only from the website’s perspective. You can save or copy the displayed text for analysis, but changing a local copy does not change the page on the server.

    How to see source code on a phone or tablet

    Mobile browsers do not consistently include a View Source command in their menus. The most portable method is to type view-source: followed by the page URL in the address bar. For example, use view-source:https://example.com. Chromium-based mobile browsers and some Firefox versions may open the returned HTML this way.

    If the browser treats the address as a search instead of a source request, try these steps:

    • Load the webpage normally, copy its complete URL, and paste it into a new tab.
    • Add view-source: without a space before https:// or http://.
    • Try the browser’s long-press page menu for a source option, if one is available.

    Safari on iPhone and iPad does not provide a consistent built-in page-source viewer. For detailed inspection, open the page on a desktop browser or use remote web-inspection tools connected to a Mac. A mobile view may also omit tools available in desktop browsers, so the desktop method is usually more reliable for technical checks.

    How to check source code for text, CSS, and JavaScript

    Once the source tab is open, press Ctrl+F on Windows or Linux, or Command+F on macOS, to search the HTML. Search for a distinctive word from the page, the title, a heading, an ID, a class name, or a section of a URL.

    To check source code for visible content, search for the exact text as it appears on the page. If the search finds nothing, the text may be added after the initial HTML loads, inserted only after an interaction, or supplied inside an embedded component. Differences in punctuation, capitalization, and encoded characters can also prevent an exact match.

    Look for these common references when identifying linked files:

    • CSS: Search for stylesheet or .css. A typical reference looks like <link rel=”stylesheet” href=”styles.css”>. The source shows the file’s address, not necessarily the CSS rules inside that file.
    • JavaScript: Search for <script, src=, or .js. An external file may appear as <script src=”app.js”></script>. JavaScript can also appear directly between script tags.
    • Metadata and structure: Search for <title>, meta, canonical, h1, or body to locate page information and major HTML sections.

    Relative links such as app.js or /assets/site.css are resolved against the page’s domain and path. A source viewer may let you open a linked file by selecting its URL, but that opens a separate resource rather than displaying it as part of the HTML document.

    How to look at website code versus the live DOM

    Page source shows the HTML delivered in the initial response. The live DOM, visible in a browser’s developer tools under Elements or Inspector, shows the document after the browser has parsed it and scripts have run.

    That distinction explains why the two views may not match. JavaScript can add a product list, replace a message, insert navigation, change attributes, or remove an element after the page loads. A framework can also build much of the visible page from a small initial HTML shell. In those cases, the content appears in the live DOM but not in the original source.

    Use page source when you need to inspect the server-delivered HTML, initial metadata, or links included in the response. Use the live DOM when you need to inspect the current structure after scripts, user actions, or browser updates have changed it.

    Developer tools also let you edit the live DOM or CSS temporarily for testing. Those edits affect only your local browser session; they do not modify the website’s original server source. To identify what changed after load, compare the page-source tab with the current Elements view, and use the Network panel when you need to inspect the actual HTML response or files requested by the browser.

  • SQL DELETE statement: syntax, WHERE filters, and NOT EXISTS

    SQL DELETE statement: syntax, WHERE filters, and NOT EXISTS

    Use the SQL DELETE statement to remove existing rows from a table. Its basic form names the target table, then optionally adds a WHERE condition. Supplying a qualifying condition removes only matching rows; omitting WHERE removes every row in the target table. These are different operations, not interchangeable forms.

    A DELETE in SQL statement can select rows by their own column values or by the absence of related rows. A SQL DELETE query using NOT EXISTS is useful when deletion should occur only if no matching record exists in another table.

    SQL DELETE statement syntax: table references and affected rows

    The minimal SQL DELETE syntax is:

    DELETE FROM table_name WHERE condition;

    DELETE FROM identifies the table affected by the operation. The optional WHERE clause determines which rows qualify. For example:

    DELETE FROM sessions WHERE expires_at < CURRENT_TIMESTAMP;

    This removes only sessions whose expiration time has passed. Rows with a future expiration time remain in the table. If no rows satisfy the condition, the statement completes without deleting anything.

    When WHERE is omitted, every row in the named table qualifies:

    DELETE FROM sessions;

    This empties the table’s rows but does not normally remove the table itself, its columns, or its indexes. Because the statement has no row filter, it must not be treated as equivalent to a DELETE with a qualifying condition. A condition that happens to match every current row is still a deliberate filter; an omitted condition provides no row-level protection.

    Table references become important when a statement uses more than one table or when aliases make column ownership clearer. A qualified reference such as orders.customer_id identifies the column from orders, rather than relying on an ambiguous unqualified name.

    Filtering DELETE in SQL with WHERE and aliases

    The WHERE clause can combine equality, ranges, Boolean logic, and null checks. For example, this statement deletes old cancelled orders while preserving recent or active orders:

    DELETE FROM orders WHERE status = ‘cancelled’ AND created_at < DATE ‘2024-01-01’;

    The database evaluates the condition for each candidate row. Both parts of the AND expression must be true for that row to be deleted. Use parentheses when combining AND with OR, so the intended precedence is explicit.

    An alias is useful when the target table appears in a correlated subquery. In systems that support this PostgreSQL-style form, the alias follows the table name:

    DELETE FROM customers AS c WHERE c.status = ‘inactive’;

    Here, c refers to the row being considered for deletion. Alias syntax varies by database system. For example, SQL Server commonly writes a target alias before the FROM clause:

    DELETE c FROM customers AS c WHERE c.status = ‘inactive’;

    Check the syntax for the specific database engine before moving a multi-table DELETE into production. The central rule remains the same: the target reference identifies the table, and the WHERE clause limits affected rows.

    How SQL NOT EXISTS evaluates a correlated absence test

    SQL NOT EXISTS tests whether a subquery returns no rows. It does not compare a value directly. Instead, the database evaluates the subquery as an existence test and returns true when the subquery produces zero matching rows.

    A correlated example identifies customers who have no orders:

    SELECT c.customer_id
    FROM customers AS c
    WHERE NOT EXISTS (SELECT 1 FROM orders AS o WHERE o.customer_id = c.customer_id);

    The inner query is correlated because it refers to c.customer_id from the outer query. Logically, the database considers each customer, searches orders for an order with the same customer ID, and applies NOT EXISTS. If at least one related order is found, the condition is false. If none is found, the condition is true and that customer appears in the result.

    SELECT 1 is conventional in an existence test. The selected value is irrelevant; only whether a row exists matters. The database can also stop searching after finding the first match. This makes the expression a direct way to represent “no related row satisfies this condition.”

    NOT EXISTS also avoids a common null issue associated with some NOT IN expressions. If the subquery can return null, NOT IN may produce an unknown result rather than the expected absence test. The correlated relationship should still use compatible keys and appropriate indexes.

    Worked SQL DELETE query examples for selected and unmatched rows

    To delete selected rows based on a related table, place the correlated absence test in the DELETE filter. This PostgreSQL-style example removes inactive customers who have never placed an order:

    DELETE FROM customers AS c
    WHERE c.status = ‘inactive’
    AND NOT EXISTS (SELECT 1 FROM orders AS o WHERE o.customer_id = c.customer_id);

    The customer must satisfy both conditions: the status must be inactive, and the subquery must find no order for that customer. An inactive customer with even one matching order is not deleted.

    The same pattern can identify unmatched rows before deletion. This query lists staging contacts that have no corresponding approved contact:

    SELECT s.contact_id, s.email
    FROM staging_contacts AS s
    WHERE NOT EXISTS (SELECT 1 FROM approved_contacts AS a WHERE a.email = s.email);

    After confirming that the result is correct, the selection can become a DELETE:

    DELETE FROM staging_contacts AS s
    WHERE NOT EXISTS (SELECT 1 FROM approved_contacts AS a WHERE a.email = s.email);

    This removes only staging contacts whose email has no match in approved_contacts. It does not delete approved contacts, and it does not delete staging contacts that do have a match.

    For a safer workflow, run the correlated SELECT with the exact intended filter first, inspect the returned keys, and then execute the corresponding DELETE in a transaction when the database supports transactional DML. Also verify that the relationship column is the correct business key; matching on an unrelated or nullable column can classify rows as unmatched incorrectly.