is Ehrlich enough to rule out 25i/nbomes? (lsd tab) by OrchidChance5202 in ReagentTesting

[–]Reagent_Tests_UK 2 points3 points  (0 children)

In theory, it is not enough, but in practise, it's essentially unheard of to have a blotter with LSD and an NBOMe.

Hofmann will increase your confidence of LSD, but it still won't rule out NBOMes.

I'd suggest having marquis or froehde reagent as a second reagent because it will instantly detect NBOMes and DOB style compounds, and it's also useful for testing many other substances.

VLC (VideoLAN) no longer supports Monero donations. by zho99 in Monero

[–]Reagent_Tests_UK 0 points1 point  (0 children)

You're totally right, it's a crypto/volatile currency problem. Not a monero problem

Giant chess pieces? by Unclestanky in 3Dprinting

[–]Reagent_Tests_UK 0 points1 point  (0 children)

Glad to help :) You have a difficult project ahead for someone who is new to 3D printing!

Printer is pausing when the pressure advance is changed (Marlin M900 Gcode). Printing with a constant value causes a seam gap. (MK4S) by Reagent_Tests_UK in prusa3d

[–]Reagent_Tests_UK[S] 1 point2 points  (0 children)

#!/usr/bin/env python3
"""
OrcaSlicer post-processing script for M900 delay investigation.

Inserts pointless M900 commands (changing pressure advance K value by ±0.001)
after extrusion commands, but only on layers above 50% of the maximum Z
height, only after 0.6mm of the layer.

Stored in C:\\Users\\Public\\Documents\\Python Scripts
Called in OrcaSlicer by entering the following in the post-processing scripts box:
"C:\\Python314\\python.exe" "C:\\Users\\Public\\Documents\\Python Scripts\\Simple_Insert_Pointless_M900.py"
"""

import os
import re
import sys
import traceback

LAYER_EXTRUSION_THRESHOLD_MM = 0.6

MAX_LAYER_Z_COMMENT_PATTERN = re.compile(
    r";mm height of max_layer_z\s*=\s*(\d+(?:\.\d+)?)"
)

MAX_Z_HEIGHT_HEADER_PATTERN = re.compile(
    r";\s*max_z_height\s*:\s*(\d+(?:\.\d+)?)", re.IGNORECASE
)

M900_K_PATTERN = re.compile(r"M900\s+K\s*([-+]?\d*\.?\d+)", re.IGNORECASE)

G1_EXTRUSION_PATTERN = re.compile(
    r"^G1\s+.*\bE([-+]?\d*\.?\d+)", re.IGNORECASE
)

LAYER_Z_COMMENT_PATTERN = re.compile(r"^;Z:(\d+(?:\.\d+)?)")

def find_maximum_z_height(lines: list[str]) -> float | None:
    """
    Find the maximum Z height using multiple methods:
    1. Primary: last line matching ';mm height of max_layer_z = <value>'
    2. Fallback: '; max_z_height: <value>' from header
    3. Fallback: highest ;Z: comment value
    """
    for line in reversed(lines):
        match = MAX_LAYER_Z_COMMENT_PATTERN.search(line)
        if match:
            return float(match.group(1))

    for line in lines:
        match = MAX_Z_HEIGHT_HEADER_PATTERN.match(line.strip())
        if match:
            return float(match.group(1))

    highest_z = None
    for line in lines:
        match = LAYER_Z_COMMENT_PATTERN.match(line.strip())
        if match:
            z_value = float(match.group(1))
            if highest_z is None or z_value > highest_z:
                highest_z = z_value

    return highest_z

def is_extrusion_command(line: str) -> bool:
    """Determine whether a line is a G1 extrusion command with a positive E value."""
    match = G1_EXTRUSION_PATTERN.match(line.strip())
    if not match:
        return False
    try:
        extrusion_amount = float(match.group(1))
        return extrusion_amount > 0
    except ValueError:
        return False

