问:
Prevent sizeForItemAt from using the wrong cell size because of reuse for dynamic collectionView cell
I used auto layout to dynamically calculate the size of the collectionView cell. Some cells are using the dimensions from the reused cells when they first scrolled to view port. As I continue to scroll the collectionView, they will be set to the correct value.

In my sizeForItemAt, I have the following:

```<code>    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        if let cachedSize = cachedHeightForIndexPath[indexPath] {
            return cachedSize
        }

        if let cell = collectionView.cellForItem(at: indexPath) {
            cell.setNeedsLayout()
            cell.layoutIfNeeded()
            let size = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
            cachedHeightForIndexPath[indexPath] = size
            print("value is \(size) for indexpath: \(indexPath)")
            return size
        }
        return CGSize(width: ScreenSize.width, height: 0.0)
    }

</code>```

I have a three sessions, with the first section all cell's height theoretically equals to 88, and all the other sections all cell's height equals to 104.

Originally, only the first section is visible. From the console, I can see the height of the cell is set to 88.0 as expected. As I scroll to the remaining sections(the first section will be invisible and the cells will be reused), some cells from second section and third section are using the value 88.0 as the height of the cells when first scrolled to view port instead of 104. As I continue to scroll, the wrong sized cell will be using 104 as the dimension. How do we force all the cells to recalculate the height and don't use the height from old cell.

答:
You have the right idea, but when you measure the cell by its internal constraints by calling systemLayoutSizeFitting, instead of calling systemLayoutSizeFitting on an existing cell (collectionView.cellForItem), you need to arm yourself with a model cell that you configure the same as cellForItem would configure it and measure that.

Here's how I do it (remarkably similar to what you have, with that one difference; also, I store the size in the model):

```<code>func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let memosize = self.sections[indexPath.section].itemData[indexPath.row].size
    if memosize != .zero {
        return memosize
    }
    self.configure(self.modelCell, forIndexPath:indexPath) // in common with cellForItem
    var sz = self.modelCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
    sz.width = ceil(sz.width); sz.height = ceil(sz.height)
    self.sections[indexPath.section].itemData[indexPath.row].size = sz // memoize
    return sz
}
</code>```

Body:
I used auto layout to dynamically calculate the size of the collectionView cell. Some cells are using the dimensions from the reused cells when they first scrolled to view port. As I continue to scroll the collectionView, they will be set to the correct value.

In my sizeForItemAt, I have the following:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        if let cachedSize = cachedHeightForIndexPath[indexPath] {
            return cachedSize
        }

        if let cell = collectionView.cellForItem(at: indexPath) {
            cell.setNeedsLayout()
            cell.layoutIfNeeded()
            let size = cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
            cachedHeightForIndexPath[indexPath] = size
            print("value is \(size) for indexpath: \(indexPath)")
            return size
        }
        return CGSize(width: ScreenSize.width, height: 0.0)
    }

I have a three sessions, with the first section all cell's height theoretically equals to 88, and all the other sections all cell's height equals to 104.

Originally, only the first section is visible. From the console, I can see the height of the cell is set to 88.0 as expected. As I scroll to the remaining sections(the first section will be invisible and the cells will be reused), some cells from second section and third section are using the value 88.0 as the height of the cells when first scrolled to view port instead of 104. As I continue to scroll, the wrong sized cell will be using 104 as the dimension. How do we force all the cells to recalculate the height and don't use the height from old cell.

Body:
You have the right idea, but when you measure the cell by its internal constraints by calling systemLayoutSizeFitting, instead of calling systemLayoutSizeFitting on an existing cell (collectionView.cellForItem), you need to arm yourself with a model cell that you configure the same as cellForItem would configure it and measure that.

Here's how I do it (remarkably similar to what you have, with that one difference; also, I store the size in the model):

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let memosize = self.sections[indexPath.section].itemData[indexPath.row].size
    if memosize != .zero {
        return memosize
    }
    self.configure(self.modelCell, forIndexPath:indexPath) // in common with cellForItem
    var sz = self.modelCell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
    sz.width = ceil(sz.width); sz.height = ceil(sz.height)
    self.sections[indexPath.section].itemData[indexPath.row].size = sz // memoize
    return sz
}


来源: stackexchange

问:
Convert numpy.array object to PIL image object
I have been trying to convert a numpy array to PIL image using Image.fromarray but it shows the following error.

Traceback (most recent call last):   File "C:\Users\Shri1008 Saurav
  Das\AppData\Local\Programs\Python\Python36-32\lib\site-packages\PIL\Image.py",
  line 2428, in fromarray
      mode, rawmode = _fromarray_typemap[typekey] KeyError: ((1, 1, 3062), '|u1')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):   File "C:/Users/Shri1008 Saurav
  Das/AppData/Local/Programs/Python/Python36-32/projects/try.py", line
  13, in
      img = Image.fromarray(IMIR)   File "C:\Users\Shri1008 Saurav Das\AppData\Local\Programs\Python\Python36-32\lib\site-packages\PIL\Image.py",
  line 2431, in fromarray
      raise TypeError("Cannot handle this data type") TypeError: Cannot handle this data type

I extracted the matrix from an hdf5 file and converted it to a numpy array. I then did some basic transformations to enhance contrast(most probable reason for error). Here is the code.

```<code>import tkinter as tk
import h5py as hp
import numpy as np
from PIL import Image, ImageTk

hf = hp.File('3RIMG_13JUL2018_0015_L1C_SGP.h5', 'r')
IMIR = hf.get('IMG_MIR')
IMIR = np.uint8(np.power(np.double(np.array(IMIR)),4)/5000000000)
IMIR = np.array(IMIR)

root = tk.Tk()
img = Image.fromarray(IMIR)
photo = ImageTk.PhotoImage(file = img)
cv = tk.Canvas(root, width=photo.width(), height=photo.height())
cv.create_image(1,1,anchor="nw",image=photo)
</code>```

I am running Python 3.6 on Windows 10. Please help.

答:
The problem is the shape of your data. Pillow's fromarray function can only do a MxNx3 array (RGB image), or an MxN array (grayscale). To make the grayscale image work, you have to turn you MxNx1 array into a MxN array. You can do this by using the np.reshape() function. This will flatten out the data and then put it into a different array shape.

IMIR = IMIR.reshape(M, N) #let M and N be the dimensions of your image

(add this before the img = Image.fromarray(IMIR))

ContentLicense: CC BY-SA 4.0

Body:
I have been trying to convert a numpy array to PIL image using Image.fromarray but it shows the following error.

Traceback (most recent call last):   File "C:\Users\Shri1008 Saurav
  Das\AppData\Local\Programs\Python\Python36-32\lib\site-packages\PIL\Image.py",
  line 2428, in fromarray
      mode, rawmode = _fromarray_typemap[typekey] KeyError: ((1, 1, 3062), '|u1')

During handling of the above exception, another exception occurred:

Traceback (most recent call last):   File "C:/Users/Shri1008 Saurav
  Das/AppData/Local/Programs/Python/Python36-32/projects/try.py", line
  13, in
      img = Image.fromarray(IMIR)   File "C:\Users\Shri1008 Saurav Das\AppData\Local\Programs\Python\Python36-32\lib\site-packages\PIL\Image.py",
  line 2431, in fromarray
      raise TypeError("Cannot handle this data type") TypeError: Cannot handle this data type

I extracted the matrix from an hdf5 file and converted it to a numpy array. I then did some basic transformations to enhance contrast(most probable reason for error). Here is the code.

import tkinter as tk
import h5py as hp
import numpy as np
from PIL import Image, ImageTk

hf = hp.File('3RIMG_13JUL2018_0015_L1C_SGP.h5', 'r')
IMIR = hf.get('IMG_MIR')
IMIR = np.uint8(np.power(np.double(np.array(IMIR)),4)/5000000000)
IMIR = np.array(IMIR)

root = tk.Tk()
img = Image.fromarray(IMIR)
photo = ImageTk.PhotoImage(file = img)
cv = tk.Canvas(root, width=photo.width(), height=photo.height())
cv.create_image(1,1,anchor="nw",image=photo)

I am running Python 3.6 on Windows 10. Please help.


问:
Associate IAM Role with RDS instance
I'm trying to add a IAM role to RDS instance via CloudFormation template. I could not find such option after looking into all attributes stated here: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-rds-database-instance.html.</p>

答:
You cannot assign role to DbInstances.

You need to create Aurora DbCluster (not instance) and specify the role for dbCluster. Here is the example cloudformation:

```<code> "DBClusters": [
    {
        ...
        "AssociatedRoles": [
            {
                "Status": "ACTIVE",
                "RoleArn": "<role-arn>"
            }
        ],
        ...
    }
   ]
</code>```

Title: Associate IAM Role with RDS instance

Body:
You cannot assign role to DbInstances.

You need to create Aurora DbCluster (not instance) and specify the role for dbCluster. Here is the example cloudformation:

 "DBClusters": [
    {
        ...
        "AssociatedRoles": [
            {
                "Status": "ACTIVE",
                "RoleArn": "<role-arn>"
            }
        ],
        ...
    }
   ]


问:
Laravel 5 / L5: Set number of attempts when pushing job to a queue using Database connection
I have setup the Queue system in L5 using the Databse connection and after i run the migration I have two tables in my DB failed_jobs and jobs. Everything is working fine so far but when the pushed operation failed its keep going and trying to process the operation and did not delete the job on fail or inserted on  failed_jobs

```<code> Queue::push(function($job) use ($id)
 {
     Account::delete($id);

     $job->delete();
 });
</code>```

In the above example how can I set number of attempts to try if not success and then insert into failed_jobs.

I know this can be done using

```<code>php artisan queue:listen --tries=3
</code>```

But I want the same using the Closures as I have different cases

答:
You can define the maximum number of attempts on the job class itself.

If the maximum number of attempts is specified on the job, it will take precedence over the value provided on the command line.

Add this to your job class:

