问:
Good XSLT for Python - lxml struggles
I'm trying to transform XHTML to text using a user-defined XSLT, which is the following:

```<code><xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.w3.org/1999/xhtml">

<xsl:output method="text"/>

<xsl:template match="/html">
Reading document entitled <xsl:value-of select="head/title"/>.

The top menu for this site has the following options:
<xsl:for-each select="body//ul[@role='menubar']/li/a">
    <xsl:value-of select="."></xsl:value-of> <xsl:text>
</xsl:text>
</xsl:for-each>

Now let's read the main part of the page.
<xsl:for-each select="body//main[@class='container']//(h1 | h2 | h3 | h4 | p | ul/li/a)">
    <xsl:value-of select="normalize-space(.)"/><xsl:text>
</xsl:text><xsl:text>
</xsl:text>
</xsl:for-each>

The footer menu for this site has the following options:
<xsl:for-each select="body//footer[@id='wb-info']//ul/li/a">
    <xsl:value-of select="."></xsl:value-of> <xsl:text>
</xsl:text>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>
</code>```

When I test in http://xsltransform.net/, applying it a typical HTML, the output is as expected.

I test the same XSLT against the same XHTML using the following Python code:

```<code>import lxml.etree as ET

html = ET.parse("../fixed_html/about.html")
xslt = ET.parse("../templates/generic.xslt")
transform = ET.XSLT(xslt)
res = transform(html)
print(res)
</code>```

I get the following error:

lxml.etree.XSLTParseError: xsl:for-each : could not compile select expression 'body//main[@class='container']//(h1 | h2 | h3 | h4 | p | ul/li/a)'

My first thought is that lxml has limitations. It can't handle valid XSLT. I'm hoping that's not the case, and I just failed to setup the code correctly.

Any issues with the Python code? Can I process the XSLT above in Python some other way?

答:
Your stylesheet declares version="1.0" but the code itself requires an XSLT 2.0 processor:

The xpath-default-namespace attribute is an XSLT 2.0 feature;

In XPath 1.0 parentheses are allowed only in the first location step.

lxml uses the libxslt processor that only supports XSLT 1.0. You will need to rewrite your stylesheet for XSLT 1.0 or find a way to incorporate  an XSLT 2.0 or higher processor in your processing chain.

When I test in http://xsltransform.net/, applying it a typical HTML, the output is as expected.

Only when you select the Saxon 9.5.1 engine. With any other processor you will get an error.

Title: Good XSLT for Python - lxml struggles

Body:
I'm trying to transform XHTML to text using a user-defined XSLT, which is the following:

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://www.w3.org/1999/xhtml">

<xsl:output method="text"/>

<xsl:template match="/html">
Reading document entitled <xsl:value-of select="head/title"/>.

The top menu for this site has the following options:
<xsl:for-each select="body//ul[@role='menubar']/li/a">
    <xsl:value-of select="."></xsl:value-of> <xsl:text>
</xsl:text>
</xsl:for-each>

Now let's read the main part of the page.
<xsl:for-each select="body//main[@class='container']//(h1 | h2 | h3 | h4 | p | ul/li/a)">
    <xsl:value-of select="normalize-space(.)"/><xsl:text>
</xsl:text><xsl:text>
</xsl:text>
</xsl:for-each>

The footer menu for this site has the following options:
<xsl:for-each select="body//footer[@id='wb-info']//ul/li/a">
    <xsl:value-of select="."></xsl:value-of> <xsl:text>
</xsl:text>
</xsl:for-each>

</xsl:template>
</xsl:stylesheet>

When I test in http://xsltransform.net/, applying it a typical HTML, the output is as expected.

I test the same XSLT against the same XHTML using the following Python code:

import lxml.etree as ET

html = ET.parse("../fixed_html/about.html")
xslt = ET.parse("../templates/generic.xslt")
transform = ET.XSLT(xslt)
res = transform(html)
print(res)

I get the following error:

lxml.etree.XSLTParseError: xsl:for-each : could not compile select expression 'body//main[@class='container']//(h1 | h2 | h3 | h4 | p | ul/li/a)'

My first thought is that lxml has limitations. It can't handle valid XSLT. I'm hoping that's not the case, and I just failed to setup the code correctly.

Any issues with the Python code? Can I process the XSLT above in Python some other way?


来源: stackexchange

问:
Why does set state not work within a subscription to an observable?
The code below has a function displayQuotes, which imports an observable that "next" are quotes. With each new quote, I would like to update the state of the quotes using react hooks. I created a custom hook that takes in an observable, subscribes it, and with each new value, sets state. I am finding that, although I log all the new incoming quotes, it appears that my setState never gets called after the first time. Any suggestions as to why this behavior is happening?

code:

```<code>const UseCustomHookForObservable = (observable, setState) => {
  useEffect(() => {
    let subscription=observable.subscribe((value) => {
      setState(value);
    });

    return () => subscription.unsubscribe();
  }, [observable, setState]);
};

function DisplayQuotes() {
  const [storedQuotes, setQuotes] = useState({});
  UseCustomHookForObservable(SymbolsObservable, setQuotes);

  return (
    <div>
      <QuotesTable values={storedQuotes} />
    </div>
  );
}
</code>```

What is even stranger to me is that the following does work:

```<code>function DisplayQuotes() {
  return (
    <div>
      <RenderSubscribedValues
        observable={SymbolsObservable}
        component={QuotesTable}
      />
    </div>
  );

class RenderSubscribedValues extends React.Component {
  constructor(props) {
    super(props);
    this.observable = props.observable;
    this.component = props.component;
    this.state = { storedValues: {} };
  }
  componentDidMount() {
    this.subscription = this.observable.subscribe((value) =>
      this.setState({ storedValues: value })
    );
  }
  componentWillUnmount() {
    this.subscription.unsubscribe();
  }
  render() {
    const Component = this.component;
    return (
      <div>
        <Component values={this.state.storedValues} />
      </div>
    );
  }
}
}
</code>```

I had been under the impression that useEffect and its return statement are effectively the same thing as componentDidMount and componentWillUnmount?

答:
Sorry, this maybe late but it might help anyone end up here.

Change your 'setState(value);' to 'setState([...value]);' if it is an array, or 'setState({...value});' if it is an obj.

ContentLicense: CC BY-SA 4.0

Body:
The code below has a function displayQuotes, which imports an observable that "next" are quotes. With each new quote, I would like to update the state of the quotes using react hooks. I created a custom hook that takes in an observable, subscribes it, and with each new value, sets state. I am finding that, although I log all the new incoming quotes, it appears that my setState never gets called after the first time. Any suggestions as to why this behavior is happening?

code:

const UseCustomHookForObservable = (observable, setState) => {
  useEffect(() => {
    let subscription=observable.subscribe((value) => {
      setState(value);
    });

    return () => subscription.unsubscribe();
  }, [observable, setState]);
};

function DisplayQuotes() {
  const [storedQuotes, setQuotes] = useState({});
  UseCustomHookForObservable(SymbolsObservable, setQuotes);

  return (

      <QuotesTable values={storedQuotes} />

  );
}

What is even stranger to me is that the following does work:

function DisplayQuotes() {
  return (

      <RenderSubscribedValues
        observable={SymbolsObservable}
        component={QuotesTable}
      />

  );

class RenderSubscribedValues extends React.Component {
  constructor(props) {
    super(props);
    this.observable = props.observable;
    this.component = props.component;
    this.state = { storedValues: {} };
  }
  componentDidMount() {
    this.subscription = this.observable.subscribe((value) =>
      this.setState({ storedValues: value })
    );
  }
  componentWillUnmount() {
    this.subscription.unsubscribe();
  }
  render() {
    const Component = this.component;
    return (

        <Component values={this.state.storedValues} />

    );
  }
}
}

I had been under the impression that useEffect and its return statement are effectively the same thing as componentDidMount and componentWillUnmount?


问:
How do I add code outside the scope of Main when using C# 9 Top Level Statements?
My understanding is that it is similar to write code directly into the old "static void Main(string[] args)" without the need to display what's above.