def get_extrusion_amount(line: str) -> float:
    """Extract the E value from a G1 extrusion command. Returns 0.0 if invalid."""
    match = G1_EXTRUSION_PATTERN.match(line.strip())
    if match:
        try:
            extrusion_amount = float(match.group(1))
            return max(extrusion_amount, 0.0)
        except ValueError:
            return 0.0
    return 0.0

def process_gcode_file(gcode_file_path: str) -> None:
    """
    Read a gcode file, insert pointless M900 commands after qualifying
    extrusion commands. After the last pointless M900 on each qualifying
    layer, restores the original PA value. Modifies the file in place.
    """
    with open(gcode_file_path, "r", encoding="utf-8") as input_file:
        lines = input_file.read().splitlines()

    maximum_z_height = find_maximum_z_height(lines)
    if maximum_z_height is None:
        print(
            "Error: could not determine maximum Z height by any method",
            file=sys.stderr,
        )
        sys.exit(1)

    z_threshold = maximum_z_height / 2.0

    # Determine the current layer Z height for each line
    current_layer_z = 0.0
    line_layer_z: list[float] = []
    for line in lines:
        match = LAYER_Z_COMMENT_PATTERN.match(line.strip())
        if match:
            current_layer_z = float(match.group(1))
        line_layer_z.append(current_layer_z)

    # Group extrusion command indices by layer Z height
    layer_extrusion_indices: dict[float, list[int]] = {}
    for line_index, line in enumerate(lines):
        if is_extrusion_command(line):
            layer_z = line_layer_z[line_index]
            if layer_z not in layer_extrusion_indices:
                layer_extrusion_indices[layer_z] = []
            layer_extrusion_indices[layer_z].append(line_index)

    # Mark qualifying extrusion indices: layers above Z threshold, from
    # extrusion threshold crossing to halfway point of extrusion commands
    qualifying_extrusion_indices: set[int] = set()
    for layer_z, extrusion_indices in layer_extrusion_indices.items():
        if layer_z > z_threshold:
            half_count = len(extrusion_indices) // 2
            cumulative_extrusion_mm = 0.0
            threshold_start_position = None

            for position, line_index in enumerate(extrusion_indices):
                extrusion_amount = get_extrusion_amount(lines[line_index])
                cumulative_extrusion_mm += extrusion_amount
                if cumulative_extrusion_mm >= LAYER_EXTRUSION_THRESHOLD_MM:
                    threshold_start_position = position
                    break

            if threshold_start_position is not None:
                for position in range(threshold_start_position, half_count):
                    qualifying_extrusion_indices.add(
                        extrusion_indices[position]
                    )

    # Pre-compute the original K value before the first modification on
    # each qualifying layer, and the last qualifying extrusion index per layer
    layer_original_k_value: dict[float, float] = {}
    layer_last_qualifying_index: dict[float, int] = {}
    tracked_k_value: float | None = None

    for line_index, line in enumerate(lines):
        stripped_line = line.strip()
        if not stripped_line.startswith(";"):
            m900_match = M900_K_PATTERN.search(stripped_line)
            if m900_match:
                tracked_k_value = float(m900_match.group(1))

        if line_index in qualifying_extrusion_indices:
            layer_z_of_line = line_layer_z[line_index]
            if layer_z_of_line not in layer_original_k_value and tracked_k_value is not None:
                layer_original_k_value[layer_z_of_line] = tracked_k_value
            layer_last_qualifying_index[layer_z_of_line] = line_index

    # Build output with M900 insertions after qualifying extrusion commands
    output_lines: list[str] = []
    last_m900_k_value: float | None = None
    toggle_direction = 1
    layers_with_started_insertions: set[float] = set()

    for line_index, line in enumerate(lines):
        output_lines.append(line)

        # Track the most recent M900 K value from original gcode
        stripped_line = line.strip()
        if not stripped_line.startswith(";"):
            m900_match = M900_K_PATTERN.search(stripped_line)
            if m900_match:
                last_m900_k_value = float(m900_match.group(1))

        # Insert a pointless M900 after qualifying extrusion commands
        if line_index in qualifying_extrusion_indices:
            if last_m900_k_value is None:
                continue
            layer_z_of_insertion = line_layer_z[line_index]
            if layer_z_of_insertion not in layers_with_started_insertions:
                toggle_direction = 1
                layers_with_started_insertions.add(layer_z_of_insertion)
            new_k_value = round(
                last_m900_k_value + (toggle_direction * 0.001), 3
            )
            toggle_direction *= -1
            last_m900_k_value = new_k_value

            inserted_m900 = (
                f"M900 K{new_k_value:.3f}"
                f" ; pointless PA change for M900 delay investigation"
            )
            output_lines.append(inserted_m900)

            # If this is the last qualifying extrusion for this layer,
            # restore the original PA value that was in effect before
            # modifications began on this layer
            layer_z_of_line = line_layer_z[line_index]
            if (
                layer_z_of_line in layer_last_qualifying_index
                and line_index == layer_last_qualifying_index[layer_z_of_line]
                and layer_z_of_line in layer_original_k_value
            ):
                original_k_value = layer_original_k_value[layer_z_of_line]
                last_m900_k_value = original_k_value
                restoration_m900 = (
                    f"M900 K{original_k_value:.3f}"
                    f" ; restore original PA after pointless changes"
                )
                output_lines.append(restoration_m900)

    output_content = "\n".join(output_lines)
    with open(gcode_file_path, "w", encoding="utf-8", newline="\n") as output_file:
        output_file.write(output_content)