```<code>/**
* The number of times the job may be attempted.
*
* @var int
*/

public $tries = 5;
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I have setup the Queue system in L5 using the Databse connection and after i run the migration I have two tables in my DB failed_jobs and jobs. Everything is working fine so far but when the pushed operation failed its keep going and trying to process the operation and did not delete the job on fail or inserted on  failed_jobs

 Queue::push(function($job) use ($id)
 {
     Account::delete($id);

     $job->delete();
 });

In the above example how can I set number of attempts to try if not success and then insert into failed_jobs.

I know this can be done using

php artisan queue:listen --tries=3

But I want the same using the Closures as I have different cases

Body:
You can define the maximum number of attempts on the job class itself.

If the maximum number of attempts is specified on the job, it will take precedence over the value provided on the command line.

Add this to your job class:

/**
* The number of times the job may be attempted.
*
* @var int
*/

public $tries = 5;


问:
Convert DTS.Variables of type System.Object into a list
I have an SSIS package that executes a SQL task in order to get the names of servers I need to connect to. Then, the results of that query are stored in an variable object called "servers". I then want to run another package on each server at once, so I wanted to split out the "servers" variable. However, when I do this in a C# Script Task, I keep getting the error:

Error: 0x1 at Script Task: Exception has been thrown by the target of an invocation.

Here's the code to split out the servers variable:

Error: 0x1 at Script Task: Exception has been thrown by the target of an invocation.

```<code>public void Main()
{
    var serverlist = (string[])Dts.Variables["User::servers"].Value;

    Dts.Variables["server1"].Value = serverlist[0];
    Dts.TaskResult = (int)ScriptResults.Success;
}

</code>```

It should be a pretty simple code, but for some reason, it just does not work.

答:
From the title of your question, it looks like you're trying to populate a C# list from an SSIS object variable.  If this is correct it can be done as follows.  Either you can populate a DataTable object with the contents of the SSIS object variable, or if you are looking to use a list specifically a list can be populated from the DataTable and you can then work with the list after this.  In the example below an OleDBDataAdapter is used to populate a DataTable object from the SSIS object variable using the Fill method.  The data filled from the object variable can they be accessed through the DataRow objects in the DataTable.  Since it looks like the SSIS object variable only contains a single column it can be accessed from column index 0 of each DataRow, dr[0] below.  You've likely already done this, but be sure that the SSIS object variable is in the ReadOnlyVariables field of the Script Task.

```<code>using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;

List<string> serverNamesList = new List<string>();

OleDbDataAdapter dtAdapter = new OleDbDataAdapter();
DataTable serverNamesDataTable = new DataTable();

//populate data table
dtAdapter.Fill(serverNamesDataTable, Dts.Variables["User::ObjectVariable"].Value);

foreach (DataRow dr in serverNamesDataTable.Rows)
{
    //either access server names from column index 0 of DataRow or add to list
    serverNamesList.Add(dr[0].ToString());
}
</code>```

Body:
I have an SSIS package that executes a SQL task in order to get the names of servers I need to connect to. Then, the results of that query are stored in an variable object called "servers". I then want to run another package on each server at once, so I wanted to split out the "servers" variable. However, when I do this in a C# Script Task, I keep getting the error:

Error: 0x1 at Script Task: Exception has been thrown by the target of an invocation.

Here's the code to split out the servers variable:

Error: 0x1 at Script Task: Exception has been thrown by the target of an invocation.

public void Main()
{
    var serverlist = (string[])Dts.Variables["User::servers"].Value;

    Dts.Variables["server1"].Value = serverlist[0];
    Dts.TaskResult = (int)ScriptResults.Success;
}

It should be a pretty simple code, but for some reason, it just does not work.

Body:
From the title of your question, it looks like you're trying to populate a C# list from an SSIS object variable.  If this is correct it can be done as follows.  Either you can populate a DataTable object with the contents of the SSIS object variable, or if you are looking to use a list specifically a list can be populated from the DataTable and you can then work with the list after this.  In the example below an OleDBDataAdapter is used to populate a DataTable object from the SSIS object variable using the Fill method.  The data filled from the object variable can they be accessed through the DataRow objects in the DataTable.  Since it looks like the SSIS object variable only contains a single column it can be accessed from column index 0 of each DataRow, dr[0] below.  You've likely already done this, but be sure that the SSIS object variable is in the ReadOnlyVariables field of the Script Task.

using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;

List<string> serverNamesList = new List<string>();

OleDbDataAdapter dtAdapter = new OleDbDataAdapter();
DataTable serverNamesDataTable = new DataTable();

//populate data table
dtAdapter.Fill(serverNamesDataTable, Dts.Variables["User::ObjectVariable"].Value);

foreach (DataRow dr in serverNamesDataTable.Rows)
{
    //either access server names from column index 0 of DataRow or add to list
    serverNamesList.Add(dr[0].ToString());
}


问:
Query not detecting input further out then column AH
So, I have a quite large pool of data, which I am query'ing thru a drop-down menu.

However, whenever I put the query to look for a column further out the AH, I get no results at all.

I have made sure all cells are set to "Plain text"

This one is working, up to AH, if I put it at AI or further, I get an empty result.

```<code>=Query({J5:CE500},"Select Col"&match(E3,J3:AH3)&",Col"&match(E3,J3:AH3)+1&",Col"&match(E3,J3:AH3)+2&",Col"&match(E3,J3:AH3)+3)
</code>```

There are no real errors, just text not showing in column 2-5, as would be expected

Link to the sheet: https://docs.google.com/spreadsheets/d/1LQK6chD_nLS1JX_jXt8pNGeCwKUTvYT2Lo_0CI0Pk2A/edit?usp=sharing

答:
replace your formula with this:

```<code>=ARRAYFORMULA(INDIRECT(
 ADDRESS(3, MATCH(E2, G2:2, 0)+6, 4)&":"&
 ADDRESS(200, MATCH(E2, G2:2, 0)+9, 4)))
</code>```

Body:
So, I have a quite large pool of data, which I am query'ing thru a drop-down menu.

However, whenever I put the query to look for a column further out the AH, I get no results at all.

I have made sure all cells are set to "Plain text"

This one is working, up to AH, if I put it at AI or further, I get an empty result.

=Query({J5:CE500},"Select Col"&match(E3,J3:AH3)&",Col"&match(E3,J3:AH3)+1&",Col"&match(E3,J3:AH3)+2&",Col"&match(E3,J3:AH3)+3)

There are no real errors, just text not showing in column 2-5, as would be expected

Link to the sheet: https://docs.google.com/spreadsheets/d/1LQK6chD_nLS1JX_jXt8pNGeCwKUTvYT2Lo_0CI0Pk2A/edit?usp=sharing

Body:
replace your formula with this:

=ARRAYFORMULA(INDIRECT(
 ADDRESS(3, MATCH(E2, G2:2, 0)+6, 4)&":"&
 ADDRESS(200, MATCH(E2, G2:2, 0)+9, 4)))


问:
How to use MaterializeCss with Vue.js?
I don't want to use Vue-Material nor Vuetify.

I want to use Materialize.
What I do is:

```<code>npm install materialize-css@next
</code>```

In main.js, where my new Vue App is defined I import Materialize like this:

```<code>import 'materialize-css'
</code>```

Somehow the javascript is working, but the CSS is not loading; I test it with a Card Reveal.

The swapping animation works, but it is not styled. Card Reveal is one of the reasons why I want to use MaterializeCss, those other two don't provide this functionality. And I also want to use 'normal' HTML elements instead of using 100 of new elements (for example in vuetify).

答:
I would also recommend you add the materialize css CDN in the index.html. Aand also create a script tag and add this:

```<code>document.addEventListener('DOMContentLoaded', function() {
    M.AutoInit();
 });
</code>```

Title: How to use MaterializeCss with Vue.js?

Body:
I don't want to use Vue-Material nor Vuetify.

I want to use Materialize.
What I do is:

npm install materialize-css@next

In main.js, where my new Vue App is defined I import Materialize like this:

import 'materialize-css'

Somehow the javascript is working, but the CSS is not loading; I test it with a Card Reveal.

The swapping animation works, but it is not styled. Card Reveal is one of the reasons why I want to use MaterializeCss, those other two don't provide this functionality. And I also want to use 'normal' HTML elements instead of using 100 of new elements (for example in vuetify).

Body:
I would also recommend you add the materialize css CDN in the index.html. Aand also create a script tag and add this:

document.addEventListener('DOMContentLoaded', function() {
    M.AutoInit();
 });


问:
Create custom list data structure with "toList" function
I want to create my own list data structure called Nodes. Then I will use my ListConverter class, which contains the 'toList' function, and create an instance of it.

data Nodes a = Empty
             | Node a (Nodes a)

class ListConverter a where
    toList :: a -> [Integer]

instance (Integral a) => ListConverter (Nodes a) where
    toList Empty = []
    toList (Node x Empty) = [x]
    toList (Node x y) = x : toList y
```

<p>GHCi tells me, that the expected type is 'Integer' but is currently 'a'. Im very confused, because in the instance I give a type for a (Integral). Here's the error message:</p>

```error:
    * Couldn't match expected type `Integer' with actual type `a'
      `a' is a rigid type variable bound by
        the instance declaration
        at main.hs:7:10-48
    * In the expression: x
      In the expression: [x]
      In an equation for `toList': toList (Node x Empty) = [x]
    * Relevant bindings include
        x :: a (bound at main.hs:9:18)
        toList :: Nodes a -> [Integer] (bound at main.hs:8:5)
  |
9 |     toList (Node x Empty) = [x]
  |                              ^
```

答:
Your instance of ListConverter is expected to accept any value of class Integral for "a", but Integer is a specific type, not a class; you'd have to do this:

instance ListConverter (Nodes Integer) where
```

<p>That or, conversely, make your ListConverter class capable of producing a list of whatever type your Nodes value contains:</p>

<pre class="lang-hs prettyprint-override"><code>class ListConverter f where
    toList :: f a -> [a]

instance ListConverter Nodes where
    toList Empty = []
    toList (Node x y) = x : toList y
</code>```

(The second equation for toList - (Node x Empty) - is unnecessary)

Body:
I want to create my own list data structure called Nodes. Then I will use my ListConverter class, which contains the 'toList' function, and create an instance of it.

data Nodes a = Empty
             | Node a (Nodes a)

class ListConverter a where
    toList :: a -> [Integer]

instance (Integral a) => ListConverter (Nodes a) where
    toList Empty = []
    toList (Node x Empty) = [x]
    toList (Node x y) = x : toList y

GHCi tells me, that the expected type is 'Integer' but is currently 'a'. Im very confused, because in the instance I give a type for a (Integral). Here's the error message:

error:
    * Couldn't match expected type `Integer' with actual type `a'
      `a' is a rigid type variable bound by
        the instance declaration
        at main.hs:7:10-48
    * In the expression: x
      In the expression: [x]
      In an equation for `toList': toList (Node x Empty) = [x]
    * Relevant bindings include
        x :: a (bound at main.hs:9:18)
        toList :: Nodes a -> [Integer] (bound at main.hs:8:5)
  |
9 |     toList (Node x Empty) = [x]
  |                              ^

Body:
Your instance of ListConverter is expected to accept any value of class Integral for "a", but Integer is a specific type, not a class; you'd have to do this:

instance ListConverter (Nodes Integer) where