However, I used to declare my variables in the class Program to have them accessible from other classes (apologies if not best practice, I learnt C# by myself and as long as it works, I'm happy with my code).
See example below:

```<code>using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace myNameSpace
{
    class Program
    {
        //variables declaration
        public static string abc = "abc";
        public static int xyz = 1;

        static void Main(string[] args)
        {
            //code goes here
        }
    }
}
</code>```

With C# 9, it seems I can only declare variables in the Main section, so how can I declare them to be able to access them from other classes?

答:
I don't think the currently-accepted answer is correct, if you toss a partial class signature in Program.cs you can most certainly add things like static-scoped fields and attributes:

```<code>var customAttributes = (CustomAttribute[])typeof(Program).GetCustomAttributes(typeof(CustomAttribute), true);
Console.WriteLine(customAttributes[0].SomePropery);
Console.WriteLine(MyField);

[Custom(SomePropery = "hello world")]
public partial class Program
{
    private const string MyField = "value";
}

class CustomAttribute : Attribute
{
    public string SomePropery { get; set; }
}

</code>```

The above code and nothing else in Program.cs will output:

```<code>/home/dongus/bazinga/bin/Debug/net6.0/bazinga
hello world
value

Process finished with exit code 0.
</code>```

I use this method to apply the [ExcludeFromCodeCoverage] attribute to my projects' Program.cs files

Body:
My understanding is that it is similar to write code directly into the old "static void Main(string[] args)" without the need to display what's above.

However, I used to declare my variables in the class Program to have them accessible from other classes (apologies if not best practice, I learnt C# by myself and as long as it works, I'm happy with my code).
See example below:

using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;

namespace myNameSpace
{
    class Program
    {
        //variables declaration
        public static string abc = "abc";
        public static int xyz = 1;

        static void Main(string[] args)
        {
            //code goes here
        }
    }
}

With C# 9, it seems I can only declare variables in the Main section, so how can I declare them to be able to access them from other classes?

Body:
I don't think the currently-accepted answer is correct, if you toss a partial class signature in Program.cs you can most certainly add things like static-scoped fields and attributes:

var customAttributes = (CustomAttribute[])typeof(Program).GetCustomAttributes(typeof(CustomAttribute), true);
Console.WriteLine(customAttributes[0].SomePropery);
Console.WriteLine(MyField);

[Custom(SomePropery = "hello world")]
public partial class Program
{
    private const string MyField = "value";
}

class CustomAttribute : Attribute
{
    public string SomePropery { get; set; }
}

The above code and nothing else in Program.cs will output:

/home/dongus/bazinga/bin/Debug/net6.0/bazinga
hello world
value

Process finished with exit code 0.

I use this method to apply the [ExcludeFromCodeCoverage] attribute to my projects' Program.cs files


问:
IndexError: list assignment index out of range for CNN program from scratch
I've been getting this error while the dimension of my array match the limits of my loop, what should I change.

this program is aimed to classify 32*32p black and white images using Neural Networks from scratch.

```<code>import numpy as np
import matplotlib.pyplot as plt
import pickle
from math import exp
from random import seed
from random import random

def unpickle(file):
    with open(file, 'rb') as fo:
        data = pickle.load(fo, encoding='bytes')
    return data

def load_data(data_dir, negatives=False):

    meta_data_dict = unpickle("batches.meta")
    data_label_names = meta_data_dict[b'label_names']
    data_label_names = np.array(data_label_names)

    # training data
    train_data = None
    train_filenames = []
    train_labels = []

    train_data_dict = unpickle("data_batch_1")
    train_data = train_data_dict[b'data']
    train_filenames += train_data_dict[b'filenames']
    train_labels += train_data_dict[b'labels']

    train_data = train_data.reshape((len(train_data), 1, 32, 32))
    if negatives:
        train_data = train_data.transpose(0, 2, 3, 1).astype(np.float32)
    else:
        train_data = np.rollaxis(train_data, 1, 4)
    train_filenames = np.array(train_filenames)
    train_labels = np.array(train_labels)

    return train_data, train_filenames, train_labels, data_label_names

data_dir = 'data-batches-py'
x_train, x_train_filenames, y_train_labels, y_label_names =load_cifar_10_data(data_dir)
print (x_train.shape)
print (len(x_train))

# Initialize a network
def initialize_network(n_hidden):
    network = list()
    hidden_layer = [{'weights':[random() for i in range(len(x_train) + 1)]} for i in range(n_hidden)]
    network.append(hidden_layer)
    output_layer = [{'weights':[random() for i in range(n_hidden +1)]} for i in range(10)]
    network.append(output_layer)
    return network

def sum(inputs):
    sum_row=[]
    for i in range(len(x_train)):
        for a in range(32):
            for b in range(32):
                sum_row[i]=0
                sum_row[i]+= inputs[i][a][b][1]
    return sum_row
# Calculate neuron activation for an input
def activate(weights, inputs):
    flattened= sum(inputs)
    activation = weights[-1]
    for i in range(len(weights)-1):
        activation += weights[i] * flattened[i]
    return activation

# Transfer neuron activation
def transfer(activation):
    return 1.0 / (1.0 + exp(-activation))

# Forward propagate input to a network output
def forward_propagate(network, row):
    inputs = row
    for layer in network:
        new_inputs = []
        for neuron in layer:
            activation = activate(neuron['weights'], inputs)
            neuron['output'] = transfer(activation)
            new_inputs.append(neuron['output'])
        inputs = new_inputs
    return inputs

network = initialize_network(1)
row = x_train
output = forward_propagate(network, row)
print(output)
</code>```

After running this code I get the following output

```<code>(10000, 32, 32, 1)
10000
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in <module>
    153 network = initialize_network(1)
    154 row = x_train
--> 155 output = forward_propagate(network, row)
    156 print(output)

/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in forward_propagate(network, row)
     78                 new_inputs = []
     79                 for neuron in layer:
---> 80                         activation = activate(neuron['weights'], inputs)
     81                         neuron['output'] = transfer(activation)
     82                         new_inputs.append(neuron['output'])

/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in activate(weights, inputs)
     62 # Calculate neuron activation for an input
     63 def activate(weights, inputs):
---> 64     flattened= sum(inputs)
     65     activation = weights[-1]
     66     for i in range(len(weights)-1):

/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in sum(inputs)
     57         for a in range(32):
     58             for b in range(32):
---> 59                 sum_row[i]=0
     60                 sum_row[i]+= inputs[i][a][b][1]
     61     return sum_row

IndexError: list assignment index out of range
</code>```

as you can see the dimension of the input is 100003232*1, then why am I getting an error?

答:
The error is in

```<code>def sum(inputs):
    sum_row=[]
    for i in range(len(x_train)):
        for a in range(32):
            for b in range(32):
                sum_row[i]=0
                sum_row[i]+= inputs[i][a][b][1]
    return sum_row
</code>```

The reason for the error is that you are trying to access an element of sum_row, but sum_row doesn't have any element in it (as you set it to [] before the for loops). Inside the for loops, you try to access members which it doesn't have. Instead of doing sum_row[i] = 0 you should be doing sum_row.append(0) which adds an element to that list. Then you can access it via  sum_row[-1] += inputs[i][a][b][1]

Body:
I've been getting this error while the dimension of my array match the limits of my loop, what should I change.

this program is aimed to classify 32*32p black and white images using Neural Networks from scratch.

import numpy as np
import matplotlib.pyplot as plt
import pickle
from math import exp
from random import seed
from random import random

def unpickle(file):
    with open(file, 'rb') as fo:
        data = pickle.load(fo, encoding='bytes')
    return data

def load_data(data_dir, negatives=False):

    meta_data_dict = unpickle("batches.meta")
    data_label_names = meta_data_dict[b'label_names']
    data_label_names = np.array(data_label_names)

    # training data
    train_data = None
    train_filenames = []
    train_labels = []

    train_data_dict = unpickle("data_batch_1")
    train_data = train_data_dict[b'data']
    train_filenames += train_data_dict[b'filenames']
    train_labels += train_data_dict[b'labels']

    train_data = train_data.reshape((len(train_data), 1, 32, 32))
    if negatives:
        train_data = train_data.transpose(0, 2, 3, 1).astype(np.float32)
    else:
        train_data = np.rollaxis(train_data, 1, 4)
    train_filenames = np.array(train_filenames)
    train_labels = np.array(train_labels)

    return train_data, train_filenames, train_labels, data_label_names

data_dir = 'data-batches-py'
x_train, x_train_filenames, y_train_labels, y_label_names =load_cifar_10_data(data_dir)
print (x_train.shape)
print (len(x_train))

# Initialize a network
def initialize_network(n_hidden):
    network = list()
    hidden_layer = [{'weights':[random() for i in range(len(x_train) + 1)]} for i in range(n_hidden)]
    network.append(hidden_layer)
    output_layer = [{'weights':[random() for i in range(n_hidden +1)]} for i in range(10)]
    network.append(output_layer)
    return network

def sum(inputs):
    sum_row=[]
    for i in range(len(x_train)):
        for a in range(32):
            for b in range(32):
                sum_row[i]=0
                sum_row[i]+= inputs[i][a][b][1]
    return sum_row
# Calculate neuron activation for an input
def activate(weights, inputs):
    flattened= sum(inputs)
    activation = weights[-1]
    for i in range(len(weights)-1):
        activation += weights[i] * flattened[i]
    return activation

# Transfer neuron activation
def transfer(activation):
    return 1.0 / (1.0 + exp(-activation))

# Forward propagate input to a network output
def forward_propagate(network, row):
    inputs = row
    for layer in network:
        new_inputs = []
        for neuron in layer:
            activation = activate(neuron['weights'], inputs)
            neuron['output'] = transfer(activation)
            new_inputs.append(neuron['output'])
        inputs = new_inputs
    return inputs

network = initialize_network(1)
row = x_train
output = forward_propagate(network, row)
print(output)

After running this code I get the following output

(10000, 32, 32, 1)
10000
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in <module>
    153 network = initialize_network(1)
    154 row = x_train
--> 155 output = forward_propagate(network, row)
    156 print(output)

/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in forward_propagate(network, row)
     78                 new_inputs = []
     79                 for neuron in layer:
---> 80                         activation = activate(neuron['weights'], inputs)
     81                         neuron['output'] = transfer(activation)
     82                         new_inputs.append(neuron['output'])

/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in activate(weights, inputs)
     62 # Calculate neuron activation for an input
     63 def activate(weights, inputs):
---> 64     flattened= sum(inputs)
     65     activation = weights[-1]
     66     for i in range(len(weights)-1):

/var/folders/gm/z9_jyr1s5k1232zgf4xf7cxc0000gn/T/ipykernel_15670/2752672525.py in sum(inputs)
     57         for a in range(32):
     58             for b in range(32):
---> 59                 sum_row[i]=0
     60                 sum_row[i]+= inputs[i][a][b][1]
     61     return sum_row

IndexError: list assignment index out of range

as you can see the dimension of the input is 100003232*1, then why am I getting an error?

Body:
The error is in

def sum(inputs):
    sum_row=[]
    for i in range(len(x_train)):
        for a in range(32):
            for b in range(32):
                sum_row[i]=0
                sum_row[i]+= inputs[i][a][b][1]
    return sum_row

The reason for the error is that you are trying to access an element of sum_row, but sum_row doesn't have any element in it (as you set it to [] before the for loops). Inside the for loops, you try to access members which it doesn't have. Instead of doing sum_row[i] = 0 you should be doing sum_row.append(0) which adds an element to that list. Then you can access it via  sum_row[-1] += inputs[i][a][b][1]


问:
can i write to file in k6 load testing framework?
I am using k6 for our performance test suite.I want to write into file if response code in not equal to 200. Is there anyway to write in file in default method or out side of it?</p>

答: You can use an extension like xk6-file as mentioned on k6 extensions doc.</p>


问:
How to split into new column via multi-column layout only when text is overflowing
I'm looking for a way to dynamically break a continuous text into multiple columns only if the content of the first column is overflowing. It should be responsive and work for any device width. The solution can be (S)css or JavaScript.

I already tried using column-count like suggested here but this always creates multiple columns no matter if there is still enough space in the first column.

This is about what I want to achieve just without the mentioned column-count

.content {
  height: 90vh;
}

.text {
  width: 300px;
  column-count: 2;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code> <div class="content">
   <div class="text">
      Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus. Cras ultricies ligula sed magna dictum porta. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui. Nulla porttitor accumsan tincidunt. Lorem ipsum dolor sit amet,
      consectetur adipiscing elit. Pellentesque in ipsum id orci porta dapibus. Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a. Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus.
   </div>
 </div></code>```

答:
You need to set height to .text so it would know when to move to the next column:

.content {
  height: 90vh;
}

.text {
  height:100%;
  width: 300px;
  column-count: 1;
}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div class="content">
   <div class="text">
      Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus. Cras ultricies ligula sed magna dictum porta. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui. Nulla porttitor accumsan tincidunt. Lorem ipsum dolor sit amet,
      consectetur adipiscing elit. Pellentesque in ipsum id orci porta dapibus. Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a. Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus.
   </div>
 </div></code>```

Body:
I'm looking for a way to dynamically break a continuous text into multiple columns only if the content of the first column is overflowing. It should be responsive and work for any device width. The solution can be (S)css or JavaScript.

I already tried using column-count like suggested here but this always creates multiple columns no matter if there is still enough space in the first column.

This is about what I want to achieve just without the mentioned column-count

.content {
  height: 90vh;
}

.text {
  width: 300px;
  column-count: 2;
}

      Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus. Cras ultricies ligula sed magna dictum porta. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui. Nulla porttitor accumsan tincidunt. Lorem ipsum dolor sit amet,
      consectetur adipiscing elit. Pellentesque in ipsum id orci porta dapibus. Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a. Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus.

Body:
You need to set height to .text so it would know when to move to the next column:

.content {
  height: 90vh;
}

.text {
  height:100%;
  width: 300px;
  column-count: 1;
}

<div class="content">
   <div class="text">
      Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus. Cras ultricies ligula sed magna dictum porta. Vestibulum ac diam sit amet quam vehicula elementum sed sit amet dui. Nulla porttitor accumsan tincidunt. Lorem ipsum dolor sit amet,
      consectetur adipiscing elit. Pellentesque in ipsum id orci porta dapibus. Mauris blandit aliquet elit, eget tincidunt nibh pulvinar a. Vivamus magna justo, lacinia eget consectetur sed, convallis at tellus.
   </div>
 </div>


问:
Axios.put only updates some fields, not all
I followed this tutorial that uses nodejs, mysql2, express, vuejs:

https://mfikri.com/en/blog/nodejs-express-mysql-vue

but I used my own database and tables.

My problem is that when I send an axios.put request, the database will only update for some fields, not all.

My users table in the database was built with:

```<code>CREATE TABLE users(
userid INT(11) PRIMARY KEY AUTO_INCREMENT NOT NULL,
email VARCHAR(255),
password VARCHAR(45) NOT NULL,
role INT(11),
emailconfirmed TINYINT(1),
TIER INT(11)
)ENGINE=INNODB;
</code>```

This database is living in a Heroku ClearDB Resource

My api in my Express backend looks like:

```<code>await axios.put(
          `http://localhost:5000/users/${this.$route.params.id}`,
          {
            email: this.userEmail,
            role: this.userRole,
            emailconfirmed: this.userEmailConfirmed,
            tier: this.userTier,
          }
        );
</code>```

When I send my request either through POSTMAN or vuejs, I can update role or tier without any issue, but when I try to change email or emailconfirmed, I get:

affectedRows: 1
changedRows:0

I don't get it and I can't find anything to help answer the question.

Please help me.

答:
I didn't check my model files in the Backend. I didn't fully set them up to update all the fields.

My code looked like:

```<code>// Update User to Database
export const updateUserById = (data, id, result) => {
    db.query("UPDATE users SET role = ?, tier = ? WHERE userid = ?", [data.role, data.tier, id], (err, results) => {
        if(err) {
            console.log(err);
            result(err, null);
        } else {
            result(null, results);
        }
    });
}
</code>```

So to fix it, obviously I need to add email and emailconfirmed to the SET expression.

Rookie mistake.

Thanks @hamid-davodi

Body:
I followed this tutorial that uses nodejs, mysql2, express, vuejs:

https://mfikri.com/en/blog/nodejs-express-mysql-vue

but I used my own database and tables.

My problem is that when I send an axios.put request, the database will only update for some fields, not all.

My users table in the database was built with:

CREATE TABLE users(
userid INT(11) PRIMARY KEY AUTO_INCREMENT NOT NULL,
email VARCHAR(255),
password VARCHAR(45) NOT NULL,
role INT(11),
emailconfirmed TINYINT(1),
TIER INT(11)
)ENGINE=INNODB;

This database is living in a Heroku ClearDB Resource

My api in my Express backend looks like:

await axios.put(
          `http://localhost:5000/users/${this.$route.params.id}`,
          {
            email: this.userEmail,
            role: this.userRole,
            emailconfirmed: this.userEmailConfirmed,
            tier: this.userTier,
          }
        );

When I send my request either through POSTMAN or vuejs, I can update role or tier without any issue, but when I try to change email or emailconfirmed, I get:

affectedRows: 1
changedRows:0

I don't get it and I can't find anything to help answer the question.

Please help me.

Body:
I didn't check my model files in the Backend. I didn't fully set them up to update all the fields.

My code looked like:

// Update User to Database
export const updateUserById = (data, id, result) => {
    db.query("UPDATE users SET role = ?, tier = ? WHERE userid = ?", [data.role, data.tier, id], (err, results) => {
        if(err) {
            console.log(err);
            result(err, null);
        } else {
            result(null, results);
        }
    });
}

So to fix it, obviously I need to add email and emailconfirmed to the SET expression.

Rookie mistake.

Thanks @hamid-davodi


问:
How can I divide a text row in a data frame into several rows, but still have the new rows connected to the same ID (Python)?
I have a meeting minutes data set. I have made a dataframe, and I would like to split the text, which is a speech, and each speech has several paragraphs. The length of each speech varies from speech to speech. I want the text data to be divided into paragraphs so I can analyze each paragraph instead of the whole speech. However, I want the text unit (paragraph) to keep the document id, and get a new text unit id. The text unit id would refer to number of paragraph in the speech.

This is how it looks like now:

row number
text_unit_id
doc_id
text

1
1
3000_speech_1
Bla bla bla (new line) Bla bla bla (new line) Bla bla bla

2
1
3000_speech_2
Bla bla bla (new line) Bla bla bla

I want to be like this:

row_number
text_unit_id
doc_id
text

1
1
3000_speech_1
Bla bla bla

2
2
3000_speech_1
Bla bla bla

3
3
3000_speech_1
Bla bla bla

4
1
3000_speech_2
Bla bla bla

5
2
3000_speech_2
Bla bla bla

答:
You can split the lines using .str.split("\n"), then massage the DataFrame a bit using melt, and finally merge the lines and the initial DataFrame to keep your metadata, maybe like:

import pandas as pd

df = pd.DataFrame(
    [
        {
            "doc_id": "3000_speech_1",
            "text": "Speech 1 head\nSpeech 1 body\nSpeech 1 tail",
        },
        {
            "doc_id": "3000_speech_2",
            "text": "Speech 2 head\nSpeech 2 tail",
        },
    ]
)

print(df)

lines = (
    df.text.str.split("\n")
    .apply(pd.Series)
    .melt(ignore_index=False, value_name="line", var_name="text_unit_id")
    .dropna()
)

del df["text"]
print(df.merge(lines, left_index=True, right_index=True))

```
<p>Which transforms:</p>
```          doc_id                                         text
0  3000_speech_1  Speech 1 head\nSpeech 1 body\nSpeech 1 tail
1  3000_speech_2                 Speech 2 head\nSpeech 2 tail
```
<p>to</p>
```          doc_id  text_unit_id           line
0  3000_speech_1             0  Speech 1 head
0  3000_speech_1             1  Speech 1 body
0  3000_speech_1             2  Speech 1 tail
1  3000_speech_2             0  Speech 2 head
1  3000_speech_2             1  Speech 2 tail
```

Body:
You can split the lines using .str.split("\n"), then massage the DataFrame a bit using melt, and finally merge the lines and the initial DataFrame to keep your metadata, maybe like:

import pandas as pd

df = pd.DataFrame(
    [
        {
            "doc_id": "3000_speech_1",
            "text": "Speech 1 head\nSpeech 1 body\nSpeech 1 tail",
        },
        {
            "doc_id": "3000_speech_2",
            "text": "Speech 2 head\nSpeech 2 tail",
        },
    ]
)

print(df)

lines = (
    df.text.str.split("\n")
    .apply(pd.Series)
    .melt(ignore_index=False, value_name="line", var_name="text_unit_id")
    .dropna()
)

del df["text"]
print(df.merge(lines, left_index=True, right_index=True))

Which transforms:

          doc_id                                         text
0  3000_speech_1  Speech 1 head\nSpeech 1 body\nSpeech 1 tail
1  3000_speech_2                 Speech 2 head\nSpeech 2 tail

to

          doc_id  text_unit_id           line
0  3000_speech_1             0  Speech 1 head
0  3000_speech_1             1  Speech 1 body
0  3000_speech_1             2  Speech 1 tail
1  3000_speech_2             0  Speech 2 head
1  3000_speech_2             1  Speech 2 tail


问:
Expo Publish Equivalent for EAS Expo Application Service
I have just migrated my project from expo classic to eas via documentation provided by expo.

Now, I need to update the App over the air which was previously possible with "expo publish" command.

This is the error message I get when I use "expo publish" after migration -

```<code>> expo publish
It seems like your project is configured for EAS Update. Please use 'eas branch:publish' instead.
</code>```

Further on running "eas branch:publish" it return another error message -

```<code>> eas branch:publish
Error: deprecated, use "eas update"
</code>```

Finally, after executing "eas update" it gave another error -

```<code>✔ Please enter an update message. … minor ui fixes
✔ Built bundle!
✔ Uploaded assets!
✖ Failed to published updates
CombinedError: [GraphQL] EAS Update is not yet publicly available.
</code>```

Is there any way to publish updates over the air with eas just like "expo publish" ?

答:
Got the same issue after some research, it seems we've both been locked behind a paywall.
According to this update post in December 2020.

EAS Update preview is available to EAS Production plan subscribers (up
to 100,000 updates/mo) and EAS Enterprise plan subscribers (up to
1,000,000 updates/mo). In 2022, EAS Update will be publicly
available with a free tier.

A more recent update with new EAS features in April 2021 re-iterates

As a reminder, previews of EAS Build and Submit are available to
developers subscribed to the EAS Priority Plan, and they won’t be
available on a free tier until they graduate from preview

https://expo.dev/pricing

EAS plan pricing tiers

Free tier doesn't include Preview EAS Update.

Body:
I have just migrated my project from expo classic to eas via documentation provided by expo.

Now, I need to update the App over the air which was previously possible with "expo publish" command.

This is the error message I get when I use "expo publish" after migration -

> expo publish
It seems like your project is configured for EAS Update. Please use 'eas branch:publish' instead.

Further on running "eas branch:publish" it return another error message -

> eas branch:publish
Error: deprecated, use "eas update"

Finally, after executing "eas update" it gave another error -

✔ Please enter an update message. … minor ui fixes
✔ Built bundle!
✔ Uploaded assets!
✖ Failed to published updates
CombinedError: [GraphQL] EAS Update is not yet publicly available.

Is there any way to publish updates over the air with eas just like "expo publish" ?


问:
PYTHON: How to take a .txt file as input from user using raw_input in Python and then read that file row wise?
I want to take a .txt file as input from user through raw_input.

Once the input is taken, I want the txt file name given by user to be accessed and the contents from it written into another file (each in next row).

I am having a problem with how to connect a and b above or how to link raw input with reading of file. I need help...the code is as follows (but it is erroneous :S).

```<code>import sys,os,csv

x = raw_input("Enter name of file to be written row wise:")
ui = "x" + txt
for ui in x:
    data = open("ui").readlines()
    outfile = open("myfile.csv","w")
    out = csv.writer(outfile)
for row in data:
    row = row.strip().split(';')
    if row:
        for subrow in row:
            subrow = subrow.strip().split()
            if subrow:
                out.writerow(subrow)
outfile.close()
</code>```

I get the error:

cannot concatenate 'str' and 'list' objects

答:
```<code>for row in data:
    row = row.strip().split(';')
</code>```

The fact that you perform split(';') has for consequence that a row (you should write: line) split according to ';' gives always a not empty list, even if it is an empty line, and even after having been stripped with strip() : ''.split(';') gives [''] . So your following condition if row: is useless.

That means that your code is equivalent to:

```<code>for row in data:
    row = row.strip().split(';')
    for subrow in row:
        subrow = subrow.split()
        if subrow:
            out.writerow(subrow)
</code>```

and then to:

```<code>for row in data:
    for subrow in  row.strip().split(';'):
        subrow = subrow.split()
        if subrow:
            out.writerow(subrow)
</code>```

.

Moreover , the fact that you use split() on subrow present in the list row.strip().split(';') eliminates all the blanks before and after each of the words present in subrow. So the first strip() in row.strip().split(';') is useless too.

Your code is then equivalent to:

```<code>for row in data:
    for subrow in row.split(';'):
        subrow = subrow.split()
        if subrow:
            out.writerow(subrow)
</code>```

Now , subrow.split() can produce a void list when subrow is only blanks, because split() without argument has its special algorithm. So the instruction if subrow is usefull.

.

In fact, what your code does is, after having read the content of such a file:

```<code>Blackcurrant, Redcurrant   ;  Orange ; Blueberry
    Pear;Chestnut;     Lemon Lime, Grapefruit
Apple;Apricot   ;  Pineapple, Fig; Mulberry, Hedge Apple
</code>```

to record another file like that:

```<code>Blackcurrant
Redcurrant
Orange
Blueberry
Pear
Chestnut
Lemon Lime
Grapefruit
Apple
Apricot
Pineapple
Fig
Mulberry
Hedge
Apple
</code>```

I prefer the following code to do that:

```<code>filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

with open(filepath) as handler,open("myfile.csv","wb") as outfile:
    out = csv.writer(outfile)
    for row in handler:
        gen = ( subrow.split() for subrow in row.split(';') )
        out.writerow([x for x in gen if x])
    del out
</code>```

.

This code will always run, even for files extremely huge whose content can't be held by the memory, because the lines of the file are read one after the other.

In case the file isn't enormous like that, it is possible to proceed like you did, with readlines():

```<code>with open(filepath) as handler:
    data = handler.readlines()

with open("myfile.csv","wb") as outfile:
    out = csv.writer(outfile)
    for row in data:
        gen = ( subrow.split() for subrow in row.split(';') )
        out.writerow([x for x in gen if x])
    del out
</code>```

But there is no particular interest to proceed so, you can do for row in handler as well.

.

Personnaly, I think it would be better to use writerows():

```<code>filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

with open(filepath) as handler,open("myfile.csv","wb") as outfile:
    out = csv.writer(outfile)
    gen = ( x for row in handler for x in (subrow.split() for subrow in row.split(';')) )
    out.writerows([x for x in gen if])
    del out
</code>```

.

I end this answer by informing you that a code employing a regex would be far more efficient:

```<code>import csv, re

regx = re.compile('[ ;\r\n]+')

filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

with open(filepath) as handler,open("myfile.txt","w") as outfile:
    outfile.write('\n'.join(x for x in regx.split(handler.read()) if x))
</code>```

Edit 1

```<code>handler = open(filepath)
outfile = open("myfile.txt","wb")
out = csv.writer(outfile)
for row in handler:
    gen = ( subrow.split() for subrow in row.split(';') )
    out.writerow([x for x in gen if x])
del out
outfile.close()
handler.close()
</code>```

or

```<code>import csv, re
regx = re.compile('[ ;\r\n]+')
filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

handler = open(filepath)
outfile = open("myfile.txt","w")
outfile.write('\n'.join(x for x in regx.split(handler.read()) if x))
outfile.close()
handler.close()
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I want to take a .txt file as input from user through raw_input.

Once the input is taken, I want the txt file name given by user to be accessed and the contents from it written into another file (each in next row).

I am having a problem with how to connect a and b above or how to link raw input with reading of file. I need help...the code is as follows (but it is erroneous :S).

import sys,os,csv

x = raw_input("Enter name of file to be written row wise:")
ui = "x" + txt
for ui in x:
    data = open("ui").readlines()
    outfile = open("myfile.csv","w")
    out = csv.writer(outfile)
for row in data:
    row = row.strip().split(';')
    if row:
        for subrow in row:
            subrow = subrow.strip().split()
            if subrow:
                out.writerow(subrow)
outfile.close()

I get the error:

cannot concatenate 'str' and 'list' objects

Body:
for row in data:
    row = row.strip().split(';')

The fact that you perform split(';') has for consequence that a row (you should write: line) split according to ';' gives always a not empty list, even if it is an empty line, and even after having been stripped with strip() : ''.split(';') gives [''] . So your following condition if row: is useless.

That means that your code is equivalent to:

for row in data:
    row = row.strip().split(';')
    for subrow in row:
        subrow = subrow.split()
        if subrow:
            out.writerow(subrow)

and then to:

for row in data:
    for subrow in  row.strip().split(';'):
        subrow = subrow.split()
        if subrow:
            out.writerow(subrow)

.

Moreover , the fact that you use split() on subrow present in the list row.strip().split(';') eliminates all the blanks before and after each of the words present in subrow. So the first strip() in row.strip().split(';') is useless too.

Your code is then equivalent to:

for row in data:
    for subrow in row.split(';'):
        subrow = subrow.split()
        if subrow:
            out.writerow(subrow)

Now , subrow.split() can produce a void list when subrow is only blanks, because split() without argument has its special algorithm. So the instruction if subrow is usefull.

.

In fact, what your code does is, after having read the content of such a file:

Blackcurrant, Redcurrant   ;  Orange ; Blueberry
    Pear;Chestnut;     Lemon Lime, Grapefruit
Apple;Apricot   ;  Pineapple, Fig; Mulberry, Hedge Apple

to record another file like that:

Blackcurrant
Redcurrant
Orange
Blueberry
Pear
Chestnut
Lemon Lime
Grapefruit
Apple
Apricot
Pineapple
Fig
Mulberry
Hedge
Apple

I prefer the following code to do that:

filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

with open(filepath) as handler,open("myfile.csv","wb") as outfile:
    out = csv.writer(outfile)
    for row in handler:
        gen = ( subrow.split() for subrow in row.split(';') )
        out.writerow([x for x in gen if x])
    del out

.

This code will always run, even for files extremely huge whose content can't be held by the memory, because the lines of the file are read one after the other.

In case the file isn't enormous like that, it is possible to proceed like you did, with readlines():

with open(filepath) as handler:
    data = handler.readlines()

with open("myfile.csv","wb") as outfile:
    out = csv.writer(outfile)
    for row in data:
        gen = ( subrow.split() for subrow in row.split(';') )
        out.writerow([x for x in gen if x])
    del out

But there is no particular interest to proceed so, you can do for row in handler as well.

.

Personnaly, I think it would be better to use writerows():

filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

with open(filepath) as handler,open("myfile.csv","wb") as outfile:
    out = csv.writer(outfile)
    gen = ( x for row in handler for x in (subrow.split() for subrow in row.split(';')) )
    out.writerows([x for x in gen if])
    del out

.

I end this answer by informing you that a code employing a regex would be far more efficient:

import csv, re

regx = re.compile('[ ;\r\n]+')

filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

with open(filepath) as handler,open("myfile.txt","w") as outfile:
    outfile.write('\n'.join(x for x in regx.split(handler.read()) if x))

Edit 1

handler = open(filepath)
outfile = open("myfile.txt","wb")
out = csv.writer(outfile)
for row in handler:
    gen = ( subrow.split() for subrow in row.split(';') )
    out.writerow([x for x in gen if x])
del out
outfile.close()
handler.close()

or

import csv, re
regx = re.compile('[ ;\r\n]+')
filename = raw_input("Enter name of file to be written row wise:") + '.txt'
filepath = 'I:\\' + filename

handler = open(filepath)
outfile = open("myfile.txt","w")
outfile.write('\n'.join(x for x in regx.split(handler.read()) if x))
outfile.close()
handler.close()


问:
Parse Json with Python where a single object contains 200 objects, and I want to operate on each object individually
So I have an object I imported into a dict.

```<code>{"results":[
{"Name":"fed-sv01","NodeID":118,"XID":"37be","RowID":"2","Vendor":"Wnet","Status":"0"},
{"Name":"Joe-sv02","NodeID":119,"XID":"ab39","RowID":"2","Vendor":"Wnet","Status":"92"},
...
{"Name":"May-sv01","NodeID":703,"XID":"zc93","RowID":"2","Vendor":"Wnet","Status":"4"}]}
</code>```

I show 3 lines, but there are around 200 similar lines.

So "results":[] is a top level container that simply encapsulated the set of objects.

What I want to do is iterate through the nested objects:

```<code>{"Name":"fed-sv01","NodeID":118,"XID":"37be","RowID":"2","Vendor":"Wnet","Status":"0"}
</code>```

And build a different json object:

```<code>{"Name":"fred-sv01","Status":"0"}
</code>```

That I will then push out to another system set up to catch these objects.  I have the code for that, what I'm trying to do is peel the json objects from inside results[] one at a time, and I'm not finding any examples of how to do that.  I could just run a command on the json to remove the results[] wrapper, but that seems silly if all I have to do is deal with results[] inside the scripts that do the iteration.

I want to read a line, create a new object, ship the object off. Rinse & repeat until iterated through all 200 objects.  We could pop them off as we iterate if that makes it easier, but I'm not sure it does.  The original object is ephemeral, so it can be destroyed.

Does anyone have some example code showing how to parse json in a results[] object with python?

The comments are helping, this is what I have now:

```<code>import json

with open('json.results') as json_file:
    data = json.load(json_file)

    for row in data['results']:
            print(row)  #good so far

            node = {row('Name'), row('Status')}
            for item in node():
                print(item) #blows up with "TypeError: 'dict' object is not callable"
</code>```

答:
Ok, I have the code I need now.  Thanks to Barmar and Hiero De Paula, they both contributed to my effort.

```<code>#!/usr/bin/env python3
import json

with open('json.to.import') as json_file:
    data = json.load(json_file)

    for i in data['results']:
            print(i)  #good so far
            print(type(i))

            node = {}
            node['Name'] = i['Name']
            node['Status'] = i['Status']

            print(type(node))
            print(node)
            print("Name ",  node['Name'])
            print("Status ",  node['Status'])
</code>```

From this point I add a couple fields to the dict node, and then execute the push into the other system, but the print statements confirm I have accomplished whet I needed help with.

Body:
So I have an object I imported into a dict.

{"results":[
{"Name":"fed-sv01","NodeID":118,"XID":"37be","RowID":"2","Vendor":"Wnet","Status":"0"},
{"Name":"Joe-sv02","NodeID":119,"XID":"ab39","RowID":"2","Vendor":"Wnet","Status":"92"},
...
{"Name":"May-sv01","NodeID":703,"XID":"zc93","RowID":"2","Vendor":"Wnet","Status":"4"}]}

I show 3 lines, but there are around 200 similar lines.

So "results":[] is a top level container that simply encapsulated the set of objects.

What I want to do is iterate through the nested objects:

{"Name":"fed-sv01","NodeID":118,"XID":"37be","RowID":"2","Vendor":"Wnet","Status":"0"}

And build a different json object:

{"Name":"fred-sv01","Status":"0"}

That I will then push out to another system set up to catch these objects.  I have the code for that, what I'm trying to do is peel the json objects from inside results[] one at a time, and I'm not finding any examples of how to do that.  I could just run a command on the json to remove the results[] wrapper, but that seems silly if all I have to do is deal with results[] inside the scripts that do the iteration.

I want to read a line, create a new object, ship the object off. Rinse & repeat until iterated through all 200 objects.  We could pop them off as we iterate if that makes it easier, but I'm not sure it does.  The original object is ephemeral, so it can be destroyed.

Does anyone have some example code showing how to parse json in a results[] object with python?

The comments are helping, this is what I have now:

import json

with open('json.results') as json_file:
    data = json.load(json_file)

    for row in data['results']:
            print(row)  #good so far

            node = {row('Name'), row('Status')}
            for item in node():
                print(item) #blows up with "TypeError: 'dict' object is not callable"

Body:
Ok, I have the code I need now.  Thanks to Barmar and Hiero De Paula, they both contributed to my effort.

#!/usr/bin/env python3
import json

with open('json.to.import') as json_file:
    data = json.load(json_file)

    for i in data['results']:
            print(i)  #good so far
            print(type(i))

            node = {}
            node['Name'] = i['Name']
            node['Status'] = i['Status']

            print(type(node))
            print(node)
            print("Name ",  node['Name'])
            print("Status ",  node['Status'])

From this point I add a couple fields to the dict node, and then execute the push into the other system, but the print statements confirm I have accomplished whet I needed help with.


问:
How can I use "IF" statement to determine the amount of free disk space to add to a VMDK?
The script I am using is below. We are upgrading our 1500 VDI's from Windows 10 1809 to 1909 and we want to automate the process as much as possible since this will be a process that we will have to do regularly with each new version Windows puts out. We are using SCCM (System Center Configuration Manager). The script works perfect for extending disk space for multiple machines. The .csv file it is importing only contains a list of virtual machines the script is to expand disk space on. I want to use an "if" statement to determine if the amount of free space is below 30GB and, if so, to add the needed disk space to bring it up to 30GB free space. Example: "if" free disk space is -lt 30GB, Set-HardDisk -CapacityGB (the difference to make 30GB free space available), "if" free space is -eq to 30GB, do nothing. I have researched Google and this site for anything remotely similar and wasn't able to find what I need. All help accomplishing this is appreciated.</p>
```<code>##Task Change Disk Size
##Variable clear
$csvobjects = @()
$cskobject = @()
$network = @()
$isalive = @()

##Import VM name(s)
$csvobjects = Import-CSV -path "C:\Temp\ExpandHDDiskList.csv"

Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false

connect-viserver -server anyserver.com -User anyuser@anyserver.com

foreach ($csvobject in $csvobjects){
##Variable clear
$network = @()
$isalive = @()
##Pre-change data gathering
$beforechange = (GET-VM -Name $csvobject.vmname | FT -auto CapacityGB|out-string)
##Stop VM
GET-VM -Name $csvobject.vmname | Get-HardDisk -Name 'Hard disk 1' | Set-HardDisk -CapacityGB 75 -Confirm:$false
start-sleep -s 60

# Variable specifying the drive you want to extend
$drive_letter = "C"

# Script to get the partition sizes and then resize the volume
$size = (Get-PartitionSupportedSize -DriveLetter $drive_letter)
Resize-Partition -DriveLetter $drive_letter -Size $size.SizeMax
}
</code>```

答:
With PowerShell 5 or newer you can replace

```<code>    $gb = 1024 * 1024 * 1024
</code>```

with

```<code>    1GB
</code>```

And replace

```<code>    $space = 30 * $gb
</code>```

with

```<code>    30GB
</code>```

So, the entire script would look like this

```<code>    $vm = Get-VMGuest $csvobject.vmname
    if ($vm.Disks[0].FreeSpace -lt 30GB) {
    Get-HardDisk $vm.Vm | Select -first 1 | Set-HardDisk -CapacityGB ([math]::round(($vm.Disks[0].Capacity + 30GB - $vm.Disks[0].FreeSpace) / 1GB))}
</code>```

Body:
The script I am using is below. We are upgrading our 1500 VDI's from Windows 10 1809 to 1909 and we want to automate the process as much as possible since this will be a process that we will have to do regularly with each new version Windows puts out. We are using SCCM (System Center Configuration Manager). The script works perfect for extending disk space for multiple machines. The .csv file it is importing only contains a list of virtual machines the script is to expand disk space on. I want to use an "if" statement to determine if the amount of free space is below 30GB and, if so, to add the needed disk space to bring it up to 30GB free space. Example: "if" free disk space is -lt 30GB, Set-HardDisk -CapacityGB (the difference to make 30GB free space available), "if" free space is -eq to 30GB, do nothing. I have researched Google and this site for anything remotely similar and wasn't able to find what I need. All help accomplishing this is appreciated.

##Task Change Disk Size
##Variable clear
$csvobjects = @()
$cskobject = @()
$network = @()
$isalive = @()

##Import VM name(s)
$csvobjects = Import-CSV -path "C:\Temp\ExpandHDDiskList.csv"

Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false

connect-viserver -server anyserver.com -User anyuser@anyserver.com

foreach ($csvobject in $csvobjects){
##Variable clear
$network = @()
$isalive = @()
##Pre-change data gathering
$beforechange = (GET-VM -Name $csvobject.vmname | FT -auto CapacityGB|out-string)
##Stop VM
GET-VM -Name $csvobject.vmname | Get-HardDisk -Name 'Hard disk 1' | Set-HardDisk -CapacityGB 75 -Confirm:$false
start-sleep -s 60

# Variable specifying the drive you want to extend
$drive_letter = "C"

# Script to get the partition sizes and then resize the volume
$size = (Get-PartitionSupportedSize -DriveLetter $drive_letter)
Resize-Partition -DriveLetter $drive_letter -Size $size.SizeMax
}

Body:
With PowerShell 5 or newer you can replace

    $gb = 1024 * 1024 * 1024

with

    1GB

And replace

    $space = 30 * $gb

with

    30GB

So, the entire script would look like this

    $vm = Get-VMGuest $csvobject.vmname
    if ($vm.Disks[0].FreeSpace -lt 30GB) {
    Get-HardDisk $vm.Vm | Select -first 1 | Set-HardDisk -CapacityGB ([math]::round(($vm.Disks[0].Capacity + 30GB - $vm.Disks[0].FreeSpace) / 1GB))}


问:
Sum specific properties values of objects in array if they have same property name and return unique array as result using java script
my problem is to map two array of objects and sum their specifics properties if they have same name value.

For example if I would like to sum x and y of all objects where property name is 'v' etc.
Here is my code

```<code>var arr = [{name:'v', x:1, b:2, c:3},{name:'r', x:2, b:0, c:3},{name:'v', x:4, b:3, c:3}, {name:'v', x:1, b:1, c:3}];
let arr2 = []
let obj = {name:null, x:null, b: null, c:null}
arr.map(item => {
for(let i=0; i<= arr.length; i++){

    if(item.name === arr[i].name){
     let a = arr.reduce((a, b) => ({x: a.x + b.x, b: a.b + b.b}));
      obj.name = item.name, obj.x = a.x, obj.b = a.b, obj.c = item.c
    } else {
    obj.name = item.name, obj.x=item.x, obj.b=item.b, obj.c=item.c
        }
  arr2.push(obj)
        }
  }
)

console.log(arr2)
</code>```

As result i would like to return array like this

```<code>arr2 = [{name: 'v', x: 6, b: 6, c: 3}, {name: 'r', x:2, b:0, c:1}]
</code>```

答:
Here is the answer for my question</p>
```<code>var arr = [{v:'v', x:1, b:2, c:3},{v:'r', x:2, b:0, c:3},{v:'v', x:4, b:3, c:3},{v:'v', x:10, b:3, c:3},{v:'r', x:1, b:1, c:3},{v:'v', x:11, b:2, c:3},{v:'r', x:22, b:0, c:3}];
let arr2 = []
for(let j=0; j< arr.length;j++){
    for(let i=j+1; i< arr.length; i++){
        let obj = {v:null, x:null, b: null, c:null}
        if(arr[j].v === arr[i].v ){
          let a =  arr.filter(({v})=> v === arr[j].v).reduce((a, b) => ({x: a.x + b.x, b: a.b + b.b}));
        obj.v = arr[j].v
        obj.x = a.x
        obj.b = a.b
        obj.c = arr[j].c
        i= arr.length
        console.log("DA", obj)
        if(!arr2.some(item=> item.v === obj.v)){
            arr2.push(obj)
        }
    } else if(i+1 === arr.length){
        obj.v = arr[j].v
        obj.x = arr[j].x
        obj.b = arr[j].b
        obj.c = arr[j].c
        console.log("NE", obj)
        if(!arr2.some(item=> item.v === obj.v)){
            arr2.push(obj)
            }
        }
    }
}
console.log(arr2, "REZ")

</code>```

Body:
my problem is to map two array of objects and sum their specifics properties if they have same name value.

For example if I would like to sum x and y of all objects where property name is 'v' etc.
Here is my code

var arr = [{name:'v', x:1, b:2, c:3},{name:'r', x:2, b:0, c:3},{name:'v', x:4, b:3, c:3}, {name:'v', x:1, b:1, c:3}];
let arr2 = []
let obj = {name:null, x:null, b: null, c:null}
arr.map(item => {
for(let i=0; i<= arr.length; i++){

    if(item.name === arr[i].name){
     let a = arr.reduce((a, b) => ({x: a.x + b.x, b: a.b + b.b}));
      obj.name = item.name, obj.x = a.x, obj.b = a.b, obj.c = item.c
    } else {
    obj.name = item.name, obj.x=item.x, obj.b=item.b, obj.c=item.c
        }
  arr2.push(obj)
        }
  }
)

console.log(arr2)

As result i would like to return array like this

arr2 = [{name: 'v', x: 6, b: 6, c: 3}, {name: 'r', x:2, b:0, c:1}]

Body:
Here is the answer for my question

var arr = [{v:'v', x:1, b:2, c:3},{v:'r', x:2, b:0, c:3},{v:'v', x:4, b:3, c:3},{v:'v', x:10, b:3, c:3},{v:'r', x:1, b:1, c:3},{v:'v', x:11, b:2, c:3},{v:'r', x:22, b:0, c:3}];
let arr2 = []
for(let j=0; j< arr.length;j++){
    for(let i=j+1; i< arr.length; i++){
        let obj = {v:null, x:null, b: null, c:null}
        if(arr[j].v === arr[i].v ){
          let a =  arr.filter(({v})=> v === arr[j].v).reduce((a, b) => ({x: a.x + b.x, b: a.b + b.b}));
        obj.v = arr[j].v
        obj.x = a.x
        obj.b = a.b
        obj.c = arr[j].c
        i= arr.length
        console.log("DA", obj)
        if(!arr2.some(item=> item.v === obj.v)){
            arr2.push(obj)
        }
    } else if(i+1 === arr.length){
        obj.v = arr[j].v
        obj.x = arr[j].x
        obj.b = arr[j].b
        obj.c = arr[j].c
        console.log("NE", obj)
        if(!arr2.some(item=> item.v === obj.v)){
            arr2.push(obj)
            }
        }
    }
}
console.log(arr2, "REZ")


问:
Theory of storing a number and text in same SQL field
I have a three tables

Results:
TestID
TestCode
Value

Tests:
TestID
TestType
SysCodeID

SystemCodes
SysCodeID
ParentSysCodeID
Description

The question I have is for when the user is entering data into the results table.

The formatting code when the row gets the focus changes the value field to a dropdown combobox if the testCode is of type SystemList.  The drop down has a list of all the system codes that have a parentsyscodeID of the test.SysCodeID.  When the user chooses a value in the list it translates into a number which goes into the value field.

The datatype of the Results.Value field is integer.  I made it an integer instead of a string because when reporting it is easier to do calculations and sorting if it is a number.  There are issues if you are putting integer/decimal value into a string field.  As well, when the system was being designed they only wanted numbers in there.

The users now want to put strings into the value field as well as numbers/values from a list and I'm wondering what the best way of doing that would be.

Would it be bad practice to convert the field over to a string and then store both strings and integers in the same field?  There are different issues related to this one but i'm not sure if any are a really big deal.

Should I add another column into the table of string datatype and  if the test is a string type then put the data the user enters into the different field.

Another option would be to create a 1-1 relationship to another table and if the user types in a string into the value field it adds it into the new table with a key of a number.

Anyone have any interesting ideas?

答:
I would create the extra column for string values. It's not true normalization but it's the easiest to implement and to work with.

Using the same field for both numbers and strings would work to as long as you don't plan on doing anything with the numbers like summing or sorting.

The extra table approach while good from a normalization standpoint is probably overly complex.

OwnerDisplayName: Jaydel Gluckie

ContentLicense: CC BY-SA 2.5

LastEditorDisplayName: Jonathan Leffler

OwnerDisplayName: DJ


问:
AngularJs custom directive used twice in one controller with $watch
Hi I have a controller which has a param called refresh and a $watch

```<code>app.controller (..., []) {
  $scope.refresh = false;

  $scope.$watch('refresh', function() {
            if(!$scope.refresh) return;
             $scope.apiCall(true);

   }, true);
}
</code>```

I have a directive where refresh is used.

```<code>app.directive('dirA', () => {
  return {
    restricts: E,
    scope: {
      refresh: '=',
      .....
    },
    templateUrl: 'location of template',
    controller: [..., {
        function test() {
          $scope.refresh = false;
          // API call here
          fetch('/test', () => {
            this.refresh = true;
          )}
        }
    }]
  }
})
</code>```

In my Controller's template I am using this directive twice like

```<code><dirA refresh="refresh"/>
<dirA refresh="refresh"/>
</code>```

Issue that I am facing is when refresh changes from first instance of directive, $watch is called but same is not happening from second instance.

I am pretty new to angularjs, Please help if possible

答:
When you declare a controller in a directive, you also need to bind the isolate scope of your directive using bindToController.

Here is an article that explains bindToController

I also took the time to write a plunkr that demonstrates with the code you provided how this should probably look.

Body:
Hi I have a controller which has a param called refresh and a $watch

app.controller (..., []) {
  $scope.refresh = false;

  $scope.$watch('refresh', function() {
            if(!$scope.refresh) return;
             $scope.apiCall(true);

   }, true);
}

I have a directive where refresh is used.

app.directive('dirA', () => {
  return {
    restricts: E,
    scope: {
      refresh: '=',
      .....
    },
    templateUrl: 'location of template',
    controller: [..., {
        function test() {
          $scope.refresh = false;
          // API call here
          fetch('/test', () => {
            this.refresh = true;
          )}
        }
    }]
  }
})

In my Controller's template I am using this directive twice like

<dirA refresh="refresh"/>
<dirA refresh="refresh"/>

Issue that I am facing is when refresh changes from first instance of directive, $watch is called but same is not happening from second instance.

I am pretty new to angularjs, Please help if possible


问:
Check if series of numbers is between two columns in pandas dataframe
I am trying to classify genomic locations, and I have DataFrame like the following, with all locations and their respective classification types. The Type column does not have unique classifications, but each row will have a unique combination of Chr, Low, High.

```<code>pd.DataFrame({
    'Chr':[1,1,3],
    'Low':[100,200,300],
    'High':[150,250,350],
    'Type':['Foo','Bar','Foo']
})
</code>```

I then have my sample set that needs to be classified like the DataFrame below.

```<code>pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325]
})
</code>```

To classify the data, for each location in the sample set, the Chromosome position found within the Chr column must match a Chr value found within the reference DataFrame and the Loc value must be >= the Low value and <= the High value. If this happens, that row should then be labeled with the respective Type in the reference DataFrame. In the example I provide, the sample set should be labeled like the following.

```<code>pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325],
    'Type':['Foo','None','None']
})
</code>```

which looks like:

```<code>   Chr  Loc  Type
0    1  125   Foo
1    1  325  None
2    5  325  None
</code>```

答:
You could merge the two on "Chr". Then on the merged DataFrame, see if "Loc" falls between "Low" and "High" and use where to fill "Type" with NaN values if it doesn't. Finally, drop irrelevant columns and duplicate rows:

```<code>merged = sample.merge(df, on='Chr', how='left')
merged['Type'] = merged['Type'].where(merged['Loc'].between(merged['Low'], merged['High']))
out = merged.drop(columns=['Low','High']).drop_duplicates(subset=['Chr','Loc'])
</code>```

Output:

```<code>   Chr  Loc Type
0    1  125  Foo
2    1  325  NaN
4    5  325  NaN
</code>```

Body:
I am trying to classify genomic locations, and I have DataFrame like the following, with all locations and their respective classification types. The Type column does not have unique classifications, but each row will have a unique combination of Chr, Low, High.

pd.DataFrame({
    'Chr':[1,1,3],
    'Low':[100,200,300],
    'High':[150,250,350],
    'Type':['Foo','Bar','Foo']
})

I then have my sample set that needs to be classified like the DataFrame below.

pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325]
})