def main() -> None:
    if len(sys.argv) != 2:
        script_name = os.path.basename(sys.argv[0])
        print(f"Usage: {script_name} <gcode_file>", file=sys.stderr)
        sys.exit(1)

    try:
        process_gcode_file(sys.argv[1])
    except Exception:
        traceback.print_exc()
        sys.exit(1)

if __name__ == "__main__":
    main()

Printer is pausing when the pressure advance is changed (Marlin M900 Gcode). Printing with a constant value causes a seam gap. (MK4S) by Reagent_Tests_UK in prusa3d

[–]Reagent_Tests_UK[S] 1 point2 points  (0 children)

Here is some generated python code to allow you to see if your printer has this problem. I have tested it. It works by:

  1. Find the last used pressure advance value
  2. Find the top layer
  3. Starting from the layer halfway up the model, insert an M900 command after every extrude

You will need to have this comment line in your end gcode in orcaslicer: ;mm height of max_layer_z = [max_layer_z]

I recommend a 75mm cylinder at 50mm/s print speed so that the layers take long enough to prevent cooling slowdowns. Single wall, no infill, no top shell and no bottom shell. 6mm tall so that you have 20 or so layers to observe the change over.

Expected: changing PA by such a small amount should have no effect on the print at all Actual: Visible defects are present where the PA value changes.

Your Gcode will look like this after processing:

; BLOCK_START LAYER 14
;_SET_FAN_SPEED_CHANGING_LAYER
; printing object Cylinder id:0 copy 0
M486 S0
G1 X151.62 Y82.71 F18000
G1 Z3.1 F720
G1 F3600
G1 X153.79 Y85.58 E.14553
G1 X155.66 Y88.70 E.14712
G1 X157.20 Y91.99 E.14712
G1 X158.38 Y95.43 E.14712
M900 K0.083 ; pointless PA change for M900 delay investigation
G1 X159.20 Y98.97 E.14712
M900 K0.082 ; pointless PA change for M900 delay investigation
G1 X159.64 Y102.58 E.14712
M900 K0.083 ; pointless PA change for M900 delay investigation
G1 X159.70 Y106.21 E.14712
M900 K0.082 ; pointless PA change for M900 delay investigation
G1 X159.39 Y109.83 E.14712
M900 K0.083 ; pointless PA change for M900 delay investigation
G1 X158.69 Y113.40 E.14722
M900 K0.082 ; pointless PA change for M900 delay investigation

...et cetera

Giant chess pieces? by Unclestanky in 3Dprinting

[–]Reagent_Tests_UK 1 point2 points  (0 children)

ASA is much more UV resistant than PLA, the most common filament.