That or, conversely, make your ListConverter class capable of producing a list of whatever type your Nodes value contains:

class ListConverter f where
    toList :: f a -> [a]

instance ListConverter Nodes where
    toList Empty = []
    toList (Node x y) = x : toList y

(The second equation for toList - (Node x Empty) - is unnecessary)


问:
Removing nested api call from for loop
i made an api call to return a set of data(ex: users - list type, with the returned data i created a for loop and and within my for loop i make another api call to get the user's profile detail based on the user's id. I know this isn't the best practice and i was wondering how i could go about refactoring it.

```<code>api.get(...).then(response => {
   this.users = response;
   for(let i=0; i<this.users.length; i++){
     api.get(...this.users[i].id).then(response => {
       if(response.name == this.users[i].name)
         this.newList.push(response);
     })
   }
})
</code>```

and in my html i loop over this.newList to display the info that i need.

How can i remove the nested api call from within the for loop and still get the same results?

答:
One possible solution is to use async/await. Although this will not remove nested loop, but make code look better

Example

```<code>async function getUsersAndProfiles () {
    try {
        this.users = await api.get(...);
        for(let i=0; i<this.users.length; i++){
            let response = await api.get(...this.users[i].id);
            if (response.name == this.users[i].name)
                this.newList.push(response);
        }
    }
    catch (e)
        console.log(e);
}
</code>```

You can even move api call for user profile to another async function for possible future reuse and better code structure

Title: Removing nested api call from for loop

Body:
i made an api call to return a set of data(ex: users - list type, with the returned data i created a for loop and and within my for loop i make another api call to get the user's profile detail based on the user's id. I know this isn't the best practice and i was wondering how i could go about refactoring it.

api.get(...).then(response => {
   this.users = response;
   for(let i=0; i<this.users.length; i++){
     api.get(...this.users[i].id).then(response => {
       if(response.name == this.users[i].name)
         this.newList.push(response);
     })
   }
})

and in my html i loop over this.newList to display the info that i need.

How can i remove the nested api call from within the for loop and still get the same results?

Body:
One possible solution is to use async/await. Although this will not remove nested loop, but make code look better

Example

async function getUsersAndProfiles () {
    try {
        this.users = await api.get(...);
        for(let i=0; i<this.users.length; i++){
            let response = await api.get(...this.users[i].id);
            if (response.name == this.users[i].name)
                this.newList.push(response);
        }
    }
    catch (e)
        console.log(e);
}

You can even move api call for user profile to another async function for possible future reuse and better code structure


问:
How to send email using MS Outlook Template (.oft), combined with variable values inserted into body of email (through Excel or otherwise)
Example: An interview confirmation email in Outlook.

Dear [A],

Your interview with [B] is confirmed for [C]. The address is [D].

Thank you,

John Doe

A - First Name

B - Company Name

C - Date & Time

D - Physical Address

I've seen people use Excel for this, but I want to be able to just enter A, B, C and D values somewhere, click send, and that's it.

All the code I've come across can achieve variable factors, but hardly any had codes for the body of the email, and if they did, NONE of them incorporated .oft files.

答:
Your question implies you were expecting to find some code that exactly matched your requirement.  Perhaps this is unfair criticism but many people do seem to expect their exact requirement to already exist or for someone to code it for them.

If I have a requirement that needs expertise with functionality that is new to me, I research each area separately and then experiment before trying to use my new knowledge to meet my requirement.

The first knowledge needed for your requirement is to create an email template file.  I assume you already know how to do this but, if not, there are many websites that explain how to do it.  I saved my template with the name “StdMsg.oft”.  You will need to amend my macro to use your name for your template.

You can save an email template file anywhere but it is probably best to use the default location so all your templates are together.  When you want to open the template, your macro will need to know where it is.  The default location, for Windows 10, is “C:\Users\xxxxx\AppData\Roaming\Microsoft\Templates” where “xxxxx” is your user name.  You can type this string out but, if you wish to share this macro with colleagues, you may wish to ask the system for the current value of “xxxxx”.  I easily found a site which gave me the default location but finding a site which told me how to get the value of “xxxxx” was more difficult.   I found plenty of sites that told me how to get the value of “xxxxx” but most were wrong or assumed knowledge that the reader might not have.  I keep a folder named “Resources” with subfolders such as Html, Css, VBAExcel, VBAOutlook and VBAGeneral.  These subfolders contain text files recording useful snippets that I am unlikely to remember.  I suggest you create a similar folder and record how I obtained the value of “xxxxx”.

Next you need to open the email template file.  I found plenty of sites that showed how to do so from Excel but I did not find a single site that showed how to do so correctly from Outlook.  From Excel, you must create an Outlook application object.  From Outlook, you are already within an Outlook application object so you do not need to create another.  In fact, you cannot create a new Outlook application object because Outlook only allows one version of itself to be running.  If you try to create a new Outlook application object, you are given a reference to the copy that is already running.  Again you may wish to record this information in a resource folder.

I have used InputBox to obtain the four values from the user.  I would use a form if I was writing this macro for myself or a client.  It is difficult to show how to create a form which would be wasted effort if you already know.

Once the email template is open, you have access to all its properties.  There are many answers on this site, and elsewhere, that show how to amend the html or the text body of an email.  I assume you want to send html emails so I have amended the html body.

My macro displays the edited email but you could use Send instead of Display if you don’t want to check the email before it is sent.

```<code>Sub SendStdMsgOft()

  Dim Address As String
  Dim CompanyName As String
  Dim DateAndTime As String
  Dim FirstName As String
  Dim NewEmail As MailItem
  Dim PathFileName As String

  PathFileName = Environ("AppData") & "\Microsoft\Templates\StdMsg.oft"

  Set NewEmail = CreateItemFromTemplate(PathFileName)

  FirstName = InputBox("First name")
  CompanyName = InputBox("Company name")
  DateAndTime = InputBox("Date And Time")
  Address = InputBox("Address")

  With NewEmail
    .HtmlBody = Replace(.HtmlBody, "[A]", FirstName)
    .HtmlBody = Replace(.HtmlBody, "[B]", CompanyName)
    .HtmlBody = Replace(.HtmlBody, "[C]", DateAndTime)
    .HtmlBody = Replace(.HtmlBody, "[D]", Address)
    .Display
  End With

End Sub
</code>```

Body:
Your question implies you were expecting to find some code that exactly matched your requirement.  Perhaps this is unfair criticism but many people do seem to expect their exact requirement to already exist or for someone to code it for them.

If I have a requirement that needs expertise with functionality that is new to me, I research each area separately and then experiment before trying to use my new knowledge to meet my requirement.

The first knowledge needed for your requirement is to create an email template file.  I assume you already know how to do this but, if not, there are many websites that explain how to do it.  I saved my template with the name “StdMsg.oft”.  You will need to amend my macro to use your name for your template.

You can save an email template file anywhere but it is probably best to use the default location so all your templates are together.  When you want to open the template, your macro will need to know where it is.  The default location, for Windows 10, is “C:\Users\xxxxx\AppData\Roaming\Microsoft\Templates” where “xxxxx” is your user name.  You can type this string out but, if you wish to share this macro with colleagues, you may wish to ask the system for the current value of “xxxxx”.  I easily found a site which gave me the default location but finding a site which told me how to get the value of “xxxxx” was more difficult.   I found plenty of sites that told me how to get the value of “xxxxx” but most were wrong or assumed knowledge that the reader might not have.  I keep a folder named “Resources” with subfolders such as Html, Css, VBAExcel, VBAOutlook and VBAGeneral.  These subfolders contain text files recording useful snippets that I am unlikely to remember.  I suggest you create a similar folder and record how I obtained the value of “xxxxx”.

Next you need to open the email template file.  I found plenty of sites that showed how to do so from Excel but I did not find a single site that showed how to do so correctly from Outlook.  From Excel, you must create an Outlook application object.  From Outlook, you are already within an Outlook application object so you do not need to create another.  In fact, you cannot create a new Outlook application object because Outlook only allows one version of itself to be running.  If you try to create a new Outlook application object, you are given a reference to the copy that is already running.  Again you may wish to record this information in a resource folder.

I have used InputBox to obtain the four values from the user.  I would use a form if I was writing this macro for myself or a client.  It is difficult to show how to create a form which would be wasted effort if you already know.

Once the email template is open, you have access to all its properties.  There are many answers on this site, and elsewhere, that show how to amend the html or the text body of an email.  I assume you want to send html emails so I have amended the html body.

My macro displays the edited email but you could use Send instead of Display if you don’t want to check the email before it is sent.

Sub SendStdMsgOft()

  Dim Address As String
  Dim CompanyName As String
  Dim DateAndTime As String
  Dim FirstName As String
  Dim NewEmail As MailItem
  Dim PathFileName As String

  PathFileName = Environ("AppData") & "\Microsoft\Templates\StdMsg.oft"

  Set NewEmail = CreateItemFromTemplate(PathFileName)

  FirstName = InputBox("First name")
  CompanyName = InputBox("Company name")
  DateAndTime = InputBox("Date And Time")
  Address = InputBox("Address")

  With NewEmail
    .HtmlBody = Replace(.HtmlBody, "[A]", FirstName)
    .HtmlBody = Replace(.HtmlBody, "[B]", CompanyName)
    .HtmlBody = Replace(.HtmlBody, "[C]", DateAndTime)
    .HtmlBody = Replace(.HtmlBody, "[D]", Address)
    .Display
  End With

End Sub


问:
How to display the datetimepicker in another language
I can't get the datetimepicker text to show the abbreviation for the month in another language

I changed the regional settings for my PC to Dutch. That changes the month name from May to mei but I don't want to do that.

On start application:

```<code>CultureInfo.CurrentCulture = New CultureInfo("en-US", False)

ElseIf TypeOf a Is DateTimePicker Then
        If TableDataString(index) IsNot Nothing And TableDataString(index) <> "" Then
            Dim dt As Date = TableDataString(index).ToString
            TryCast(a, DateTimePicker).Format = DateTimePickerFormat.Custom
            TryCast(a, DateTimePicker).CustomFormat = "dd-MMM-yyyy"
            TryCast(a, DateTimePicker).Text = dt
        Else
            Dim dt As Date
            TryCast(a, DateTimePicker).Format = DateTimePickerFormat.Custom
            TryCast(a, DateTimePicker).CustomFormat = "  -  -  "
            TryCast(a, DateTimePicker).Text = dt
        End If
</code>```

To change the date in a textbox I can do:

```<code>textbox.Text = result.ToString("dd-MMM-yyyy", New Globalization.CultureInfo("nl"))
</code>```

This is not working

```<code>TryCast(a, DateTimePicker).Text = dt.ToString("dd-MMM-yyyy", New Globalization.CultureInfo("nl"))
</code>```

I like May to show mei

答:
As per the docs, the DateTimePicker class's Text property returns the text representation of the Value property based on the format of the CustomFormat property.

The DateTime object (in this case, the Value property) does not store culture information, and the default ToString method (that is called within the get function of the Text property) will attempt to use the CurrentCulture of the application. You will need to find a way to pass the CultureInfo object into the get function for the Text property of the DateTimePicker object.

That is the reason why setting the text with

```<code>TryCast(a, DateTimePicker).Text = dt.ToString("dd-MMM-yyyy", New Globalization.CultureInfo("nl"))
</code>```

does not work.

You could potentially inherit or extend from the DateTimePicker class to create your own custom implementation that stores and uses the CultureInfo to properly display the date.

Body:
I can't get the datetimepicker text to show the abbreviation for the month in another language

I changed the regional settings for my PC to Dutch. That changes the month name from May to mei but I don't want to do that.

On start application:

CultureInfo.CurrentCulture = New CultureInfo("en-US", False)

ElseIf TypeOf a Is DateTimePicker Then
        If TableDataString(index) IsNot Nothing And TableDataString(index) <> "" Then
            Dim dt As Date = TableDataString(index).ToString
            TryCast(a, DateTimePicker).Format = DateTimePickerFormat.Custom
            TryCast(a, DateTimePicker).CustomFormat = "dd-MMM-yyyy"
            TryCast(a, DateTimePicker).Text = dt
        Else
            Dim dt As Date
            TryCast(a, DateTimePicker).Format = DateTimePickerFormat.Custom
            TryCast(a, DateTimePicker).CustomFormat = "  -  -  "
            TryCast(a, DateTimePicker).Text = dt
        End If

To change the date in a textbox I can do:

textbox.Text = result.ToString("dd-MMM-yyyy", New Globalization.CultureInfo("nl"))

This is not working

TryCast(a, DateTimePicker).Text = dt.ToString("dd-MMM-yyyy", New Globalization.CultureInfo("nl"))

I like May to show mei

Body:
As per the docs, the DateTimePicker class's Text property returns the text representation of the Value property based on the format of the CustomFormat property.

The DateTime object (in this case, the Value property) does not store culture information, and the default ToString method (that is called within the get function of the Text property) will attempt to use the CurrentCulture of the application. You will need to find a way to pass the CultureInfo object into the get function for the Text property of the DateTimePicker object.

That is the reason why setting the text with

TryCast(a, DateTimePicker).Text = dt.ToString("dd-MMM-yyyy", New Globalization.CultureInfo("nl"))

does not work.

You could potentially inherit or extend from the DateTimePicker class to create your own custom implementation that stores and uses the CultureInfo to properly display the date.


问:
Reactjs how to use ref inside map function?
I'm mapping through an array and for each item display a button with text. Say I want that on clicking the button, the text underneath will change its color to red. How can I target the sibling of the button? I tried using ref but since it's a mapped jsx, only the last ref element will be declared.

Here is my code:

```<code>class Exams extends React.Component {
    constructor(props) {
        super()
        this.accordionContent = null;
    }
    state = {
        examsNames: null, // fetched from a server
    }
    accordionToggle = () => {
        this.accordionContent.style.color = 'red'
    }
    render() {
        return (
            <div className="container">
                {this.state.examsNames && this.state.examsNames.map((inst, key) => (
                    <React.Fragment key={key}>
                        <button onClick={this.accordionToggle} className="inst-link"></button>
                        <div ref={accordionContent => this.accordionContent = accordionContent} className="accordionContent">
                            <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aperiam, neque.</p>
                        </div>
                    </React.Fragment>
                ))}
            </div>
        )
    }
}

export default Exams;
</code>```

As explained, the outcome is that on each button click, the paragraph attached to the last button will be targeted.

Thanks in advance

答:
Here is my working codepen example based on your code above

Linked example is an "actual" accordion, ie display and hide adjacent content.

(see code snippets below for turning to red)

https://codepen.io/PapaCodio/pen/XwxmvK?editors=0010

CODE SNIPPETS

initialize the referance array:

```<code>constructor(props) {
    super();
    this.accordionContent = [];
}
</code>```

add the ref to the reference array using the key:

```<code><div ref={ref => (this.accordionContent[key] = ref)} >
</code>```

pass the key to the toggle function via onClick

```<code> <button onClick={() => this.accordionToggle(key)} >
</code>```

finally reference the key inside the toggle function

```<code>accordionToggle = key => {
    this.accordionContent[key].style.color = 'red'
};
</code>```

Body:
I'm mapping through an array and for each item display a button with text. Say I want that on clicking the button, the text underneath will change its color to red. How can I target the sibling of the button? I tried using ref but since it's a mapped jsx, only the last ref element will be declared.

Here is my code:

class Exams extends React.Component {
    constructor(props) {
        super()
        this.accordionContent = null;
    }
    state = {
        examsNames: null, // fetched from a server
    }
    accordionToggle = () => {
        this.accordionContent.style.color = 'red'
    }
    render() {
        return (

                {this.state.examsNames && this.state.examsNames.map((inst, key) => (
                    <React.Fragment key={key}>
                        <button onClick={this.accordionToggle} className="inst-link"></button>

 this.accordionContent = accordionContent} className="accordionContent">

Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aperiam, neque.

                    </React.Fragment>
                ))}

        )
    }
}

export default Exams;

As explained, the outcome is that on each button click, the paragraph attached to the last button will be targeted.

Thanks in advance

Body:
Here is my working codepen example based on your code above

Linked example is an "actual" accordion, ie display and hide adjacent content.

(see code snippets below for turning to red)

https://codepen.io/PapaCodio/pen/XwxmvK?editors=0010

CODE SNIPPETS

initialize the referance array:

constructor(props) {
    super();
    this.accordionContent = [];
}

add the ref to the reference array using the key:

<div ref={ref => (this.accordionContent[key] = ref)} >

pass the key to the toggle function via onClick

 <button onClick={() => this.accordionToggle(key)} >

finally reference the key inside the toggle function

accordionToggle = key => {
    this.accordionContent[key].style.color = 'red'
};


问:
ImageMagick: How do I do a simple crop?
All I'm trying to do is crop images to a width of 1400 pixels from the left, but leave them at the same height.

The format should be width: 1400px, height 100% (unchanged), offset X and Y are both zero, so +0+0 (for X and Y):

```<code>convert -crop 1400x100%+0+0 inputfile outputfile
</code>```

This doesn't actually do anything! Can someone help me with my syntax?

答:
I figured it out. The 100% isn't necessary. It should be:

convert -crop 1400x+0+0 inputfile outputfile

Title: ImageMagick: How do I do a simple crop?

Body:
All I'm trying to do is crop images to a width of 1400 pixels from the left, but leave them at the same height.

The format should be width: 1400px, height 100% (unchanged), offset X and Y are both zero, so +0+0 (for X and Y):

convert -crop 1400x100%+0+0 inputfile outputfile

This doesn't actually do anything! Can someone help me with my syntax?


问:
What should $value be when I try to update a B2C Policy using the trustFrameWork API? PUT /trustFramework/policies/{id}/$value
I'm trying to update a B2C custom policy I've already POST'd to my B2C tenant.  The documentation at https://learn.microsoft.com/en-us/graph/api/trustframeworkpolicy-get?view=graph-rest-beta doesn't include any code samples and doesn't really explain what $value should be when performing a PUT /trustFramework/policies/{id}/$value

Can someone provide some insight as to what $value should be?

Thank you

答:
For the PUT operation, $value indicates you are replacing the raw content (i.e. the XML content) of the trust framework policy resource, so it doesn't have to be set to a specific value.

You should only have to set the Content-Type request header to application/xml and the request body to the XML content of the policy file.


问:
Multiply every third element of a list by two
Input data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Output data: [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]

I have read many answers where were suggested to use slice notation with including first element. But in my case I should take each 3rd element of the list.

Is it possible to improve my realization?

for index in range(len(data)):
    if (index + 1) % 3 == 0:
        data[index] = data[index] * 2
```

答:
You could use cycle from itertools and zip to pair items with their multipliers:

```<code>data   = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

from itertools import cycle
result = [n*m for n,m in zip(data,cycle([1,1,2]))]

# [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]
</code>```

OR, you can use enumerate()

```<code>result = [ n*max(1,i%3) for i,n in enumerate(data) ]
</code>```

Body:
You could use cycle from itertools and zip to pair items with their multipliers:

data   = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

from itertools import cycle
result = [n*m for n,m in zip(data,cycle([1,1,2]))]

# [1, 2, 6, 4, 5, 12, 7, 8, 18, 10]

OR, you can use enumerate()

result = [ n*max(1,i%3) for i,n in enumerate(data) ]


问:
How to pass reference to a WinForm control to a class when creating instance of this class?
How to pass a reference to a form object (i.e. TextBox) to a class, so I could specify what text box this instance needs to be working with when creating this instance?
Specific example:
I have a class that processes some text strings. I have few instances of this class.
I also have few text boxes on my form. I have a method in a class that shows some text in a text box. What do I need to do to tell to a specific instance of my class what text box to use when creating this instance? Should be in constructor, something like:

public MyClass (string textString, /ref to a text box/)

This is my class:

```<code> public class LogClass
{
    private readonly TextBox _textBox;

    private string logText;
    public string LogText
    {
        get
        {
            return logText;
        }

        set
        {
            logText = value;
        }
    }

    public void AddToLog(string textString)
    {

        try
        {
            if (string.IsNullOrEmpty(textString))
            {
                throw new ArgumentException("message", nameof(textString));
            }
            logText = logText+ "\n" + textString;
            _textBox.Text = logText;

        }
        catch (Exception)
        {

            throw;
        }

    }

    public LogClass(string initialText, TextBox textBox)
    {
        logText = initialText;
        _textBox = textBox;
        _textBox.Text = logText;

    }
}
</code>```

And this is my form:

```<code> public partial class LogWindow : Form
{

    LogClass myLog = new LogClass("this is initial string", logOutputBox);
    public LogWindow()
    {
        InitializeComponent();
    }

    public string LogTextToPass {
        get { return logOutputBox.Text; }
        set { logOutputBox.Text = value; }
    }

    private void buttonWriteLog_Click(object sender, EventArgs e)
    {
        myLog.AddToLog(inputText.Text);

    }

    private void logOutputBox_TextChanged(object sender, EventArgs e)
    {

    }
}
</code>```

Error CS0236 is on this line:

```<code>    LogClass myLog = new LogClass("this is initial string", logOutputBox);
</code>```

Error   CS0236  A field initializer cannot reference the non-static field, method, or property 'LogWindow.logOutputBox'
logOutputBox is highlighted

答:
It should be as easy as, passing a reference to it in the Constructor

Whenever a class or struct is created, its constructor is called. A
  class or struct may have multiple constructors that take different
  arguments. Constructors enable the programmer to set default values,
  limit instantiation, and write code that is flexible and easy to read.

```<code>public class MyLovelyHorse
{
   // private field of TextBox to play with internally
   private readonly TextBox _textbox;

   // constructor
   public MyLovelyHorse(TextBox textbox)
   {
      _textbox = textbox;
   }

   // some awesome method that does stuff
   public void SomeMethodThatDoesStuff()
   {
      _textbox.Text = "rah";
   }
}
</code>```

Usage

```<code>var myLovelyHorse = new MyLovelyHorse(MyTextBox);

// do stuff
myLovelyHorse.SomeMethodThatDoesStuff();
</code>```

Body:
How to pass a reference to a form object (i.e. TextBox) to a class, so I could specify what text box this instance needs to be working with when creating this instance?
Specific example:
I have a class that processes some text strings. I have few instances of this class.
I also have few text boxes on my form. I have a method in a class that shows some text in a text box. What do I need to do to tell to a specific instance of my class what text box to use when creating this instance? Should be in constructor, something like:

public MyClass (string textString, /ref to a text box/)

This is my class:

 public class LogClass
{
    private readonly TextBox _textBox;

    private string logText;
    public string LogText
    {
        get
        {
            return logText;
        }

        set
        {
            logText = value;
        }
    }

    public void AddToLog(string textString)
    {

        try
        {
            if (string.IsNullOrEmpty(textString))
            {
                throw new ArgumentException("message", nameof(textString));
            }
            logText = logText+ "\n" + textString;
            _textBox.Text = logText;

        }
        catch (Exception)
        {

            throw;
        }

    }

    public LogClass(string initialText, TextBox textBox)
    {
        logText = initialText;
        _textBox = textBox;
        _textBox.Text = logText;

    }
}

And this is my form:

 public partial class LogWindow : Form
{

    LogClass myLog = new LogClass("this is initial string", logOutputBox);
    public LogWindow()
    {
        InitializeComponent();
    }

    public string LogTextToPass {
        get { return logOutputBox.Text; }
        set { logOutputBox.Text = value; }
    }

    private void buttonWriteLog_Click(object sender, EventArgs e)
    {
        myLog.AddToLog(inputText.Text);

    }

    private void logOutputBox_TextChanged(object sender, EventArgs e)
    {

    }
}

Error CS0236 is on this line:

    LogClass myLog = new LogClass("this is initial string", logOutputBox);

Error   CS0236  A field initializer cannot reference the non-static field, method, or property 'LogWindow.logOutputBox'
logOutputBox is highlighted

Body:
It should be as easy as, passing a reference to it in the Constructor

Whenever a class or struct is created, its constructor is called. A
  class or struct may have multiple constructors that take different
  arguments. Constructors enable the programmer to set default values,
  limit instantiation, and write code that is flexible and easy to read.

public class MyLovelyHorse
{
   // private field of TextBox to play with internally
   private readonly TextBox _textbox;

   // constructor
   public MyLovelyHorse(TextBox textbox)
   {
      _textbox = textbox;
   }

   // some awesome method that does stuff
   public void SomeMethodThatDoesStuff()
   {
      _textbox.Text = "rah";
   }
}

Usage

var myLovelyHorse = new MyLovelyHorse(MyTextBox);

// do stuff
myLovelyHorse.SomeMethodThatDoesStuff();


问:
Button in data template not recognizinng command
Button in a data template with a command in a list view of items not working. I have tried other data templates with stack panel.
The button to search for the initial items will recognize it's command and work.

Here is the page with the data template for the items:

```<code><Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:local="clr-namespace:WpfFstApp1.Pages"
  xmlns:ViewModels="clr-namespace:WpfFstApp1.ViewModels" x:Class="WpfFstApp1.Pages.CsvPage"
  mc:Ignorable="d"
  d:DesignHeight="450" d:DesignWidth="800"
  Title="CsvPage">

<Page.DataContext>
    <ViewModels:CsvViewModel/>
</Page.DataContext>

<Page.Resources>
    <DataTemplate x:Key="CsvTemp">
        <ListView>
            <TextBlock Text="{Binding Dir}"/>
            <TextBlock Text="{Binding FiPath}"/>
            <Button Content="Click To Open" Command="{Binding OpenFiCommand, Mode=OneWay}" CommandParameter="{Binding SelResult.FiPath}"></Button>
            <ListView ItemsSource="{Binding Refs}"/>
        </ListView>
    </DataTemplate>
</Page.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="55"/>
        <RowDefinition/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>

    <TextBlock Text="Project" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top" Height="16" Width="37"/>
    <TextBlock Text="Sales Line" HorizontalAlignment="Left" Margin="65,5,0,0" VerticalAlignment="Top" Height="16" Width="52"/>
    <TextBlock Text="Part Number" HorizontalAlignment="Left" Margin="155,5,0,0" VerticalAlignment="Top" Height="16" Width="68"/>
    <TextBox x:Name="TxtBoxProj" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" VerticalAlignment="Top" Width="50"
             TextAlignment="Right" MaxLines="1" Text="{Binding SearchVal1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox x:Name="TxtBoxSline" HorizontalAlignment="Left" Height="23" Margin="65,26,0,0" VerticalAlignment="Top" Width="85" MaxLines="1" MaxLength="25"
             TextAlignment="Right" CharacterCasing="Upper" Text="{Binding SearchVal2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox x:Name="TxtBoxPart" HorizontalAlignment="Left" Height="23" Margin="155,26,0,0" VerticalAlignment="Top" Width="120"
             TextAlignment="Right" MaxLines="1" CharacterCasing="Upper" Text="{Binding SearchVal3, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

    <Button x:Name="BtnSrch" Content="Search" HorizontalAlignment="Left" Margin="280,29,0,0" VerticalAlignment="Top" Width="40" Command="{Binding SearchCommand, Mode=OneWay}"/>

    <ListView Margin="10" Grid.Row="1" ItemsSource="{Binding OcResults}" ItemTemplate="{Binding Mode=OneWay, Source={StaticResource CsvTemp}}" SelectedItem="{Binding SelResult}"/>

    <StatusBar Grid.Row="2" FontSize="14" Margin="1,0,1,1" VerticalAlignment="Bottom">
        <TextBlock x:Name="tsTxtBlck1" Text="{Binding CurStat1}" />
        <TextBlock x:Name="tsTxtBlck2" Text="{Binding CurStat2}"/>
    </StatusBar>

</Grid>
</code>```

Here is the Model :

```<code>class SearchResult
{
    public string Dir { get; set; }
    public string FiName { get; set; }
    public string FiPath { get; set; }
    public List<string> Refs { get; set; }
}
</code>```

Here is my ViewModel :

```<code>class CsvViewModel : ModelBase
{

    #region [ Declarations ]
    //
    bool Init = false;
    string CurDir = string.Empty;
    //Count of files traversed and timer for diagnostic output
    int fileCount = 0;
    Stopwatch sw;
    public List<SearchResult> ResList;
    //
    #endregion

    #region [ Properties ]
    //
    public ObservableCollection<SearchResult> OcResults { get; set; }
    //
    private string _curStat1;
    public string CurStat1
    {
        get { return _curStat1; }
        set { _curStat1 = value; OnPropertyChanged(nameof(CurStat1)); }
    }

    private string _curStat2;
    public string CurStat2
    {
        get { return _curStat2; }
        set { _curStat2 = value; OnPropertyChanged(nameof(CurStat2)); }
    }
    //
    private string _searchVal1 = string.Empty;
    public string SearchVal1
    {
        get { return _searchVal1; }
        set { _searchVal1 = value; OnPropertyChanged(nameof(SearchVal1)); }
    }

    private string _searchVal2 = string.Empty;
    public string SearchVal2
    {
        get { return _searchVal2; }
        set { _searchVal2 = value; OnPropertyChanged(nameof(SearchVal2)); }
    }

    private string _searchVal3 = string.Empty;
    public string SearchVal3
    {
        get { return _searchVal3; }
        set { _searchVal3 = value; OnPropertyChanged(nameof(SearchVal3)); }
    }
    //
    public RelCom SearchCommand { get; private set; }
    public RelCom OpenFiCommand { get; private set; }
    //
    private SearchResult selResult;
    public SearchResult SelResult
    {
        get { return selResult; }
        set { selResult = value; OnPropertyChanged(nameof(SelResult)); }
    }
    //
    #endregion

    public CsvViewModel()
    {
        ResList = new List<SearchResult>();
        OcResults = new ObservableCollection<SearchResult>();
        SearchCommand = new RelCom(Search_CanExecute, Search);
        OpenFiCommand = new RelCom(OpenFi_CanExecute, OpenFile);
    }

    private bool Search_CanExecute(object obj)
    {
        return true;
    }

    private void Search(object obj)
    {
        CurDir = string.Empty;
        //
        if (!string.IsNullOrWhiteSpace(SearchVal1))
            SearchVal2 = SearchVal1.Trim() + " " + SearchVal2.Trim();
        //
        if (!string.IsNullOrWhiteSpace(SearchVal3))
            SearchVal3 = SearchVal3.Trim();
        //
        try
        {
            TraverseTreeParallelForEach(@"\\ast-sigmanest\Feedback\Feedback", (f) =>
            {
                // Exceptions are no-ops.
                try
                {
                    // Do nothing with the data except read it to find string...
                    FileInfo fi1 = new FileInfo(f);
                    bool addfi = false;
                    //
                    string[] Lines = File.ReadAllLines(f);
                    List<string> refLines = new List<string>();
                    foreach (string line in Lines)
                    {
                        if (line.Contains(SearchVal2) & line.Contains(SearchVal3))
                        {
                            addfi = true;
                            refLines.Add(line);
                        }
                    }
                    //
                    if (addfi)
                    {
                        SearchResult Sres = new SearchResult { Dir = fi1.Directory.ToString(), FiName = fi1.Name, FiPath = fi1.FullName, Refs = refLines };
                        ResList.Add(Sres);
                    }
                    //
                    //contents = null;
                    Lines = null;
                    fi1 = null;
                    //
                }
                catch (FileNotFoundException) { }
                catch (IOException) { }
                catch (UnauthorizedAccessException) { }
                catch (SecurityException) { }
                // Display the filename.
                //Console.WriteLine(f);
            });
        }
        catch (ArgumentException Ae)
        {
            MessageBox.Show(Ae.Message);
        }
        //
        var resgrp = (from res in ResList group res by res.Dir into newres orderby newres.Key select newres);
        foreach (var rgrp in resgrp)
        {
            foreach (var res in rgrp)
            {
                OcResults.Add(res);
            }
        }
        //
    }

    private bool OpenFi_CanExecute(object obj)
    {
        return obj != null;
    }

    private void OpenFile(object obj)
    {
        Process.Start(new ProcessStartInfo(SelResult.FiPath));
    }

    public void TraverseTreeParallelForEach(string root, Action<string> action)
    {
        //Count of files traversed and timer for diagnostic output
        fileCount = 0;
        sw = Stopwatch.StartNew();

        // Determine whether to parallelize file processing on each folder based on processor count.
        int procCount = System.Environment.ProcessorCount;

        // Data structure to hold names of subfolders to be examined for files.
        Stack<string> dirs = new Stack<string>();

        if (!Directory.Exists(root))
        {
            throw new ArgumentException();
        }
        dirs.Push(root);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs = { };
            string[] files = { };

            try
            {
                subDirs = Directory.GetDirectories(currentDir);
                // Push the subdirectories onto the stack for traversal.
                // This could also be done before handing the files.
                foreach (string str in subDirs)
                    dirs.Push(str);
            }
            // Thrown if we do not have discovery permission on the directory.
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            // Thrown if another process has deleted the directory after we retrieved its name.
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            //
            try
            {
                files = Directory.GetFiles(currentDir, "*.csv");
            }
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (IOException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            //
            // Execute in parallel if there are enough files in the directory.
            // Otherwise, execute sequentially.Files are opened and processed
            // synchronously but this could be modified to perform async I/O.
            try
            {
                if (files.Length < procCount)
                {
                    foreach (var file in files)
                    {
                        action(file);
                        fileCount++;
                    }
                }
                else
                {
                    Parallel.ForEach(files, () => 0, (file, loopState, localCount) =>
                    {
                        action(file);
                        return (int)++localCount;
                    },
                                     (c) =>
                                     {
                                         Interlocked.Add(ref fileCount, c);
                                     });
                }
            }
            catch (AggregateException ae)
            {
                ae.Handle((ex) =>
                {
                    if (ex is UnauthorizedAccessException)
                    {
                        // Here we just output a message and go on.
                        Console.WriteLine(ex.Message);
                        return true;
                    }
                    // Handle other exceptions here if necessary...

                    return false;
                });
            }
            //
        }
        //
    }
}
</code>```

For some reason the button in the data template does not trigger the command, even though it shows to be bound to it.
Any help appreciated.
Thanks.

答:
You need to let the Open command know that the CanExecute conditions have changed, do this in your SelResult setter:

```<code>((RelayCommand<object>)OpenFiCommand).RaiseCanExecuteChanged();
</code>```

This is one of the reasons I don't like using CanExecute.

Body:
Button in a data template with a command in a list view of items not working. I have tried other data templates with stack panel.
The button to search for the initial items will recognize it's command and work.

Here is the page with the data template for the items:

<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:local="clr-namespace:WpfFstApp1.Pages"
  xmlns:ViewModels="clr-namespace:WpfFstApp1.ViewModels" x:Class="WpfFstApp1.Pages.CsvPage"
  mc:Ignorable="d"
  d:DesignHeight="450" d:DesignWidth="800"
  Title="CsvPage">

<Page.DataContext>
    <ViewModels:CsvViewModel/>
</Page.DataContext>

<Page.Resources>
    <DataTemplate x:Key="CsvTemp">
        <ListView>
            <TextBlock Text="{Binding Dir}"/>
            <TextBlock Text="{Binding FiPath}"/>
            <Button Content="Click To Open" Command="{Binding OpenFiCommand, Mode=OneWay}" CommandParameter="{Binding SelResult.FiPath}"></Button>
            <ListView ItemsSource="{Binding Refs}"/>
        </ListView>
    </DataTemplate>
</Page.Resources>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="55"/>
        <RowDefinition/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>

    <TextBlock Text="Project" HorizontalAlignment="Left" Margin="10,5,0,0" VerticalAlignment="Top" Height="16" Width="37"/>
    <TextBlock Text="Sales Line" HorizontalAlignment="Left" Margin="65,5,0,0" VerticalAlignment="Top" Height="16" Width="52"/>
    <TextBlock Text="Part Number" HorizontalAlignment="Left" Margin="155,5,0,0" VerticalAlignment="Top" Height="16" Width="68"/>
    <TextBox x:Name="TxtBoxProj" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" VerticalAlignment="Top" Width="50"
             TextAlignment="Right" MaxLines="1" Text="{Binding SearchVal1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox x:Name="TxtBoxSline" HorizontalAlignment="Left" Height="23" Margin="65,26,0,0" VerticalAlignment="Top" Width="85" MaxLines="1" MaxLength="25"
             TextAlignment="Right" CharacterCasing="Upper" Text="{Binding SearchVal2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <TextBox x:Name="TxtBoxPart" HorizontalAlignment="Left" Height="23" Margin="155,26,0,0" VerticalAlignment="Top" Width="120"
             TextAlignment="Right" MaxLines="1" CharacterCasing="Upper" Text="{Binding SearchVal3, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

    <Button x:Name="BtnSrch" Content="Search" HorizontalAlignment="Left" Margin="280,29,0,0" VerticalAlignment="Top" Width="40" Command="{Binding SearchCommand, Mode=OneWay}"/>

    <ListView Margin="10" Grid.Row="1" ItemsSource="{Binding OcResults}" ItemTemplate="{Binding Mode=OneWay, Source={StaticResource CsvTemp}}" SelectedItem="{Binding SelResult}"/>

    <StatusBar Grid.Row="2" FontSize="14" Margin="1,0,1,1" VerticalAlignment="Bottom">
        <TextBlock x:Name="tsTxtBlck1" Text="{Binding CurStat1}" />
        <TextBlock x:Name="tsTxtBlck2" Text="{Binding CurStat2}"/>
    </StatusBar>

</Grid>

Here is the Model :

class SearchResult
{
    public string Dir { get; set; }
    public string FiName { get; set; }
    public string FiPath { get; set; }
    public List<string> Refs { get; set; }
}

Here is my ViewModel :

class CsvViewModel : ModelBase
{

    #region [ Declarations ]
    //
    bool Init = false;
    string CurDir = string.Empty;
    //Count of files traversed and timer for diagnostic output
    int fileCount = 0;
    Stopwatch sw;
    public List<SearchResult> ResList;
    //
    #endregion

    #region [ Properties ]
    //
    public ObservableCollection<SearchResult> OcResults { get; set; }
    //
    private string _curStat1;
    public string CurStat1
    {
        get { return _curStat1; }
        set { _curStat1 = value; OnPropertyChanged(nameof(CurStat1)); }
    }

    private string _curStat2;
    public string CurStat2
    {
        get { return _curStat2; }
        set { _curStat2 = value; OnPropertyChanged(nameof(CurStat2)); }
    }
    //
    private string _searchVal1 = string.Empty;
    public string SearchVal1
    {
        get { return _searchVal1; }
        set { _searchVal1 = value; OnPropertyChanged(nameof(SearchVal1)); }
    }

    private string _searchVal2 = string.Empty;
    public string SearchVal2
    {
        get { return _searchVal2; }
        set { _searchVal2 = value; OnPropertyChanged(nameof(SearchVal2)); }
    }

    private string _searchVal3 = string.Empty;
    public string SearchVal3
    {
        get { return _searchVal3; }
        set { _searchVal3 = value; OnPropertyChanged(nameof(SearchVal3)); }
    }
    //
    public RelCom SearchCommand { get; private set; }
    public RelCom OpenFiCommand { get; private set; }
    //
    private SearchResult selResult;
    public SearchResult SelResult
    {
        get { return selResult; }
        set { selResult = value; OnPropertyChanged(nameof(SelResult)); }
    }
    //
    #endregion

    public CsvViewModel()
    {
        ResList = new List<SearchResult>();
        OcResults = new ObservableCollection<SearchResult>();
        SearchCommand = new RelCom(Search_CanExecute, Search);
        OpenFiCommand = new RelCom(OpenFi_CanExecute, OpenFile);
    }

    private bool Search_CanExecute(object obj)
    {
        return true;
    }

    private void Search(object obj)
    {
        CurDir = string.Empty;
        //
        if (!string.IsNullOrWhiteSpace(SearchVal1))
            SearchVal2 = SearchVal1.Trim() + " " + SearchVal2.Trim();
        //
        if (!string.IsNullOrWhiteSpace(SearchVal3))
            SearchVal3 = SearchVal3.Trim();
        //
        try
        {
            TraverseTreeParallelForEach(@"\\ast-sigmanest\Feedback\Feedback", (f) =>
            {
                // Exceptions are no-ops.
                try
                {
                    // Do nothing with the data except read it to find string...
                    FileInfo fi1 = new FileInfo(f);
                    bool addfi = false;
                    //
                    string[] Lines = File.ReadAllLines(f);
                    List<string> refLines = new List<string>();
                    foreach (string line in Lines)
                    {
                        if (line.Contains(SearchVal2) & line.Contains(SearchVal3))
                        {
                            addfi = true;
                            refLines.Add(line);
                        }
                    }
                    //
                    if (addfi)
                    {
                        SearchResult Sres = new SearchResult { Dir = fi1.Directory.ToString(), FiName = fi1.Name, FiPath = fi1.FullName, Refs = refLines };
                        ResList.Add(Sres);
                    }
                    //
                    //contents = null;
                    Lines = null;
                    fi1 = null;
                    //
                }
                catch (FileNotFoundException) { }
                catch (IOException) { }
                catch (UnauthorizedAccessException) { }
                catch (SecurityException) { }
                // Display the filename.
                //Console.WriteLine(f);
            });
        }
        catch (ArgumentException Ae)
        {
            MessageBox.Show(Ae.Message);
        }
        //
        var resgrp = (from res in ResList group res by res.Dir into newres orderby newres.Key select newres);
        foreach (var rgrp in resgrp)
        {
            foreach (var res in rgrp)
            {
                OcResults.Add(res);
            }
        }
        //
    }

    private bool OpenFi_CanExecute(object obj)
    {
        return obj != null;
    }

    private void OpenFile(object obj)
    {
        Process.Start(new ProcessStartInfo(SelResult.FiPath));
    }

    public void TraverseTreeParallelForEach(string root, Action<string> action)
    {
        //Count of files traversed and timer for diagnostic output
        fileCount = 0;
        sw = Stopwatch.StartNew();

        // Determine whether to parallelize file processing on each folder based on processor count.
        int procCount = System.Environment.ProcessorCount;

        // Data structure to hold names of subfolders to be examined for files.
        Stack<string> dirs = new Stack<string>();

        if (!Directory.Exists(root))
        {
            throw new ArgumentException();
        }
        dirs.Push(root);

        while (dirs.Count > 0)
        {
            string currentDir = dirs.Pop();
            string[] subDirs = { };
            string[] files = { };

            try
            {
                subDirs = Directory.GetDirectories(currentDir);
                // Push the subdirectories onto the stack for traversal.
                // This could also be done before handing the files.
                foreach (string str in subDirs)
                    dirs.Push(str);
            }
            // Thrown if we do not have discovery permission on the directory.
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            // Thrown if another process has deleted the directory after we retrieved its name.
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            //
            try
            {
                files = Directory.GetFiles(currentDir, "*.csv");
            }
            catch (UnauthorizedAccessException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (DirectoryNotFoundException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            catch (IOException e)
            {
                Console.WriteLine(e.Message);
                continue;
            }
            //
            // Execute in parallel if there are enough files in the directory.
            // Otherwise, execute sequentially.Files are opened and processed
            // synchronously but this could be modified to perform async I/O.
            try
            {
                if (files.Length < procCount)
                {
                    foreach (var file in files)
                    {
                        action(file);
                        fileCount++;
                    }
                }
                else
                {
                    Parallel.ForEach(files, () => 0, (file, loopState, localCount) =>
                    {
                        action(file);
                        return (int)++localCount;
                    },
                                     (c) =>
                                     {
                                         Interlocked.Add(ref fileCount, c);
                                     });
                }
            }
            catch (AggregateException ae)
            {
                ae.Handle((ex) =>
                {
                    if (ex is UnauthorizedAccessException)
                    {
                        // Here we just output a message and go on.
                        Console.WriteLine(ex.Message);
                        return true;
                    }
                    // Handle other exceptions here if necessary...

                    return false;
                });
            }
            //
        }
        //
    }
}

For some reason the button in the data template does not trigger the command, even though it shows to be bound to it.
Any help appreciated.
Thanks.

Body:
You need to let the Open command know that the CanExecute conditions have changed, do this in your SelResult setter:

((RelayCommand<object>)OpenFiCommand).RaiseCanExecuteChanged();

This is one of the reasons I don't like using CanExecute.


问:
Utilizing a string from an array to a function as a variable
I want to use some string from an array and pass it into a function. The string has the same name as a global variable. From there, I want to set the output to the variable name. It is being passed to a slider function where the variable should update upon any changes.

I've tried passing it through [window] or eval(), but it does not work. Ideally, in the createSliders() function, on slide the global var would update.

```<code>i_current_annual_volume = 1000000;

let sliderArr = [{
   input: "i_current_annual_volume" (or window[i_current_annual_volume]),
   value: 1000000,
   min: 1000,
   max: 10000000,
   step: 1000,
}];

function createSliders() {
  for ( var i = 0; i < sliderArr.length; i++ ){
    let slider_name = "#slider-" + [i + 1];
    let handle_name = "#custom-handle-" + [i + 1];
    let input_field = sliderArr[ i ].input;

    $( slider_name ).slider({
      value: sliderArr[ i ].value,
      min: sliderArr[ i ].min,
      max: sliderArr[ i ].max,
      step: sliderArr[ i ].step,
      create: function() {
        $( handle_name ).text( $( this ).slider( "value" ) );
      },
      slide: function( event, ui ) {
        $( handle_name ).text( ui.value );
        input_field = ui.value;
      },
      stop: function(){
        loadNumbers();
      }
    });
  }
};

When I remove the quotes in the sliderArr, the output is 1000000. I need it to be i_current_annual_volume.
</code>```

答:
You said you tried to use window, but you didn't show how you tried to do it. Global variables are properties of the window object. See Use dynamic variable names in JavaScript

Change

```<code>        input_field = ui.value;
</code>```

to

```<code>        window[input_field] = ui.value;
</code>```

Body:
I want to use some string from an array and pass it into a function. The string has the same name as a global variable. From there, I want to set the output to the variable name. It is being passed to a slider function where the variable should update upon any changes.

I've tried passing it through [window] or eval(), but it does not work. Ideally, in the createSliders() function, on slide the global var would update.

i_current_annual_volume = 1000000;

let sliderArr = [{
   input: "i_current_annual_volume" (or window[i_current_annual_volume]),
   value: 1000000,
   min: 1000,
   max: 10000000,
   step: 1000,
}];

function createSliders() {
  for ( var i = 0; i < sliderArr.length; i++ ){
    let slider_name = "#slider-" + [i + 1];
    let handle_name = "#custom-handle-" + [i + 1];
    let input_field = sliderArr[ i ].input;

    $( slider_name ).slider({
      value: sliderArr[ i ].value,
      min: sliderArr[ i ].min,
      max: sliderArr[ i ].max,
      step: sliderArr[ i ].step,
      create: function() {
        $( handle_name ).text( $( this ).slider( "value" ) );
      },
      slide: function( event, ui ) {
        $( handle_name ).text( ui.value );
        input_field = ui.value;
      },
      stop: function(){
        loadNumbers();
      }
    });
  }
};

When I remove the quotes in the sliderArr, the output is 1000000. I need it to be i_current_annual_volume.

Body:
You said you tried to use window, but you didn't show how you tried to do it. Global variables are properties of the window object. See Use dynamic variable names in JavaScript

Change

        input_field = ui.value;

to

        window[input_field] = ui.value;


问:
SQL Server 2017 C++ ODBC connection not working on Linux
We are using an Azure SQL Server 2017 database and wish to connect to it via c++. We have already achieved this incredible feat on windows but it is necessary to run this on ubuntu.

We installed the Linux ODBC 13 driver using this tutorial and our /etc/odbcinst.ini file contains the following

```<code>[ODBC Driver 13 for SQL Server]
Description=Microsoft ODBC Driver 13 for SQL Server
Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.0.so.1.0
UsageCount=1

[ODBC]
Trace = Yes
TraceFile = /dev/stdout
</code>```

Our code is as follows:

```<code>#include <iostream>
#include <string>
#include <sqlext.h>
#include <sqltypes.h>
#include <sql.h>
#include <stdio.h>

using namespace std;

int main() {

    #define SQL_RESULT_LEN 240
    #define SQL_RETURN_CODE_LEN 1024

    //define handles and variables
    SQLHDBC      hdbc = SQL_NULL_HDBC;   // Connection handle
    SQLHANDLE    sqlConnHandle = NULL;
    SQLHANDLE    sqlStmtHandle = NULL;
    SQLHANDLE    sqlEnvHandle;
    SQLCHAR      outstr[SQL_RETURN_CODE_LEN];
    SQLRETURN    retcode;
    SQLSMALLINT  outstrlen;

    //allocations
    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlEnvHandle))
        cout << "SQLAllocHandle err (ENV)" << endl;

    if (SQL_SUCCESS != SQLSetEnvAttr(sqlEnvHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
        cout << "SQLSetEnvAttr err" << endl;

    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, sqlEnvHandle, &sqlConnHandle))
        cout << "SQLAllocHandle (DBC) err" << endl;

    //output
    cout << "Attempting connection to SQL Server..." << endl;

    //Connect to server

    retcode = SQLDriverConnect(hdbc, NULL, (SQLCHAR *)"Driver={ODBC Driver 13 for SQL Server};Server=tcp:cppdatabase.database.windows.net,1433;Database=stockData;Uid=admin@cppdatabase;Pwd=password;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;", SQL_NTS, outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_NOPROMPT);

    switch (retcode) {

    case SQL_SUCCESS:
        cout << "Successfully connected to SQL Server" << endl;
        break;

    case SQL_SUCCESS_WITH_INFO:
        cout << "Successfully connected to SQL Server"<< endl;
        break;

    case SQL_INVALID_HANDLE:
        cout << "Could not connect to SQL Server" << endl;
        break;

    case SQL_ERROR:
        cout << "Could not connect to SQL Server ERR" << endl;
        break;

    default:
        break;
    }
}
</code>```

Which we compile with g++ as follows: g++ -g mssql.cpp -fpermissive -lodbc -o mssql

This code however fails to connect and we get the following output (no compiling errors):

```<code>[ODBC][17915][1559000402.543184][__handles.c][460]
        Exit:[SQL_SUCCESS]
            Environment = 0xf04d10