To classify the data, for each location in the sample set, the Chromosome position found within the Chr column must match a Chr value found within the reference DataFrame and the Loc value must be >= the Low value and <= the High value. If this happens, that row should then be labeled with the respective Type in the reference DataFrame. In the example I provide, the sample set should be labeled like the following.

pd.DataFrame({
    'Chr':[1,1,5],
    'Loc':[125,325,325],
    'Type':['Foo','None','None']
})

which looks like:

   Chr  Loc  Type
0    1  125   Foo
1    1  325  None
2    5  325  None

Body:
You could merge the two on "Chr". Then on the merged DataFrame, see if "Loc" falls between "Low" and "High" and use where to fill "Type" with NaN values if it doesn't. Finally, drop irrelevant columns and duplicate rows:

merged = sample.merge(df, on='Chr', how='left')
merged['Type'] = merged['Type'].where(merged['Loc'].between(merged['Low'], merged['High']))
out = merged.drop(columns=['Low','High']).drop_duplicates(subset=['Chr','Loc'])

Output:

   Chr  Loc Type
0    1  125  Foo
2    1  325  NaN
4    5  325  NaN


问:
Suddenly Stops working: TypeError: Cannot read property 'getRange' of null
EDIT: I have attached a copy of the spreadsheet on an alternative account. So far, regardless of solutions offered or links to other answers, I am still getting the same problem.