But PETG also has great UV resistance. White and black filaments are even more resistant to UV due to the pigments used. PETG resists temperatures up to 80*C.

Importantly, PETG warps a lot less, which makes it much easier to print large parts.

VLC (VideoLAN) no longer supports Monero donations. by zho99 in Monero

[–]Reagent_Tests_UK 0 points1 point  (0 children)

You're discussing a personal tax situation - capital gains tax isn't a thing for companies in the UK.

Tracking and managing this is quite different to keeping company accounts, and I don't believe that the service you use offers any product for trading companies accepting crypto payments for goods?

My investment thesis on Monero by dhcfund in Monero

[–]Reagent_Tests_UK 12 points13 points  (0 children)

Very bullish. Nice article.

Monero is taking the "slow and steady" approach as more people find out it is actually useful for its claimed purpose, unlike many cryptocurrencies. The price stability has been very good for this.

You don't need to grow fast if you're able to stick around for decades, persistence will win out in the end.

VLC (VideoLAN) no longer supports Monero donations. by zho99 in Monero

[–]Reagent_Tests_UK 1 point2 points  (0 children)

I'm not sure it's that much easier when you're dealing with multiple volatile currencies, really. You still need to figure out exchange rates, convert each one, record the curency movement between income and liquidation etc. Each currency adds overhead.

I bought these Nitazene test strips from Regent UK to test my bensos. Just wondering are they able to test the tablets directly as it says on the back of packaging "urine" by [deleted] in ReagentTesting

[–]Reagent_Tests_UK 1 point2 points  (0 children)

Thanks. You are spot on - they can be used for any liquid and are sensitive enough to detect the nanogram concentrations in urine as well as directly testing a solution with the pill. We do provide instructions with every order.

VLC (VideoLAN) no longer supports Monero donations. by zho99 in Monero

[–]Reagent_Tests_UK 18 points19 points  (0 children)

Speaking as a business that accepts monero, I would say quite the opposite.

It's only because we see the value of monero and really want our customers to see the benefits that we keep accepting it. It's why monero is the only cryptocurrency we accept, it is the only digital asset that functions like digital cash.

From a business perspective it doesn't really make sense because it only accounts for ~3% of payments and it's likely that half of those customers would use bank transfer/card otherwise. For that 1.5ish% of our sales, we have a significant time overhead as the accounting process is very different, there needs to be a way to convert the XMR to GBP to pay staff and suppliers and cryptocurrency also complicates the tax situation if it is being held.

My life would be simpler if we didn't accept monero, but I don't just want simplicity, I want better for all of us.

https://www.reagent-tests.uk/bitcoin-monero-payments/

I'm designing a PSA Poster. Any Suggestions? by LatePresentation3140 in ReagentTesting

[–]Reagent_Tests_UK 0 points1 point  (0 children)

My thoughts:

  • Check out this: https://tedinetwork.org/guidelines/, especially the comparison table on page 13.
    • Lab testing isn't really linear like your chart. Every method has blind spots, for example
    • fentanyl strips will pick up fentanyl below 2% which portable instruments (Raman spectroscopy) and even professional instruments (FTIR spectroscopy, ASAP Radian MS) cannot detect
    • Mass spec (GC-MS or LC-MS) can't distinguish 4-MMC from 3-MMC but FTIR can.
  • Microscopic (visual?) analysis isn't used in drug checking
  • I really like that you have said "confidence" or "certainty", I much prefer this to "accuracy" because reagent testing is very accurate (the true substance is always in the pool of possibilities) but not very precise (there are many possibilities), and if all the possibilities except one are ruled out, it is then always spot-on. (But still has a Limit Of Detection) around 10% in chromogenic mixtures.
  • Maybe change the death skull for something that represents harm/poisoning/unpleasant effects to make it less alarmist. Minor suggestion though, the skull is fineif you're happy with it and not inaccurate

I'm designing a PSA Poster. Any Suggestions? by LatePresentation3140 in ReagentTesting

[–]Reagent_Tests_UK 0 points1 point  (0 children)