[ODBC][17915][1559000402.543204][SQLSetEnvAttr.c][189]
        Entry:
            Environment = 0xf04d10
            Attribute = SQL_ATTR_ODBC_VERSION
            Value = 0x3
            StrLen = 0
[ODBC][17915][1559000402.543216][SQLSetEnvAttr.c][363]
        Exit:[SQL_SUCCESS]
[ODBC][17915][1559000402.543223][SQLAllocHandle.c][375]
        Entry:
            Handle Type = 2
            Input Handle = 0xf04d10
[ODBC][17915][1559000402.543232][SQLAllocHandle.c][493]
        Exit:[SQL_SUCCESS]
            Output Handle = 0xf05610
Attempting connection to SQL Server...
[ODBC][17915][1559000402.543250][SQLDriverConnect.c][686]Error: SQL_INVALID_HANDLE
Could not connect to SQL Server
Could not connect to SQL Server ERR

</code>```

The connection string we used came directly from the Azure portal (while the sensitive data has been replaced with generic variants) so we doubt there is any issue with that. We doubt it is a driver issue as ODBC successfully logs to stdout. So we imagine it must be a coding problem.

Any pointers (no pun intended)?

答:
We solved it using a Domain Source Name (DNS). In our /etc/odbc.ini file we wrote:

```<code>[mssql]
Description = "Test for Microsoft SQL Server 2017 using ODBC 2013 driver"
Driver = /opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.0.so.1.0
Database = stockData
Server = cppdatabase.database.windows.net
Port = 1433
</code>```

And then we connected using the following code:

```<code>#include <iostream>
#include <string>
#include <sqlext.h>
#include <sqltypes.h>
#include <sql.h>
#include <stdio.h>
#include <cstdlib>