https://docs.google.com/spreadsheets/d/1feRQ7txV5dI-7Ein66-Z6LjF5w8vdmtw8gACk_motic/edit?usp=sharing

EDIT 2: Screenshot provided below showing execution screenshot. This was triggered in P3 using col===57

I've read through a bunch of answers on StackOverflow, and none seem to fit what's going on here and it's really throwing me for a loop. Hopefully someone can help!

This script worked for 3 months. The ONLY changes made were to the var tc numbers (i.e., which column to check as a trigger). Nothing else has changed. The strangest part of all... if lines 6-25 are triggered, everything works. If lines 26-45 are triggered, I get an error. So I'm at a loss at why this would stop working when it was working for 3 months, part of it works but the other doesn't, and I haven't changed any names/labels in the sheet or in the script.

(btw, I did check the common fixes such as ensuring the sheet names are 100% identical, including case, spaces, etc)

What is supposed to happen:

In a given sheet, when someone selects TRUE on a specific checkbox, indicated by column, the row in that sheet is moved to the next sheet in the workflow. For example, if "Prospect" line 21 is marked true, it moves to "Pricing" and is then deleted from "Prospects".

What is happening right now:

Everything works for Prospects -> Pricing, Pricing -> Onboarding, and Onboarding -> DASH.
Nothing works for ADMIN -> BOOKS, BOOKS -> PREP, PREP -> REVIEW, REVIEW - FILING. Instead I get the following error message:

