parsing – Python molar mass calculator

I created this code that takes a molecular formula, eg CH3COOH and calculates its molar mass.

#! /usr/bin/env python3
element_weights = {
    'H': 1.00794,
    'He': 4.002602,

    'Ts': 294.0,
    'Og': 294.0,

def tokenize(string):
    position = 0
    tokens = ()
    striter = iter(string)

    character = next(striter)

    while True:
            token = character

            if character in "()":
                character = next(striter)
            elif character.isnumeric():
                while (character := next(striter)).isnumeric():
                    token += character

            elif character.isupper():
                while (character := next(striter)).islower():
                    token += character
                raise ValueError("Can't parse")


        except StopIteration:
            return tokens

def get_composition(tokens_list):
    composition = {}

    tokens = iter(tokens_list)
    token = next(tokens)

    while True:
        if(token == "EOF"):

        num_parens = 0

        if token == "(":
            num_parens = 1
            substr_tokens = ()

            while num_parens > 0:
                token = next(tokens)

                if token == "EOF":
                    raise ValueError(f"Unbalanced Parens, tokens: {tokens_list}")
                elif token == "(":
                    num_parens += 1
                elif token == ")":
                    num_parens -= 1

                if (num_parens > 0):


            substr_composition = get_composition(substr_tokens)

            if (token := next(tokens)).isnumeric():
                substr_composition = {k: int(token) * v for k,v in substr_composition.items()}

            for k,v in substr_composition.items():
                if k in composition:
                    composition(k) += v
                    composition(k) = v

        if token == ")":
            raise ValueError(f"Unbalanced Parens, tokens: {tokens_list}")

        if token not in element_weights:
            raise ValueError(f"Can't find element {token}, tokens {tokens_list}")

        element = token

        if (token := next(tokens)).isnumeric():
            element_count = int(token)
            token = next(tokens)
            element_count = 1

        if element in composition:
            composition(element) += element_count
            composition(element) = element_count

    return composition
def convertToAMU(element_count):
    return sum(element_weights(k) * v for k,v in element_count.items())

if __name__ == "__main__":
    import sys

    if(len(sys.argv) > 1):
        print(f"Usage: {sys.argv(0)} (chemical_formula)")

Bound on probability mass of binomial distribution

Let $n$ be an integer and $pin (0, 1)$. I am looking for an upper bound on
$$max_{0leq ileq n} binom ni p^i(1-p)^{n-i}.$$
In other words, I want an upper bound on how much mass of a binomial distribution with parameters $n$ and $p$ can reside at any one point. By guessing that the maximum is obtained at $i=pn$ (which may be non-integer), Sterlings approximation yields an estimate of $O(1/sqrt{np(1-p)})$. I could probably formalise this. However, it does not feel like a very clean argument.

Is there a more elegant solution?

magento2 – Magento 2.3 On mass action how can I refresh listing grid using ajax (without page refresh)

As I see by default once magento2 mass action applied, default logic is to refresh the page. I would like to have grid refreshing without actual page reload but rather from js once massaction completed. I have successfully refershed grid once I add new item with my custom scripts using js, however I can’t find way easy way to call js for massaction and as far as I see for massaction magento2 just doing redirect to the actual controller page there action happen.

Here’s part of my listing grid for massdelete (working just fine but with page refresh)

            <action name="massdelete">
                <argument name="data" xsi:type="array">
                    <item name="config" xsi:type="array">
                        <item name="type" xsi:type="string">massdelete</item>
                        <item name="label" xsi:type="string" translate="true">Delete</item>                        
                        <item name="url" xsi:type="url" path="electroidlab/connect_ui/massDelete"/>                        
                        <item name="confirm" xsi:type="array">
                            <item name="title" xsi:type="string" translate="true">Attention</item>
                            <item name="message" xsi:type="string" translate="true">Are you sure want to delete?</item>

Here’s part of the controller with redirect. If I comment redirect part, then it will be just white page with controller path in url

                    public function execute()
                    $collection = $this->filter
                    $catRecordDeleted = 0;
                    foreach ($collection as $category) {
                        __("A total of %1 record(s) have been deleted.", $catRecordDeleted)
                    return $this->resultRedirectFactory->create()->setPath(
                        '_secure' => $this->getRequest()->isSecure()


Is there a way to make default massaction without actual page refresh? Thanks!

probability – Compute mass function of $U=X+2Y$

Let be $X$ and $Y$ random variables and let be the joint mass $f_{X,Y}(x,y)=frac{xy}{96}I_{R}(x,y)$
where $R:={(x,y):0<x<4,1<y<5}$. Let be $U:=X+2Y$, its mass function is
$$f_U(u)=P(Uleq u) = intint_{{(x,y):x+2yleq u}} f_{X,Y}(x,y) dxdy =$$
$$intint_{{(x,y):x+2yleq u}} cxyI_R(x,y) dxdy =intint_{{(x,y):x+2yleq u}cap R} cxy dxdy$$
If we draw ${(x,y):x+2yleq u}cap R$ we can see we have to considerate several cases.

One case is $2<u<6$.
$$f_U(u) = intint_{{(x,y):x+2yleq u}cap R} cxy dxdy = int_0^{u-2}int_1^{frac{u-x}{2}} cxy dxdy$$
Second case is $6<u<10$, in this case i think the integral is
$$int_0^4int_1^{frac{u-4}{2}}cxydydx + int_{0}^4int_{{frac{u-4}{2}}}^{frac{u-x}{2}}cxydydx = u^2/96 -u/18 +1/24$$
But the solution is $(3u-8)/144$. I dont know why my second integral is bad defined.

email – How to unsubscribe customers on mass / bulk in Magento 2.3

We have migrated from M1 to M2, and it appears on M1 we had customers “subscribed” in Magento admin but had subsequently unsubscribed in our email platform. Unfortunately, this had not synced back to Magento 1 and was one way. Therefore when moving to Magento 2, it began to re-subscribe customers that should be unsubscribed.

We have around 30k subscribers that need unsubscribing, which I can find in the newsletter_subscriber table and comparing to our email provider’s db.
However changing subscriber_status field in the db from 1 to 3 (subscribe to unsubscribe) does not appear to work, and I suspect a customer save also needs to happen, but not sure how to do this.

Any ideas, either to save all customers pragmatically, or to unsubscribe pragmatically?
I have a list of emails or subscriber_id’s and customer id’s

Unity – movement code overriding rigidbody mass?

whatever I set the objects mass at it still falls the same speed

That’s how gravity works. Gravity is a constant rate of acceleration and is not affected by mass. In real life, rate of descent may be slowed by air resistance.

I don’t fully understand what you’re trying to do with your movement code (move object relative to the camera?), but it doesn’t seem like the cleanest way to do what you want. Does the object fall as expected if you aren’t giving any horizontal or vertical input?

You might want to reorganize it like this:

float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");

// this code is to keep movement direction when switching to alternate camera
if (Input.GetButtonDown("Horizontal") || Input.GetButtonDown("Vertical")) {
    viewForward = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
    viewRight = Vector3.Scale(Camera.main.transform.right, new Vector3(1, 0, 1)).normalized;
    viewRight = new Vector3(viewForward.z, 0f, viewForward.x * -1f);

    moveDirection = v * viewForward + h * viewRight;
    if (moveDirection != {
        // moveDirection.y = rb.velocity <-- not working
        transform.position += moveDirection * Time.deltaTime * moveSpeed;
        transform.rotation = Quaternion.LookRotation(moveDirection);