using namespace std;

int main() {
   SQLHENV henv;
   SQLHDBC hdbc;
   SQLHSTMT hstmt;
   SQLRETURN retcode;

   SQLCHAR * OutConnStr = (SQLCHAR * )malloc(255);
   SQLSMALLINT * OutConnStrLen = (SQLSMALLINT *)malloc(255);

   // Allocate environment handle
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

   // Set the ODBC version environment attribute
   if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
      retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

      // Allocate connection handle
      if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
         retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

         // Set login timeout to 5 seconds
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
            SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

            // Connect to data source
            retcode = SQLConnect(hdbc, (SQLCHAR*) "mssql", SQL_NTS, (SQLCHAR*) "QuantitateAdmin", 15, "SomeRandomPassword1", 19);

            // Allocate statement handle
            if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

                cout << "Success!" << endl;

               retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

               // Process data
               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
                  SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
               }

               SQLDisconnect(hdbc);
            } else {
                cout << "Error" << endl;
            }

            SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
         }
      }
      SQLFreeHandle(SQL_HANDLE_ENV, henv);
   }
}
</code>```

Body:
We are using an Azure SQL Server 2017 database and wish to connect to it via c++. We have already achieved this incredible feat on windows but it is necessary to run this on ubuntu.

We installed the Linux ODBC 13 driver using this tutorial and our /etc/odbcinst.ini file contains the following

[ODBC Driver 13 for SQL Server]
Description=Microsoft ODBC Driver 13 for SQL Server
Driver=/opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.0.so.1.0
UsageCount=1

[ODBC]
Trace = Yes
TraceFile = /dev/stdout

Our code is as follows:

#include <iostream>
#include <string>
#include <sqlext.h>
#include <sqltypes.h>
#include <sql.h>
#include <stdio.h>

using namespace std;

int main() {

    #define SQL_RESULT_LEN 240
    #define SQL_RETURN_CODE_LEN 1024

    //define handles and variables
    SQLHDBC      hdbc = SQL_NULL_HDBC;   // Connection handle
    SQLHANDLE    sqlConnHandle = NULL;
    SQLHANDLE    sqlStmtHandle = NULL;
    SQLHANDLE    sqlEnvHandle;
    SQLCHAR      outstr[SQL_RETURN_CODE_LEN];
    SQLRETURN    retcode;
    SQLSMALLINT  outstrlen;

    //allocations
    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlEnvHandle))
        cout << "SQLAllocHandle err (ENV)" << endl;

    if (SQL_SUCCESS != SQLSetEnvAttr(sqlEnvHandle, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0))
        cout << "SQLSetEnvAttr err" << endl;

    if (SQL_SUCCESS != SQLAllocHandle(SQL_HANDLE_DBC, sqlEnvHandle, &sqlConnHandle))
        cout << "SQLAllocHandle (DBC) err" << endl;

    //output
    cout << "Attempting connection to SQL Server..." << endl;

    //Connect to server

    retcode = SQLDriverConnect(hdbc, NULL, (SQLCHAR *)"Driver={ODBC Driver 13 for SQL Server};Server=tcp:cppdatabase.database.windows.net,1433;Database=stockData;Uid=admin@cppdatabase;Pwd=password;Encrypt=yes;TrustServerCertificate=no;Connection Timeout=30;", SQL_NTS, outstr, sizeof(outstr), &outstrlen, SQL_DRIVER_NOPROMPT);

    switch (retcode) {

    case SQL_SUCCESS:
        cout << "Successfully connected to SQL Server" << endl;
        break;

    case SQL_SUCCESS_WITH_INFO:
        cout << "Successfully connected to SQL Server"<< endl;
        break;

    case SQL_INVALID_HANDLE:
        cout << "Could not connect to SQL Server" << endl;
        break;

    case SQL_ERROR:
        cout << "Could not connect to SQL Server ERR" << endl;
        break;

    default:
        break;
    }
}

Which we compile with g++ as follows: g++ -g mssql.cpp -fpermissive -lodbc -o mssql

This code however fails to connect and we get the following output (no compiling errors):

[ODBC][17915][1559000402.543184][__handles.c][460]
        Exit:[SQL_SUCCESS]
            Environment = 0xf04d10
[ODBC][17915][1559000402.543204][SQLSetEnvAttr.c][189]
        Entry:
            Environment = 0xf04d10
            Attribute = SQL_ATTR_ODBC_VERSION
            Value = 0x3
            StrLen = 0
[ODBC][17915][1559000402.543216][SQLSetEnvAttr.c][363]
        Exit:[SQL_SUCCESS]
[ODBC][17915][1559000402.543223][SQLAllocHandle.c][375]
        Entry:
            Handle Type = 2
            Input Handle = 0xf04d10
[ODBC][17915][1559000402.543232][SQLAllocHandle.c][493]
        Exit:[SQL_SUCCESS]
            Output Handle = 0xf05610
Attempting connection to SQL Server...
[ODBC][17915][1559000402.543250][SQLDriverConnect.c][686]Error: SQL_INVALID_HANDLE
Could not connect to SQL Server
Could not connect to SQL Server ERR

The connection string we used came directly from the Azure portal (while the sensitive data has been replaced with generic variants) so we doubt there is any issue with that. We doubt it is a driver issue as ODBC successfully logs to stdout. So we imagine it must be a coding problem.

Any pointers (no pun intended)?

Body:
We solved it using a Domain Source Name (DNS). In our /etc/odbc.ini file we wrote:

[mssql]
Description = "Test for Microsoft SQL Server 2017 using ODBC 2013 driver"
Driver = /opt/microsoft/msodbcsql/lib64/libmsodbcsql-13.0.so.1.0
Database = stockData
Server = cppdatabase.database.windows.net
Port = 1433

And then we connected using the following code:

#include <iostream>
#include <string>
#include <sqlext.h>
#include <sqltypes.h>
#include <sql.h>
#include <stdio.h>
#include <cstdlib>

using namespace std;

int main() {
   SQLHENV henv;
   SQLHDBC hdbc;
   SQLHSTMT hstmt;
   SQLRETURN retcode;

   SQLCHAR * OutConnStr = (SQLCHAR * )malloc(255);
   SQLSMALLINT * OutConnStrLen = (SQLSMALLINT *)malloc(255);

   // Allocate environment handle
   retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

   // Set the ODBC version environment attribute
   if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
      retcode = SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, 0);

      // Allocate connection handle
      if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
         retcode = SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

         // Set login timeout to 5 seconds
         if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
            SQLSetConnectAttr(hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0);

            // Connect to data source
            retcode = SQLConnect(hdbc, (SQLCHAR*) "mssql", SQL_NTS, (SQLCHAR*) "QuantitateAdmin", 15, "SomeRandomPassword1", 19);

            // Allocate statement handle
            if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {

                cout << "Success!" << endl;

               retcode = SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

               // Process data
               if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) {
                  SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
               }

               SQLDisconnect(hdbc);
            } else {
                cout << "Error" << endl;
            }

            SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
         }
      }
      SQLFreeHandle(SQL_HANDLE_ENV, henv);
   }
}


问:
Screen scraping web page after delay
I'm trying to scrape a web page using C#, however after the page loads, it executes some JavaScript which loads more elements into the DOM which I need to scrape. A standard scraper simply grabs the html of the page on load and doesn't pick up the DOM changes made via JavaScript. How do I put in some sort of functionality to wait for a second or two and then grab the source?

Here is my current code:

private string ScrapeWebpage(string url, DateTime? updateDate)
{
    HttpWebRequest request = null;
    HttpWebResponse response = null;
    Stream responseStream = null;
    StreamReader reader = null;
    string html = null;
    try
    {
        //create request (which supports http compression)
        request = (HttpWebRequest)WebRequest.Create(url);
        request.Pipelined = true;
        request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
        if (updateDate != null)
            request.IfModifiedSince = updateDate.Value;
        //get response.
        response = (HttpWebResponse)request.GetResponse();
        responseStream = response.GetResponseStream();
        if (response.ContentEncoding.ToLower().Contains("gzip"))
            responseStream = new GZipStream(responseStream,
                CompressionMode.Decompress);
        else if (response.ContentEncoding.ToLower().Contains("deflate"))
            responseStream = new DeflateStream(responseStream,
                CompressionMode.Decompress);
        //read html.
        reader = new StreamReader(responseStream, Encoding.Default);
        html = reader.ReadToEnd();
    }
    catch
    {
        throw;
    }
    finally
    {
        //dispose of objects.
        request = null;
        if (response != null)
        {
            response.Close();
            response = null;
        }
        if (responseStream != null)
        {
            responseStream.Close();
            responseStream.Dispose();
        }
        if (reader != null)
        {
            reader.Close();
            reader.Dispose();
        }
    }
    return html;
}
```