Feb 9, 2022, 4:19:23 PM Error   TypeError: Cannot read property 'getRange' of null
at onEdit(Code:56:47)

EDIT: Added image of the sheets being used for reference. Metrics is not used in this script so can be ignored.

```<code>function onEdit(event) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var r = event.range;
  var s = event.source.getActiveSheet();
  var sheetName = s.getName();
  if (sheetName == "Prospects") {
    var ts = "Pricing";
    var as = "ARCHIVED";
    var tc = 11;
    var bc = 200;
    var ar = 45
  } else if (sheetName == "Pricing") {
    var ps = "Prospects";
    var ts = "Onboarding";
    var as = "ARCHIVED";
    var tc = 34;
    var bc = 11;
    var ar = 45
  } else if (sheetName == "Onboarding") {
    var ps = "Pricing";
    var ts = "DASH";
    var as = "ARCHIVED";
    var tc = 46;
    var bc = 34;
    var ar = 45
  } else if (sheetName == "ADMIN") {
    var ps = "DASH";
    var ts = "BOOKS";
    var tc = 55;
    var bc = 500;
  } else if (sheetName == "BOOKS") {
    var ps = "ADMIN";
    var ts = "PREP";
    var tc = 56;
    var bc = 10;
  } else if (sheetName == "PREP") {
    var ps = "BOOKS";
    var ts = "REVIEW";
    var tc = 57;
    var bc = 11;
  } else if (sheetName == "REVIEW") {
    var ps = "PREP";
    var ts = "FILING";
    var tc = 58;
    var bc = 12;
  }

  var targetSheet = "";
  if (r.getColumn() == tc && event.value == "TRUE") {
    targetSheet = ts;
  } else if (r.getColumn() == bc && event.value == "FALSE") {
    targetSheet = ps;
  }  else if (r.getColumn() == ar && event.value == "TRUE") {
    targetSheet = as;
  }
  var lastRow = ss.getSheetByName(targetSheet).getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()
  var row = r.getRow();
  var numColumns = s.getLastColumn();
  var target = ss.getSheetByName(targetSheet).getRange(lastRow + 1, 1);
  s.getRange(row, 1, 1, numColumns).moveTo(target);
  s.deleteRow(row);
</code>```