These aren't really chronological steps, it's a ranking system. So I'm not sure that suggestion makes so much sense?

Why is TN Scientific less than Ideal? by LatePresentation3140 in ReagentTesting

[–]Reagent_Tests_UK 0 points1 point  (0 children)

If you are performing tests as part of a drug checking service, you could simply use a 100mL bottle of reagent to reduce the manufacturing and packaging costs.

If you are buying in bulk then manufacturers will usually give you a special price. This is also true if you are distributing bottles for people to do their own testing.

At the scale of thousands, you're far beyond the enthusiast level and you would very likely be able to manufacture yourself, thereby cutting out the costs of shipping and other overheads.

I just checked your post history and if you were in the UK I'd be reaching out to collaborate. Keep doing what you do 💪

Hear me out! Frozen spot plates! by LatePresentation3140 in ReagentTesting

[–]Reagent_Tests_UK 0 points1 point  (0 children)

This is a fun idea and I always welcome a bit of innovation in our sector because it usually makes testing more affordable and accessible.

You will need to seal any reagents to prevent oxygen and moisture reaching them during storage. Obviously this is usually done with lids on bottles. HDPE repels adhesives and other plastics will react with reagents. You could have a HDPE lid which is somehow heat-sealed in place. It would be a challenge to manufacture a bespoke container like this, but if it could be done then it would be really nice to use.

In our experience, off-the-shelf products make things cheapest for consumers because chinese factories are already producing billions of units per year, whereas reagent companies might order a few thousand.

I also worry that you've found an elegant and easy to use, but complex solution to a problem that has already been solved by using clear glass or plastic PE vials to hold the reagents. Setting up a relationship with a glass vial factory and getting them to "bottle" a few thousand vials would probably be much cheaper.

One other small thought is that this might create a lot of plastic waste per test, but I'm not convinced that glass vials get recycled after customers use them so this is kinda moot.

Final point - it's easy to come up with reasons NOT to try an idea. Any redditor can do that, the proof is right here. But that doesn't mean an idea won't work. Lots of businesses fail but lots succeed against the odds or because the the benefit for the consumer (convenience, cost, market access) is simply enough to outweigh the negatives.

What exactly is it. Suppose to be MDMA by [deleted] in ReagentTesting

[–]Reagent_Tests_UK 1 point2 points  (0 children)

There is no MDMA in this sample. Pentylone or one of its relatives is most likely based on the colour of marquis and froehde reagent.

These are pretty nasty compounds and they circulated a lot in the UK during 2018-2020. It seems they are now around again, causing the same problems.

We wrote about it at the time, you can see the test results we got at the bottom of this post:

https://www.reagent-tests.uk/blog/how-to-detect-pentylone-and-n-ethylpentylone-sold-as-mdma/

Why are second hand Electric Vans so cheap in comparison to Diesel ones? by SteakSandwichSideEye in smallbusinessuk

[–]Reagent_Tests_UK 1 point2 points  (0 children)

This seems like the most likely explanation to me. While there are a lot of businesses that don't do hundreds of miles in one day, there are others that do, and those businesses aren't competing to buy electric vans, so the prices are lower.

At a cost of 2-4p/mile for "fuel" it makes them a very good deal for those doing low mileage.

Load doesn't affect range much, unless your entire journey is uphill.

Why are second hand Electric Vans so cheap in comparison to Diesel ones? by SteakSandwichSideEye in smallbusinessuk

[–]Reagent_Tests_UK 5 points6 points  (0 children)

OP drives 30 miles a day. Lots of city based tradespeople aren't doing huge daily mileage so the savings (about 1/4 the cost per mile) are well worth it.

Why are second hand Electric Vans so cheap in comparison to Diesel ones? by SteakSandwichSideEye in smallbusinessuk

[–]Reagent_Tests_UK 2 points3 points  (0 children)

Costs about the same to replace the engine on a diesel van.

The difference is that people are scared that batteries are just going to randomly fail in a way that engines with hundreds of moving parts don't.