Here's a sample URL:

http://www.realtor.com/realestateandhomes-search/geneva_ny#listingType-any/pg-4

You'll see when the page first loads it says 134 listings found, then after a second it says 187 properties found.

答:
The approach you have will not work regardless how long you wait, you need a browser to execute the javascript (or something that understands javascript).

Try this question:
What's a good tool to screen-scrape with Javascript support?

Title: Screen scraping web page after delay

Body:
I'm trying to scrape a web page using C#, however after the page loads, it executes some JavaScript which loads more elements into the DOM which I need to scrape. A standard scraper simply grabs the html of the page on load and doesn't pick up the DOM changes made via JavaScript. How do I put in some sort of functionality to wait for a second or two and then grab the source?

Here is my current code:

private string ScrapeWebpage(string url, DateTime? updateDate)
{
    HttpWebRequest request = null;
    HttpWebResponse response = null;
    Stream responseStream = null;
    StreamReader reader = null;
    string html = null;
    try
    {
        //create request (which supports http compression)
        request = (HttpWebRequest)WebRequest.Create(url);
        request.Pipelined = true;
        request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
        if (updateDate != null)
            request.IfModifiedSince = updateDate.Value;
        //get response.
        response = (HttpWebResponse)request.GetResponse();
        responseStream = response.GetResponseStream();
        if (response.ContentEncoding.ToLower().Contains("gzip"))
            responseStream = new GZipStream(responseStream,
                CompressionMode.Decompress);
        else if (response.ContentEncoding.ToLower().Contains("deflate"))
            responseStream = new DeflateStream(responseStream,
                CompressionMode.Decompress);
        //read html.
        reader = new StreamReader(responseStream, Encoding.Default);
        html = reader.ReadToEnd();
    }
    catch
    {
        throw;
    }
    finally
    {
        //dispose of objects.
        request = null;
        if (response != null)
        {
            response.Close();
            response = null;
        }
        if (responseStream != null)
        {
            responseStream.Close();
            responseStream.Dispose();
        }
        if (reader != null)
        {
            reader.Close();
            reader.Dispose();
        }
    }
    return html;
}

Here's a sample URL:

http://www.realtor.com/realestateandhomes-search/geneva_ny#listingType-any/pg-4

You'll see when the page first loads it says 134 listings found, then after a second it says 187 properties found.