答:
Try this:

```<code>function onEdit(e) {
  const vA = [{ name: "Prospects", ps: "", ts: "Pricing", as: "ARCHIVED", tc: 11, bc: 200, ar: 45 }, { name: "Pricing", ps: "Prospects", ts: "Onboarding", as: "ARCHIVED", tc: 34, bc: 11, ar: 45 }];//need to fill in the rest of the array
  const sh = e.range.getSheet();
  const name = sh.getName();
  for (let i = 0; i < vA.length; i++) {
    if (name == vA[i].name) {
      let tshname;
      if (e.range.columnStart == vA[i].tc && e.value == "TRUE") {
        tshname = vA[i].ts;
      } else if (e.range.columnStart == vA[i].bc && e.value == "FALSE") {
        tshname = vA[i].ps;
      } else if (r.range.columnStart == vA[i].ar && e.value == "TRUE") {
        tshname = vA[i].as;
      }
      let tsh = e.source.getSheetByName(tshname);
      let lastRow = tsh.getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()
      sh.getRange(e.range.rowStart, 1, 1, sh.getLastColumn()).moveTo(tsh.getRange(lastRow + 1, 1));
      sh.deleteRow(e.range.rowStart);
      break;
    }
  }
}
</code>```

You will need to complete the vA array.