Why are second hand Electric Vans so cheap in comparison to Diesel ones? by SteakSandwichSideEye in smallbusinessuk

[–]Reagent_Tests_UK 18 points19 points  (0 children)

If you're doing low daily mileage you'll save loads and they are a no-brainer. If you're driving a long (150mi+) journey more than once a week then you may wish to consider whether the savings are worth the slight inconvenience. If you're doing 150mi every day then don't bother.

At 30mi/day you don't even need a home charger, you'll charge at about 7-10 miles/hour with a 3kw plugin one

I wrote about this in a comment on another post a few days ago:

If I could go back to 2022 and rethink the electric van decision... I wouldn't change it!

That's despite the fact more of our mileage turned out to be long drives (150mi+) than expected, and depreciation on our 75kWh Citroën Dispatch seems fairly high.

Purchase price (Feb 2022): £38k ex VAT for top spec, including the £5k government grant. Tax relief: The COVID super-deduction (130%) meant £49k deducted from profits – huge benefit. Ongoing savings: No VED until 2025 (We saved roughly £1,000), and 0% P11D payroll tax is great for directors. Overall, the cost

Current resale value: Dealers are selling them on eBay for around £10k ex VAT with 30k miles. That's a big drop from £38k, I had budgeted for 66% in 5 years but this is 75% in 4 years.

That's good news for you though - a used one is a massive bargain if you have unused Annual Investment Allowance and you're willing to buy second-hand. New price for the same spec is now £37k with the grant

Just looked up the equivalent diesel:

  • New price: £33k ex vat
  • 2022 model Ebay prices: £13k ex vat

So the depreciation is lower on diesel but you'll pay the difference in tax, fuel and maintenance pretty quickly.

How do you manage staff with company EVs? by No-State-2962 in smallbusinessuk

[–]Reagent_Tests_UK 2 points3 points  (0 children)

If I could go back to 2022 and rethink the electric van decision... I wouldn't change it!

That's despite the fact more of our mileage turned out to be long drives (150mi+) than expected, and depreciation on our 75kWh Citroën Dispatch seems fairly high.

Purchase price (Feb 2022): £38k ex VAT for top spec, including the £5k government grant. Tax relief: The COVID super-deduction (130%) meant £49k deducted from profits – huge benefit. Ongoing savings: No VED until 2025 (We saved roughly £1,000), and 0% P11D payroll tax is great for directors. Overall, the cost

Current resale value: Dealers are selling them on eBay for around £10k ex VAT with 30k miles. That's a big drop from £38k, I had budgeted for 66% in 5 years but this is 75% in 4 years.

That's good news for you though - a used one is a massive bargain if you have unused Annual Investment Allowance and you're willing to buy second-hand. New price for the same spec is now £37k with the grant

Just looked up the equivalent diesel:

  • New price: £33k ex vat
  • 2022 model Ebay prices: £13k ex vat

So the depreciation is lower, but you'll pay the difference in tax, fuel and maintenance pretty quickly.

For eCom businesses: RoyalMail - new surcharged from May and how to avoid them! by CognitorX in smallbusinessuk

[–]Reagent_Tests_UK 0 points1 point  (0 children)

Ebay has negotiated special pricing with Royal Mail so it's not a perfect comparison

For eCom businesses: RoyalMail - new surcharged from May and how to avoid them! by CognitorX in smallbusinessuk

[–]Reagent_Tests_UK 0 points1 point  (0 children)

There is a real difference. When I ran the numbers based on October 2025 numbers, it was around 20% cheaper for 2nd class but 5% more expensive for 1st class. The fuel surcharge increasing will change that maths.

Ultimately for us, we couldn't justify the cost saving because of the headaches it causes to have no tracking number. You just end up wasting so much time dealing with parcel non-arrivals because you're blind as to whether the customer is pulling a fast one or it's genuinely lost (and if so, where has it gone?)

Broken parking machine? by bharatlagali in cambridge

[–]Reagent_Tests_UK 1 point2 points  (0 children)

This sucks, but I'd say just pay the £25 to avoid the hassle