Body:
EDIT: I have attached a copy of the spreadsheet on an alternative account. So far, regardless of solutions offered or links to other answers, I am still getting the same problem.

https://docs.google.com/spreadsheets/d/1feRQ7txV5dI-7Ein66-Z6LjF5w8vdmtw8gACk_motic/edit?usp=sharing

EDIT 2: Screenshot provided below showing execution screenshot. This was triggered in P3 using col===57

I've read through a bunch of answers on StackOverflow, and none seem to fit what's going on here and it's really throwing me for a loop. Hopefully someone can help!

This script worked for 3 months. The ONLY changes made were to the var tc numbers (i.e., which column to check as a trigger). Nothing else has changed. The strangest part of all... if lines 6-25 are triggered, everything works. If lines 26-45 are triggered, I get an error. So I'm at a loss at why this would stop working when it was working for 3 months, part of it works but the other doesn't, and I haven't changed any names/labels in the sheet or in the script.

(btw, I did check the common fixes such as ensuring the sheet names are 100% identical, including case, spaces, etc)

What is supposed to happen:

In a given sheet, when someone selects TRUE on a specific checkbox, indicated by column, the row in that sheet is moved to the next sheet in the workflow. For example, if "Prospect" line 21 is marked true, it moves to "Pricing" and is then deleted from "Prospects".

What is happening right now:

Everything works for Prospects -> Pricing, Pricing -> Onboarding, and Onboarding -> DASH.
Nothing works for ADMIN -> BOOKS, BOOKS -> PREP, PREP -> REVIEW, REVIEW - FILING. Instead I get the following error message:

Feb 9, 2022, 4:19:23 PM Error   TypeError: Cannot read property 'getRange' of null
at onEdit(Code:56:47)

EDIT: Added image of the sheets being used for reference. Metrics is not used in this script so can be ignored.

function onEdit(event) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var r = event.range;
  var s = event.source.getActiveSheet();
  var sheetName = s.getName();
  if (sheetName == "Prospects") {
    var ts = "Pricing";
    var as = "ARCHIVED";
    var tc = 11;
    var bc = 200;
    var ar = 45
  } else if (sheetName == "Pricing") {
    var ps = "Prospects";
    var ts = "Onboarding";
    var as = "ARCHIVED";
    var tc = 34;
    var bc = 11;
    var ar = 45
  } else if (sheetName == "Onboarding") {
    var ps = "Pricing";
    var ts = "DASH";
    var as = "ARCHIVED";
    var tc = 46;
    var bc = 34;
    var ar = 45
  } else if (sheetName == "ADMIN") {
    var ps = "DASH";
    var ts = "BOOKS";
    var tc = 55;
    var bc = 500;
  } else if (sheetName == "BOOKS") {
    var ps = "ADMIN";
    var ts = "PREP";
    var tc = 56;
    var bc = 10;
  } else if (sheetName == "PREP") {
    var ps = "BOOKS";
    var ts = "REVIEW";
    var tc = 57;
    var bc = 11;
  } else if (sheetName == "REVIEW") {
    var ps = "PREP";
    var ts = "FILING";
    var tc = 58;
    var bc = 12;
  }

  var targetSheet = "";
  if (r.getColumn() == tc && event.value == "TRUE") {
    targetSheet = ts;
  } else if (r.getColumn() == bc && event.value == "FALSE") {
    targetSheet = ps;
  }  else if (r.getColumn() == ar && event.value == "TRUE") {
    targetSheet = as;
  }
  var lastRow = ss.getSheetByName(targetSheet).getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()
  var row = r.getRow();
  var numColumns = s.getLastColumn();
  var target = ss.getSheetByName(targetSheet).getRange(lastRow + 1, 1);
  s.getRange(row, 1, 1, numColumns).moveTo(target);
  s.deleteRow(row);

Body:
Try this:

function onEdit(e) {
  const vA = [{ name: "Prospects", ps: "", ts: "Pricing", as: "ARCHIVED", tc: 11, bc: 200, ar: 45 }, { name: "Pricing", ps: "Prospects", ts: "Onboarding", as: "ARCHIVED", tc: 34, bc: 11, ar: 45 }];//need to fill in the rest of the array
  const sh = e.range.getSheet();
  const name = sh.getName();
  for (let i = 0; i < vA.length; i++) {
    if (name == vA[i].name) {
      let tshname;
      if (e.range.columnStart == vA[i].tc && e.value == "TRUE") {
        tshname = vA[i].ts;
      } else if (e.range.columnStart == vA[i].bc && e.value == "FALSE") {
        tshname = vA[i].ps;
      } else if (r.range.columnStart == vA[i].ar && e.value == "TRUE") {
        tshname = vA[i].as;
      }
      let tsh = e.source.getSheetByName(tshname);
      let lastRow = tsh.getRange(1, 1).getDataRegion(SpreadsheetApp.Dimension.ROWS).getLastRow()
      sh.getRange(e.range.rowStart, 1, 1, sh.getLastColumn()).moveTo(tsh.getRange(lastRow + 1, 1));
      sh.deleteRow(e.range.rowStart);
      break;
    }
  }
}

You will need to complete the vA array.


问:
Does MSAL.js support the check_session_iframe OIDC endpoint?
I'm working on an SPA which depends on an instance of Identity Server for authenticating users. I need a solution that manages my tokens locally, but Duende (the owners of Identity Server) lean towards a Backend For Frontend (BFF) pattern over Javascript libraries. This isn't going to work for us. Since the original oidc-client that was written by the authors of Identity Server is no longer maintained I've been looking at Javascript alternatives. The most likely candidate would seem to be Microsoft's MSAL.js which is built for Azure AD, but supposedly supports OIDC standards.

From what I can tell, MSAL.js forces you down an offline_access path using refresh tokens to renew security tokens. Even if I don't expressly require an offline_access scope the library appends one anyway! But my use case doesn't require refresh tokens. Instead I want my client to keep the session on the identity provider fresh using OIDC session mamnagement standards (via the check_session_iframe endpoint exposed by the provider's well-known JSON).

I have found that if I ignore the offline_access scope requested by the MSAL.js library so my identity provider only issues and ID token and an access token then MSAL continues to work just fine. It even has an ssoSilent option for explicitly renewing the tokens via a connect/authorize request in a hidden iframe. But as far as I can tell I can't have the library keeping that session fresh via an iframe like the old oidc-client used to.

So given that session management is part of the OIDC specification, and MSAL is supposed to be an OIDC-compliant library, am I missing something here?

答: Unfortunately, at this time MSAL.js does not have an API that integrates with the checksession endpoint. If you would like to see this added, you are welcome to open a PR on our Github.