问:
C# windows form button to execute SQL Query
I'm new to programming so please bear with me as I learn. I've been looking for days for a way to make this work, trying different solutions that I have found on here and other sites. I am using user input to create my connection string, and button 1 works great to verify that a connection has been established, button 2 not so much. I am trying to create a button that once pushed will execute a SQL command and provide the results from the command.

This is what I have so far, its button 2 that I have not been able to get to work yet.

using Microsoft.AspNet.SignalR.Infrastructure;
using Microsoft.SqlServer.Server;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

       private void Form1_Load(object sender, EventArgs e)
       {

       }

       private void textBox1_TextChanged(object sender, EventArgs e)
       {

       }

       private void textBox2_TextChanged(object sender, EventArgs e)
       {

       }

       private void textBox3_TextChanged(object sender, EventArgs e)
       {

       }
       private void textBox4_TextChanged(object sender, EventArgs e)
       {

       }
       private void textBox5_TextChanged(object sender, EventArgs e)
       {

       }

       private void button1_Click(object sender, EventArgs e)
       {
           {
               string ServerName = textBox1.Text;
               string Database = textBox2.Text;
               string Username = textBox3.Text;
               string Pass = textBox4.Text;

               string connetionString;
               SqlConnection cnn;
               connetionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";
               cnn = new SqlConnection(connetionString);
               try
               {
                   cnn.Open();
                   MessageBox.Show("Connection Open  !");
                   cnn.Close();
               }
               catch (Exception) { MessageBox.Show("Login Failed, Information is Incorrect"); }
           }
       }

       private void button2_Click(object sender, EventArgs e)
       {
           string ServerName = textBox1.Text;
           string Database = textBox2.Text;
           string Username = textBox3.Text;
           string Pass = textBox4.Text;
           string results = textBox5.Text;

           string connetionString;
           SqlConnection cnn;
           connetionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";
           string userInput = "";
           var process = new Process();
           var startInfo = new ProcessStartInfo();
           startInfo.WindowStyle = ProcessWindowStyle.Hidden;
           startInfo.FileName = "cmd.exe";
           startInfo.Arguments = string.Format(@"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + "; "" SELECT count(*) from participanthistory, SELECT count(*) from postransaction where communicated = 0, userInput);

           process.StartInfo = startInfo;
           process.Start();
       }

       }

   }
```

<p>I am trying to get the button to run this sql:</p>

<pre class="lang-sql prettyprint-override"><code>select count(*) from history
select count(*) from results where communicated = 0
</code>```

I can run the SQL Query in SSMS no problem its just getting it to launch from the GUI I'm creating.

Any help is greatly appreciated.

答:
I wanted to say that I appreciate all the help and patience from everyone on here, I was able to get this resolved on another board and wanted to share the results encase someone else needs assistance with it.

```<code>using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {

        }
        private void textBox4_TextChanged(object sender, EventArgs e)
        {

        }
        private void textBox5_TextChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            {
                string ServerName = textBox1.Text;
                string Database = textBox2.Text;
                string Username = textBox3.Text;
                string Pass = textBox4.Text;

                string connetionString;
                SqlConnection cnn;
                connetionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";
                cnn = new SqlConnection(connetionString);
                try
                {
                    cnn.Open();
                    MessageBox.Show("Connection Open  !");
                    cnn.Close();
                }
                catch (Exception) { MessageBox.Show("Login Failed, Information is Incorrect"); }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string ServerName = textBox1.Text;
            string Database = textBox2.Text;
            string Username = textBox3.Text;
            string Pass = textBox4.Text;
            SqlConnection connection = new SqlConnection();

            connection.ConnectionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";

            SqlCommand command = new SqlCommand();

            command.Connection = connection;
            command.CommandText = "--your SQL query --";
            command.CommandType = CommandType.Text;

            try
            {
                connection.Open();

                SqlDataReader reader = command.ExecuteReader();

                while (reader.Read())
                {
                    int CommunicatedRecordsCount = (int)reader[0];
                    textBox5.Text = CommunicatedRecordsCount.ToString();
                }

                reader.Close();
            }
            catch
            {
            }
            finally
            {
                if (connection.State == ConnectionState.Open)
                    connection.Close();
            }
        }
    }
}
</code>```

Where I was looking for a numerical output we changed the output slightly, but again thanks everyone for all the assistance.

Body:
I'm new to programming so please bear with me as I learn. I've been looking for days for a way to make this work, trying different solutions that I have found on here and other sites. I am using user input to create my connection string, and button 1 works great to verify that a connection has been established, button 2 not so much. I am trying to create a button that once pushed will execute a SQL command and provide the results from the command.

This is what I have so far, its button 2 that I have not been able to get to work yet.

using Microsoft.AspNet.SignalR.Infrastructure;
using Microsoft.SqlServer.Server;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
   public partial class Form1 : Form
   {
       public Form1()
       {
           InitializeComponent();
       }

       private void Form1_Load(object sender, EventArgs e)
       {

       }

       private void textBox1_TextChanged(object sender, EventArgs e)
       {

       }

       private void textBox2_TextChanged(object sender, EventArgs e)
       {

       }

       private void textBox3_TextChanged(object sender, EventArgs e)
       {

       }
       private void textBox4_TextChanged(object sender, EventArgs e)
       {

       }
       private void textBox5_TextChanged(object sender, EventArgs e)
       {

       }

       private void button1_Click(object sender, EventArgs e)
       {
           {
               string ServerName = textBox1.Text;
               string Database = textBox2.Text;
               string Username = textBox3.Text;
               string Pass = textBox4.Text;

               string connetionString;
               SqlConnection cnn;
               connetionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";
               cnn = new SqlConnection(connetionString);
               try
               {
                   cnn.Open();
                   MessageBox.Show("Connection Open  !");
                   cnn.Close();
               }
               catch (Exception) { MessageBox.Show("Login Failed, Information is Incorrect"); }
           }
       }

       private void button2_Click(object sender, EventArgs e)
       {
           string ServerName = textBox1.Text;
           string Database = textBox2.Text;
           string Username = textBox3.Text;
           string Pass = textBox4.Text;
           string results = textBox5.Text;

           string connetionString;
           SqlConnection cnn;
           connetionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";
           string userInput = "";
           var process = new Process();
           var startInfo = new ProcessStartInfo();
           startInfo.WindowStyle = ProcessWindowStyle.Hidden;
           startInfo.FileName = "cmd.exe";
           startInfo.Arguments = string.Format(@"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + "; "" SELECT count(*) from participanthistory, SELECT count(*) from postransaction where communicated = 0, userInput);

           process.StartInfo = startInfo;
           process.Start();
       }

       }

   }

I am trying to get the button to run this sql:

select count(*) from history
select count(*) from results where communicated = 0

I can run the SQL Query in SSMS no problem its just getting it to launch from the GUI I'm creating.

Any help is greatly appreciated.

Body:
I wanted to say that I appreciate all the help and patience from everyone on here, I was able to get this resolved on another board and wanted to share the results encase someone else needs assistance with it.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp4
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {

        }
        private void textBox4_TextChanged(object sender, EventArgs e)
        {

        }
        private void textBox5_TextChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            {
                string ServerName = textBox1.Text;
                string Database = textBox2.Text;
                string Username = textBox3.Text;
                string Pass = textBox4.Text;

                string connetionString;
                SqlConnection cnn;
                connetionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";
                cnn = new SqlConnection(connetionString);
                try
                {
                    cnn.Open();
                    MessageBox.Show("Connection Open  !");
                    cnn.Close();
                }
                catch (Exception) { MessageBox.Show("Login Failed, Information is Incorrect"); }
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            string ServerName = textBox1.Text;
            string Database = textBox2.Text;
            string Username = textBox3.Text;
            string Pass = textBox4.Text;
            SqlConnection connection = new SqlConnection();

            connection.ConnectionString = @"Data Source= " + ServerName + ";Initial Catalog= " + Database + ";User ID=" + Username + ";Password= " + Pass + ";";

            SqlCommand command = new SqlCommand();

            command.Connection = connection;
            command.CommandText = "--your SQL query --";
            command.CommandType = CommandType.Text;

            try
            {
                connection.Open();

                SqlDataReader reader = command.ExecuteReader();

                while (reader.Read())
                {
                    int CommunicatedRecordsCount = (int)reader[0];
                    textBox5.Text = CommunicatedRecordsCount.ToString();
                }

                reader.Close();
            }
            catch
            {
            }
            finally
            {
                if (connection.State == ConnectionState.Open)
                    connection.Close();
            }
        }
    }
}

Where I was looking for a numerical output we changed the output slightly, but again thanks everyone for all the assistance.


来源: stackexchange

问:
SQL Server- How can I perform the same function as Excel index/match?
So I have the following code which works fine:

```<code>SELECT
    CODE,
    TRADEDATE,
    SETTLE,
    SUBSTRING(EXPIRY, 1, 1) AS CONTRACT_CODE,
    SUBSTRING(EXPIRY, 2, 4) AS CONTRACT_YEAR
FROM
    QUANDL.DBO.AR_MWCS$
INNER JOIN
    QUANDL.DBO.AR_MWCF$ ON QUANDL.DBO.AR_MWCS$.FULL_code = QUANDL.DBO.AR_MWCF$.FULL_CODE
 WHERE
    CODE IN ('CI', 'TC', 'PG', 'PW', 'NG', 'NL', 'PD', '8X', 'PH', 'PM', 'NJ', 'NX', 'TZ6', 'TR', 'NW', 'CL', 'CY', 'WJ')
    AND EXPIRY IN ('H2020')
ORDER BY
    CODE ASC, TRADEDATE DESC, EXPIRY ASC
</code>```

The output looks like this:

I have another table called "contract_key" which contains two columns. One is "contract_code" and the other is "contract_month". What I need is to join the tables so I can see the contract_month, March, instead of the contract_code, H.

In Excel it would be

```<code>=INDEX(A:A, MATCH(E2,B:B,0))
</code>```

where column A is the month and column B is the code,cell E2 is the code H and the formula returns "3".

The desired output would look like this instead:

I'm using AR_MWCS$ to pull in the settle price. The table looks like this:

Table AR_MWCF$ looks like this:

I'm using substring to split EXPIRY into "H" and "2020"

Table CONTRACT_KEY looks like this:

So I need to join the CONTRACT_CODE from table CONTRACT_KEY and the substring CONTRACT_CODE created from table AR_MWCF$ to find the contract month then combine the contract month with the contract year as a date.

I was able to get my desired output by modifying the code to:

```<code>SELECT
     CODE
    ,TRADEDATE
    ,SETTLE
    ,CONCAT(CONTRACT_MONTH,'-','01','-',CONTRACT_YEAR) AS EXPIRATION

FROM
     QUANDL.DBO.AR_MWCS$

INNER JOIN
    QUANDL.DBO.AR_MWCF$
 ON QUANDL.DBO.AR_MWCS$.FULL_code = QUANDL.DBO.AR_MWCF$.FULL_CODE

INNER JOIN
    QUANDL.DBO.CONTRACT_KEY
ON QUANDL.DBO.AR_MWCF$.CONTRACT_CODE = QUANDL.DBO.CONTRACT_KEY.CONTRACT_CODE

WHERE
    CODE IN ('CI','TC','PG','PW','NG','NL','PD','8X','PH','PM','NJ','NX','TZ6','TR','NW','CL','CY','WJ')

ORDER BY
    CODE ASC, TRADEDATE DESC, EXPIRY ASC
</code>```

Which returns the following:

答:
```<code>SELECT
     CODE,
     TRADEDATE,
     SETTLE,
     contract_key.contract_month AS Expiration
FROM QUANDL.DBO.AR_MWCS$
INNER JOIN QUANDL.DBO.AR_MWCF$
           ON QUANDL.DBO.AR_MWCS$.FULL_code = QUANDL.DBO.AR_MWCF$.FULL_CODE
INNER JOIN contract_key ON contract_key.contract_code = QUANDL.DBO.AR_MWCS$.FULL_code
</code>```

We do not know which, if any, of your original tables contains a joinable "CODE" field.  I used MWCS$.FULL_Code as the joinable table and field.  Use MWCS$ or MWCF$ and FULL_Code or PARTIAL_code or CD as the case may be for the Excel field you seek.

```<code> WHERE
    CODE IN ('CI', 'TC', 'PG', 'PW', 'NG', 'NL', 'PD', '8X', 'PH', 'PM', 'NJ', 'NX', 'TZ6', 'TR', 'NW', 'CL', 'CY', 'WJ')
    AND EXPIRY IN ('H2020')
ORDER BY
    CODE ASC, TRADEDATE DESC, EXPIRY ASC
</code>```

ContentLicense: CC BY-SA 4.0

Body:
So I have the following code which works fine:

SELECT
    CODE,
    TRADEDATE,
    SETTLE,
    SUBSTRING(EXPIRY, 1, 1) AS CONTRACT_CODE,
    SUBSTRING(EXPIRY, 2, 4) AS CONTRACT_YEAR
FROM
    QUANDL.DBO.AR_MWCS$
INNER JOIN
    QUANDL.DBO.AR_MWCF$ ON QUANDL.DBO.AR_MWCS$.FULL_code = QUANDL.DBO.AR_MWCF$.FULL_CODE
 WHERE
    CODE IN ('CI', 'TC', 'PG', 'PW', 'NG', 'NL', 'PD', '8X', 'PH', 'PM', 'NJ', 'NX', 'TZ6', 'TR', 'NW', 'CL', 'CY', 'WJ')
    AND EXPIRY IN ('H2020')
ORDER BY
    CODE ASC, TRADEDATE DESC, EXPIRY ASC

The output looks like this:

I have another table called "contract_key" which contains two columns. One is "contract_code" and the other is "contract_month". What I need is to join the tables so I can see the contract_month, March, instead of the contract_code, H.

In Excel it would be

=INDEX(A:A, MATCH(E2,B:B,0))

where column A is the month and column B is the code,cell E2 is the code H and the formula returns "3".

The desired output would look like this instead:

I'm using AR_MWCS$ to pull in the settle price. The table looks like this:

Table AR_MWCF$ looks like this:

I'm using substring to split EXPIRY into "H" and "2020"

Table CONTRACT_KEY looks like this:

So I need to join the CONTRACT_CODE from table CONTRACT_KEY and the substring CONTRACT_CODE created from table AR_MWCF$ to find the contract month then combine the contract month with the contract year as a date.

I was able to get my desired output by modifying the code to:

SELECT
     CODE
    ,TRADEDATE
    ,SETTLE
    ,CONCAT(CONTRACT_MONTH,'-','01','-',CONTRACT_YEAR) AS EXPIRATION

FROM
     QUANDL.DBO.AR_MWCS$

INNER JOIN
    QUANDL.DBO.AR_MWCF$
 ON QUANDL.DBO.AR_MWCS$.FULL_code = QUANDL.DBO.AR_MWCF$.FULL_CODE

INNER JOIN
    QUANDL.DBO.CONTRACT_KEY
ON QUANDL.DBO.AR_MWCF$.CONTRACT_CODE = QUANDL.DBO.CONTRACT_KEY.CONTRACT_CODE

WHERE
    CODE IN ('CI','TC','PG','PW','NG','NL','PD','8X','PH','PM','NJ','NX','TZ6','TR','NW','CL','CY','WJ')

ORDER BY
    CODE ASC, TRADEDATE DESC, EXPIRY ASC

Which returns the following:

Body:
SELECT
     CODE,
     TRADEDATE,
     SETTLE,
     contract_key.contract_month AS Expiration
FROM QUANDL.DBO.AR_MWCS$
INNER JOIN QUANDL.DBO.AR_MWCF$
           ON QUANDL.DBO.AR_MWCS$.FULL_code = QUANDL.DBO.AR_MWCF$.FULL_CODE
INNER JOIN contract_key ON contract_key.contract_code = QUANDL.DBO.AR_MWCS$.FULL_code

We do not know which, if any, of your original tables contains a joinable "CODE" field.  I used MWCS$.FULL_Code as the joinable table and field.  Use MWCS$ or MWCF$ and FULL_Code or PARTIAL_code or CD as the case may be for the Excel field you seek.

 WHERE
    CODE IN ('CI', 'TC', 'PG', 'PW', 'NG', 'NL', 'PD', '8X', 'PH', 'PM', 'NJ', 'NX', 'TZ6', 'TR', 'NW', 'CL', 'CY', 'WJ')
    AND EXPIRY IN ('H2020')
ORDER BY
    CODE ASC, TRADEDATE DESC, EXPIRY ASC


问:
How do you fight design complexity?
I often find myself fighting overengineering -- the person in charge of designing the software comes up with an architecture that's, way, way overcomplicated.

It's all fine and dandy to have all the esoteric features that users will never know about and get that sense of achievement when you're doing something that all the magazine articles are telling you is the latest, cool thing, but we are going to spend half of our  engineering time on this monument to our cleverness, and not, you know, the actual product that our users need and upper management expects to be completed within a reasonable or at least a bounded time frame.

And you'll probably just have to revert back to the simpler solution anyway when you start running out of time, that is, if you get that chance.

We've all heard the refrain: Keep It Simple, Stupid™.

How do you fight with overcomplexity in your team?

One example I've had to work with repeatedly lately is when the decision has been made to go to a fully denormalized database design rather than an RDBMS. "because it's faster!" Fully denormalized databases are really hard to get right, and are only appropriate for really specialized data problems like Flickr or ebay, and which can be extremely expensive in terms of developer time relative to the rest of your development.

答:
At least for me, the bigger issue is that it's often hard to tell what feature is in there because of its buzzword-friendly, magaziney enterprisey goodness and which is in there because it adds a level of flexibility that will be useful in the future.

It's been shown that people are generally terrible at anticipating future complexity, and side-effects of current decisions. Unfortunately this doesn't always mean simplest is best - in my case, there've been loads of things I thought were too complicated at first and didn't see the value of until much later (er... spring). Also things I thought made sense that turned out to be wildly overcomplicated (EJB1). So I know that my intuition about these things is faulty.

Best bet - any kind of indirection layer should be supported with an argument supporting the value of the flexibility it adds vs. its added dev complexity.

However, people who are dogmatically maintaining a particular db setup on abstract grounds are probably in the "building it because I read that it's the right thing" camp. It might be unrealistic, but some people might be convinced if you build a test version and benchmark, especially if the results show more effort leading to an insignificant performance increase.

OwnerDisplayName: ʞɔıu

ContentLicense: CC BY-SA 2.5

Title: How do you fight design complexity?

LastEditorDisplayName: philippe

OwnerDisplayName: Steve B.


问:
How can I ensure a button is visible when the keyboard is used?
I have a form with some elements and a button on the bottom. If I click inside a input the keyboard appears and covers the button. I want the page scrolls down so the button should be visible. I tried to use WidgetsBinding to find out when the keyoard is shown and controller.jumpTo(controller.position.maxScrollExtent); to scroll to the end of the ListView but that doesn't work.

```<code>class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver {

  Size lastSize;
  Menu selected = Menu.Email;
  ScrollController controller = ScrollController();

  @protected
  void initState() {
    super.initState();
    lastSize = WidgetsBinding.instance.window.physicalSize;
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeMetrics() {
    controller.jumpTo(controller.position.maxScrollExtent);
  }

  @override
  Widget build(BuildContext context) {
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;

    return Scaffold(
      body:
      Container(
        height: height,
        width: width,
        decoration: BoxDecoration(
          gradient: LinearGradient(
              colors: [AppColors.primaryLight, AppColors.primary],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter),
        ),
        child: ListView(
            controller: controller,
            padding: EdgeInsets.all(0.0),
            shrinkWrap: true,
          children: <Widget>[
            Padding(
                padding: EdgeInsets.only(top: 25, bottom: 35),
                child: Align(
                  child: SvgPicture.asset(
                    'assets/images/logo.svg',
                    height: width / 3,
                    width: width / 3,
                  ),
                  alignment: Alignment.center,
                )),
            Container(
                decoration:
                    BoxDecoration(border: Border(top: BorderSide(color: Colors.white), bottom: BorderSide(color: Colors.white))),
                child: Row(
                  children: <Widget>[
                    Expanded(
                        child: FlatButton(
                            onPressed: () {
                              setState(() {
                                selected = Menu.Email;
                              });
                            },
                            child: Text(
                              'Email',
                              style:
                                  TextStyle(color: Colors.white, fontSize: 18, fontWeight: selected == Menu.Email ? FontWeight.bold : FontWeight.normal),
                              textAlign: TextAlign.center,
                            ))),
                    Expanded(
                        child: FlatButton(
                            onPressed: () {
                              setState(() {
                                selected = Menu.Phone;
                              });
                            },
                            child: Text(
                              'Phone',
                              style:
                                  TextStyle(color: Colors.white, fontSize: 18, fontWeight: selected == Menu.Phone ? FontWeight.bold : FontWeight.normal),
                              textAlign: TextAlign.center,
                            ))),
                  ],
                )),
            LoginWithEmail()

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

答:
You should try to use the package keyboard_visibility to trigger your scroll controller.

_scrollDown(bool visible) {
   if (visible)
      controller.jumpTo(controller.position.maxScrollExtent);
}

@override
void initState() {
   super.initState();
   KeyboardVisibilityNotification().addNewListener(onChange: _scrollDown);
}
```

Body:
I have a form with some elements and a button on the bottom. If I click inside a input the keyboard appears and covers the button. I want the page scrolls down so the button should be visible. I tried to use WidgetsBinding to find out when the keyoard is shown and controller.jumpTo(controller.position.maxScrollExtent); to scroll to the end of the ListView but that doesn't work.

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> with WidgetsBindingObserver {

  Size lastSize;
  Menu selected = Menu.Email;
  ScrollController controller = ScrollController();

  @protected
  void initState() {
    super.initState();
    lastSize = WidgetsBinding.instance.window.physicalSize;
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeMetrics() {
    controller.jumpTo(controller.position.maxScrollExtent);
  }

  @override
  Widget build(BuildContext context) {
    double height = MediaQuery.of(context).size.height;
    double width = MediaQuery.of(context).size.width;

    return Scaffold(
      body:
      Container(
        height: height,
        width: width,
        decoration: BoxDecoration(
          gradient: LinearGradient(
              colors: [AppColors.primaryLight, AppColors.primary],
              begin: Alignment.topCenter,
              end: Alignment.bottomCenter),
        ),
        child: ListView(
            controller: controller,
            padding: EdgeInsets.all(0.0),
            shrinkWrap: true,
          children: <Widget>[
            Padding(
                padding: EdgeInsets.only(top: 25, bottom: 35),
                child: Align(
                  child: SvgPicture.asset(
                    'assets/images/logo.svg',
                    height: width / 3,
                    width: width / 3,
                  ),
                  alignment: Alignment.center,
                )),
            Container(
                decoration:
                    BoxDecoration(border: Border(top: BorderSide(color: Colors.white), bottom: BorderSide(color: Colors.white))),
                child: Row(
                  children: <Widget>[
                    Expanded(
                        child: FlatButton(
                            onPressed: () {
                              setState(() {
                                selected = Menu.Email;
                              });
                            },
                            child: Text(
                              'Email',
                              style:
                                  TextStyle(color: Colors.white, fontSize: 18, fontWeight: selected == Menu.Email ? FontWeight.bold : FontWeight.normal),
                              textAlign: TextAlign.center,
                            ))),
                    Expanded(
                        child: FlatButton(
                            onPressed: () {
                              setState(() {
                                selected = Menu.Phone;
                              });
                            },
                            child: Text(
                              'Phone',
                              style:
                                  TextStyle(color: Colors.white, fontSize: 18, fontWeight: selected == Menu.Phone ? FontWeight.bold : FontWeight.normal),
                              textAlign: TextAlign.center,
                            ))),
                  ],
                )),
            LoginWithEmail()

          ],
        ),
      ),
    );
  }
}


问:
Bug in Heap Sort with Linked List
I'm writing a Heap Sort algorithm for a Linked List in C# and have encountered a bug that I cannot seem to solve. Basically what happens is instead of sorting the list properly, it duplicates some elements and removes others. The result is a list of the same length as original but with missing and duplicated elements and not ordered properly. I have been trying to fix the bug for quite some time but haven't succeeded yet. Could anyone help me spot the problem?

Thanks in advance!

Here's the relevant code:

MyFileList class:

```<code>using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Lab1
{
    class MyFileList : DataList
    {
        int prevNode;
        int currentNode;
        int nextNode;

        public MyFileList(string filename, int n)
        {
            length = n;
            Random rand = new Random();

            if (File.Exists(filename)) File.Delete(filename);

            try
            {
                using (BinaryWriter writer = new BinaryWriter(File.Open(filename,
               FileMode.Create)))
                {
                    writer.Write(4);
                    for (int j = 0; j < length; j++)
                    {
                        char c = (char)rand.Next('a', 'z');
                        int ri = (int)rand.Next();
                        Element e = new Element(c, ri);
                        writer.Write(e.partOne);
                        writer.Write(e.partTwo);
                        writer.Write((j + 1) * 9 + 4);
                    }
                }
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public FileStream fs { get; set; }
        public override Element Head()
        {
            BinaryReader br = new BinaryReader(fs);
            prevNode = -1;
            br.BaseStream.Seek(0, SeekOrigin.Begin);
            currentNode = br.ReadInt32();
            br.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            char c = (char)br.ReadChar();
            int i = br.ReadInt32();

            Element result = new Element(c, i);
            nextNode = br.ReadInt32();
            return result;
        }
        public override Element Next()
        {
            prevNode = currentNode;
            currentNode = nextNode;
            BinaryReader br = new BinaryReader(fs);
            char c = (char)br.ReadChar();
            int i = br.ReadInt32();
            Element result = new Element(c, i);
            nextNode = br.ReadInt32();
            return result;

        }

        public override Element returnAtIndex(int index)
        {
            //int tempcurrent = currentNode; int tempprev = prevNode; int tempnext = nextNode;

            Element result = Head();
            for (int i = 0; i < index; i++)
            {
                result = Next();
            }

            //Console.WriteLine(prevNode);

            //currentNode = tempcurrent; prevNode = tempprev; nextNode = tempnext;

            return result;
        }

        public override void Swap(int index1, int index2)
        {
            Byte[] data1 = new Byte[6];
            Byte[] data2 = new Byte[6];
            Element e = null;
            BinaryReader br = new BinaryReader(fs);
            BinaryWriter bw = new BinaryWriter(fs);

            Head();
            for (int i = 0; i < index1; i++)
                Next();
            br.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            br.BaseStream.Read(data1, 0, 6);

            Head();
            for (int i = 0; i < index2; i++)
                Next();
            br.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            br.BaseStream.Read(data2, 0, 6);

            Console.WriteLine();

            Head();
            for (int i = 0; i < index1; i++)
                Next();
            bw.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            bw.Write(data2, 0, 6);

            Head();
            for (int i = 0; i < index2; i++)
                Next();
            bw.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            bw.Write(data1, 0, 6);
        }

        public int findNodeofElement(Element e)
        {
            Element elem = Head();
            for (int i = 0; i < length; i++)
            {
                elem = Next();
                if (elem.partOne == e.partOne && elem.partTwo == e.partTwo) break;

            }
            return currentNode;
        }

        public override void setValues(Element e)
        {
            BinaryWriter bw = new BinaryWriter(fs);
            bw.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            bw.Write(e.partOne);
            bw.Write(e.partTwo);
        }

    }
</code>```

Program.cs:

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

namespace Lab1
{
    class Program
    {
        static void Main(string[] args)
        {
            int seed = (int)DateTime.Now.Ticks & 0x0000FFFF;

            rikiavimas(10);

        }

        public static void rikiavimas(int n)
        {
            string filename = @"test1.txt";
            MyFileList myfilelist = new MyFileList(filename, n);
            using (myfilelist.fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite))
            {
                Console.WriteLine("\n *****FILE LIST***** \n");
                myfilelist.Print(n);
                PerformHeapSort(myfilelist);
                Console.WriteLine("\n *****SORTED FILE LIST***** \n");
                myfilelist.Print(n);
            }
        }

        public static void PerformHeapSort(MyFileList arr)
        {
            int heapSize = arr.Length - 1;
            BuildHeap(arr);
            for (int i = arr.Length - 1; i >= 0; i--)
            {
               Console.WriteLine("********* " + i);
                if (i!= 0) arr.Swap(0, i);
                heapSize--;
                Heapify(arr, 0);
            }
        }

        private static void BuildHeap(MyFileList arr)
        {
            int heapSize = arr.Length - 1;
            for (int i = heapSize / 2; i >= 0; i--)
            {
                Heapify(arr, i);
            }
        }
        private static void Heapify(MyFileList arr, int index)
        {
            int heapSize = arr.Length - 1;
            int left = 2 * index;
            int right = 2 * index + 1;
            int largest = index;

            Element elmLeft = null; Element elmRight = null;
            if (left <= heapSize) elmLeft = arr.returnAtIndex(left);
            if (right <= heapSize) elmRight = arr.returnAtIndex(right);
            Element elmLargest = arr.returnAtIndex(largest);

            if (left <= heapSize && elmLeft > elmLargest) //index
            {
                largest = left;
            }

            if (right <= heapSize && elmRight > elmLargest)
            {
                largest = right;
            }

            if (largest != index)
            {
               if (index != largest) arr.Swap(index, largest);
                Console.WriteLine("*******index is " + index + " largest is " + largest);
                Heapify(arr, largest);
            }
        }

    }

    abstract class DataList
    {
        protected int length;
        public int Length { get { return length; } }
        public abstract Element Head();
        public abstract Element Next();
        //public abstract Element Previous();
        public abstract Element returnAtIndex(int index);
        //public abstract Element returnAtIndex(int index);
        public abstract void Swap(Element a, Element b);
        public abstract void Swap(int index1, int index2);
        public abstract void setValues(Element e);
        //public abstract void Append ()
        //public abstract void PerformHeapSort(DataList list);
        public void Print(int n)
        {

            Element head = Head();
            Console.Write(head.partOne);
            Console.WriteLine(head.partTwo);
            for (int i = 1; i < n; i++)
            {
                Element elem = Next();
                Console.Write(elem.partOne);
                Console.WriteLine(elem.partTwo);
            }
            Console.WriteLine();

        }

    }

    class Element
    {
        public char partOne;
        public int partTwo;

        public Element (char c, int i)
        {
            partOne = c;
            partTwo = i;
        }

        public void PrintInt()
        {
            Console.WriteLine(partTwo);
        }

        public void PrintChar()
        {
            Console.WriteLine(partOne);
        }

        public static bool operator < (Element e1, Element e2)
        {
            if (e1.partOne < e2.partOne) return true;
            else if (e1.partOne == e2.partOne && (e1.partTwo < e2.partTwo)) return true;
            else return false;
        }

        public static bool operator > (Element e1, Element e2)
        {
            if (e1.partOne > e2.partOne) return true;
            else if (e1.partOne == e2.partOne && (e1.partTwo > e2.partTwo)) return true;
            else return false;
        }
    }
}
</code>```

Here's an example of the output I get when I run this code:

```<code> *****FILE LIST*****

j849146725
q569436044
r1645801130
p1861344598
k886292186
a852479939
v1166576825
j1180639416
v1227743602
y739268292

 *****SORTED FILE LIST*****

v1227743602
v1227743602
j1180639416
p1861344598
r1645801130
a852479939
y739268292
r1645801130
q569436044
j849146725
</code>```

答:
I think there may be multiple bugs, but one issue I've found, and I think this is causing the duplicate values, happens when you do a swap.

It appears that the nodes are stored in a binary file in the following format:
offset to head node, the node value (a char and an int), and offset to the next node
So something like this:

```<code>04 00 00 00 67 D0 DB 2C 0E 0D 00 00 00

0x00000004 is the offset to the head node
0x67D0DB2C0E is the head node value (0x67 is the char 'g' and 0x0E2CDBD0 is the int)
0x0000000D is the offset to the next node
</code>```

I see two approaches to using the linked list: 1) never change the linked-list offsets and just swap the values or 2) leave the values where they are and update the linked-list offsets to swap values.  It looks like you're trying to use the first approach in your Print and Next functions.  For example in your Next function it simply reads the next node from the file, basically ignoring the linked-list offsets.  The problem then comes in your Swap function.  It's sort of using a mixture of approach 1 and 2.  It uses the offsets from the file but it's also swapping them.  The Swap function reads and writes 6 bytes from the file (5 value bytes and the first byte of the offset to the next node).  So it's changing the offsets and the values.  If you changed it to only read 5 bytes then it would only be changing the values.

You need to make sure all of your code is consistent in how it's using the linked list.  Is it going to use the linked-list offsets or is it going to assume that the head node is always at offset 4, and the next node at offset 13?

As I mentioned in the beginning there may be other issues, but I believe this is the one causing the duplicate values.

Title: Bug in Heap Sort with Linked List

Body:
I'm writing a Heap Sort algorithm for a Linked List in C# and have encountered a bug that I cannot seem to solve. Basically what happens is instead of sorting the list properly, it duplicates some elements and removes others. The result is a list of the same length as original but with missing and duplicated elements and not ordered properly. I have been trying to fix the bug for quite some time but haven't succeeded yet. Could anyone help me spot the problem?

Thanks in advance!

Here's the relevant code:

MyFileList class:

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

namespace Lab1
{
    class MyFileList : DataList
    {
        int prevNode;
        int currentNode;
        int nextNode;

        public MyFileList(string filename, int n)
        {
            length = n;
            Random rand = new Random();

            if (File.Exists(filename)) File.Delete(filename);

            try
            {
                using (BinaryWriter writer = new BinaryWriter(File.Open(filename,
               FileMode.Create)))
                {
                    writer.Write(4);
                    for (int j = 0; j < length; j++)
                    {
                        char c = (char)rand.Next('a', 'z');
                        int ri = (int)rand.Next();
                        Element e = new Element(c, ri);
                        writer.Write(e.partOne);
                        writer.Write(e.partTwo);
                        writer.Write((j + 1) * 9 + 4);
                    }
                }
            }
            catch (IOException ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public FileStream fs { get; set; }
        public override Element Head()
        {
            BinaryReader br = new BinaryReader(fs);
            prevNode = -1;
            br.BaseStream.Seek(0, SeekOrigin.Begin);
            currentNode = br.ReadInt32();
            br.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            char c = (char)br.ReadChar();
            int i = br.ReadInt32();

            Element result = new Element(c, i);
            nextNode = br.ReadInt32();
            return result;
        }
        public override Element Next()
        {
            prevNode = currentNode;
            currentNode = nextNode;
            BinaryReader br = new BinaryReader(fs);
            char c = (char)br.ReadChar();
            int i = br.ReadInt32();
            Element result = new Element(c, i);
            nextNode = br.ReadInt32();
            return result;

        }

        public override Element returnAtIndex(int index)
        {
            //int tempcurrent = currentNode; int tempprev = prevNode; int tempnext = nextNode;

            Element result = Head();
            for (int i = 0; i < index; i++)
            {
                result = Next();
            }

            //Console.WriteLine(prevNode);

            //currentNode = tempcurrent; prevNode = tempprev; nextNode = tempnext;

            return result;
        }

        public override void Swap(int index1, int index2)
        {
            Byte[] data1 = new Byte[6];
            Byte[] data2 = new Byte[6];
            Element e = null;
            BinaryReader br = new BinaryReader(fs);
            BinaryWriter bw = new BinaryWriter(fs);

            Head();
            for (int i = 0; i < index1; i++)
                Next();
            br.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            br.BaseStream.Read(data1, 0, 6);

            Head();
            for (int i = 0; i < index2; i++)
                Next();
            br.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            br.BaseStream.Read(data2, 0, 6);

            Console.WriteLine();

            Head();
            for (int i = 0; i < index1; i++)
                Next();
            bw.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            bw.Write(data2, 0, 6);

            Head();
            for (int i = 0; i < index2; i++)
                Next();
            bw.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            bw.Write(data1, 0, 6);
        }

        public int findNodeofElement(Element e)
        {
            Element elem = Head();
            for (int i = 0; i < length; i++)
            {
                elem = Next();
                if (elem.partOne == e.partOne && elem.partTwo == e.partTwo) break;

            }
            return currentNode;
        }

        public override void setValues(Element e)
        {
            BinaryWriter bw = new BinaryWriter(fs);
            bw.BaseStream.Seek(currentNode, SeekOrigin.Begin);
            bw.Write(e.partOne);
            bw.Write(e.partTwo);
        }

    }

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

namespace Lab1
{
    class Program
    {
        static void Main(string[] args)
        {
            int seed = (int)DateTime.Now.Ticks & 0x0000FFFF;

            rikiavimas(10);

        }

        public static void rikiavimas(int n)
        {
            string filename = @"test1.txt";
            MyFileList myfilelist = new MyFileList(filename, n);
            using (myfilelist.fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite))
            {
                Console.WriteLine("\n *****FILE LIST***** \n");
                myfilelist.Print(n);
                PerformHeapSort(myfilelist);
                Console.WriteLine("\n *****SORTED FILE LIST***** \n");
                myfilelist.Print(n);
            }
        }

        public static void PerformHeapSort(MyFileList arr)
        {
            int heapSize = arr.Length - 1;
            BuildHeap(arr);
            for (int i = arr.Length - 1; i >= 0; i--)
            {
               Console.WriteLine("********* " + i);
                if (i!= 0) arr.Swap(0, i);
                heapSize--;
                Heapify(arr, 0);
            }
        }

        private static void BuildHeap(MyFileList arr)
        {
            int heapSize = arr.Length - 1;
            for (int i = heapSize / 2; i >= 0; i--)
            {
                Heapify(arr, i);
            }
        }
        private static void Heapify(MyFileList arr, int index)
        {
            int heapSize = arr.Length - 1;
            int left = 2 * index;
            int right = 2 * index + 1;
            int largest = index;

            Element elmLeft = null; Element elmRight = null;
            if (left <= heapSize) elmLeft = arr.returnAtIndex(left);
            if (right <= heapSize) elmRight = arr.returnAtIndex(right);
            Element elmLargest = arr.returnAtIndex(largest);

            if (left <= heapSize && elmLeft > elmLargest) //index
            {
                largest = left;
            }

            if (right <= heapSize && elmRight > elmLargest)
            {
                largest = right;
            }

            if (largest != index)
            {
               if (index != largest) arr.Swap(index, largest);
                Console.WriteLine("*******index is " + index + " largest is " + largest);
                Heapify(arr, largest);
            }
        }

    }

    abstract class DataList
    {
        protected int length;
        public int Length { get { return length; } }
        public abstract Element Head();
        public abstract Element Next();
        //public abstract Element Previous();
        public abstract Element returnAtIndex(int index);
        //public abstract Element returnAtIndex(int index);
        public abstract void Swap(Element a, Element b);
        public abstract void Swap(int index1, int index2);
        public abstract void setValues(Element e);
        //public abstract void Append ()
        //public abstract void PerformHeapSort(DataList list);
        public void Print(int n)
        {

            Element head = Head();
            Console.Write(head.partOne);
            Console.WriteLine(head.partTwo);
            for (int i = 1; i < n; i++)
            {
                Element elem = Next();
                Console.Write(elem.partOne);
                Console.WriteLine(elem.partTwo);
            }
            Console.WriteLine();

        }

    }

    class Element
    {
        public char partOne;
        public int partTwo;

        public Element (char c, int i)
        {
            partOne = c;
            partTwo = i;
        }

        public void PrintInt()
        {
            Console.WriteLine(partTwo);
        }

        public void PrintChar()
        {
            Console.WriteLine(partOne);
        }

        public static bool operator < (Element e1, Element e2)
        {
            if (e1.partOne < e2.partOne) return true;
            else if (e1.partOne == e2.partOne && (e1.partTwo < e2.partTwo)) return true;
            else return false;
        }

        public static bool operator > (Element e1, Element e2)
        {
            if (e1.partOne > e2.partOne) return true;
            else if (e1.partOne == e2.partOne && (e1.partTwo > e2.partTwo)) return true;
            else return false;
        }
    }
}

Here's an example of the output I get when I run this code:

 *****FILE LIST*****

j849146725
q569436044
r1645801130
p1861344598
k886292186
a852479939
v1166576825
j1180639416
v1227743602
y739268292

 *****SORTED FILE LIST*****

v1227743602
v1227743602
j1180639416
p1861344598
r1645801130
a852479939
y739268292
r1645801130
q569436044
j849146725

Body:
I think there may be multiple bugs, but one issue I've found, and I think this is causing the duplicate values, happens when you do a swap.

It appears that the nodes are stored in a binary file in the following format:
offset to head node, the node value (a char and an int), and offset to the next node
So something like this:

04 00 00 00 67 D0 DB 2C 0E 0D 00 00 00

0x00000004 is the offset to the head node
0x67D0DB2C0E is the head node value (0x67 is the char 'g' and 0x0E2CDBD0 is the int)
0x0000000D is the offset to the next node

I see two approaches to using the linked list: 1) never change the linked-list offsets and just swap the values or 2) leave the values where they are and update the linked-list offsets to swap values.  It looks like you're trying to use the first approach in your Print and Next functions.  For example in your Next function it simply reads the next node from the file, basically ignoring the linked-list offsets.  The problem then comes in your Swap function.  It's sort of using a mixture of approach 1 and 2.  It uses the offsets from the file but it's also swapping them.  The Swap function reads and writes 6 bytes from the file (5 value bytes and the first byte of the offset to the next node).  So it's changing the offsets and the values.  If you changed it to only read 5 bytes then it would only be changing the values.

You need to make sure all of your code is consistent in how it's using the linked list.  Is it going to use the linked-list offsets or is it going to assume that the head node is always at offset 4, and the next node at offset 13?

As I mentioned in the beginning there may be other issues, but I believe this is the one causing the duplicate values.


问:
Heat map creation in android studio using google maps api
I recently created an android app with heat maps using google maps API in android studio. I used below codes for gradient creation. I got a result showing squares? Why I got that result? Need Help Please.

```<code>int[] colors = {
        Color.GREEN,    // green
        Color.YELLOW,    // yellow
        Color.rgb(255,165,0), //Orange
        Color.RED,              //red
        Color.rgb(153,50,204), //dark orchid
        Color.rgb(165,42,42) //brown
};

float[] startpoints = {
        0.0f,    //0-50
        0.1f,   //51-100
        0.2f,   //101-150
        0.3f,   //151-200
        0.4f,    //201-300
        0.6f      //301-500
};

private ArrayList addheatmap() {
    ArrayList<WeightedLatLng> arr = new ArrayList<>();

    arr.add(new WeightedLatLng(new LatLng(9.9252, 78.119),10)); //madurai
    arr.add(new WeightedLatLng(new LatLng(10.7905, 78.7047),60)); //trichy
    arr.add(new WeightedLatLng(new LatLng(13.0827, 80.2707),180)); //chennai
    arr.add(new WeightedLatLng(new LatLng(11.0168, 76.9558),270)); //coimbatore
    arr.add(new WeightedLatLng(new LatLng(11.7863, 77.8008),380));
    arr.add(new WeightedLatLng(new LatLng(11.7480, 79.7714),190));
    arr.add(new WeightedLatLng(new LatLng(8.7642, 78.1348),299));
    arr.add(new WeightedLatLng(new LatLng(11.6643, 78.1460),398));

    Log.e("adding heatmap","yes");

    return arr;
}

private void buildheatmap(){

    Gradient gradient = new Gradient(colors,startpoints);
    heatmapTileProvider = new HeatmapTileProvider.Builder()
            .weightedData(addheatmap())
            .radius(20)
            .gradient(gradient)
            .build();
    TileOverlayOptions tileoverlayoptions = new TileOverlayOptions().tileProvider(heatmapTileProvider);
    TileOverlay tileoverlay = googleMap.addTileOverlay(tileoverlayoptions);
    tileoverlay.clearTileCache();
    Toast.makeText(this,"added heatmap",Toast.LENGTH_SHORT).show();
}
</code>```

Screenshot of App output

I used above colors array and startpoints array for creating gradient for HeatMapTileProvider.
Why I am getting square like structures and what to do to get them in circle like structures? Thank YOU

答: If you start the startpoints array at 0.05f (or some insignificantly small number) rather than 0 it should get rid of the squareness of the heatmap.</p>

ContentLicense: CC BY-SA 3.0

Body:
I recently created an android app with heat maps using google maps API in android studio. I used below codes for gradient creation. I got a result showing squares? Why I got that result? Need Help Please.

int[] colors = {
        Color.GREEN,    // green
        Color.YELLOW,    // yellow
        Color.rgb(255,165,0), //Orange
        Color.RED,              //red
        Color.rgb(153,50,204), //dark orchid
        Color.rgb(165,42,42) //brown
};

float[] startpoints = {
        0.0f,    //0-50
        0.1f,   //51-100
        0.2f,   //101-150
        0.3f,   //151-200
        0.4f,    //201-300
        0.6f      //301-500
};

private ArrayList addheatmap() {
    ArrayList<WeightedLatLng> arr = new ArrayList<>();

    arr.add(new WeightedLatLng(new LatLng(9.9252, 78.119),10)); //madurai
    arr.add(new WeightedLatLng(new LatLng(10.7905, 78.7047),60)); //trichy
    arr.add(new WeightedLatLng(new LatLng(13.0827, 80.2707),180)); //chennai
    arr.add(new WeightedLatLng(new LatLng(11.0168, 76.9558),270)); //coimbatore
    arr.add(new WeightedLatLng(new LatLng(11.7863, 77.8008),380));
    arr.add(new WeightedLatLng(new LatLng(11.7480, 79.7714),190));
    arr.add(new WeightedLatLng(new LatLng(8.7642, 78.1348),299));
    arr.add(new WeightedLatLng(new LatLng(11.6643, 78.1460),398));

    Log.e("adding heatmap","yes");

    return arr;
}

private void buildheatmap(){

    Gradient gradient = new Gradient(colors,startpoints);
    heatmapTileProvider = new HeatmapTileProvider.Builder()
            .weightedData(addheatmap())
            .radius(20)
            .gradient(gradient)
            .build();
    TileOverlayOptions tileoverlayoptions = new TileOverlayOptions().tileProvider(heatmapTileProvider);
    TileOverlay tileoverlay = googleMap.addTileOverlay(tileoverlayoptions);
    tileoverlay.clearTileCache();
    Toast.makeText(this,"added heatmap",Toast.LENGTH_SHORT).show();
}

Screenshot of App output

I used above colors array and startpoints array for creating gradient for HeatMapTileProvider.
Why I am getting square like structures and what to do to get them in circle like structures? Thank YOU


问:
Resetting an iterator, which is a map object?
I'm learning Python by myself.

I've come across the following

```<code>sol=map(pow,[1,2,3],[4,5,6])
</code>```

sol is an iterator.

When I run consecutively next(sol), I will iterate along the elements of sol, until I get StopIteration error.

However, how can I restart the iteration?

I've tried iter_1=itertools.cycle(sol), but I need to restart sol by running sol=map(pow,[1,2,3],[4,5,6]) and only then iter_1=itertools.cycle(sol).

Is there another way?

答:
To achieve the effect you described on the OP, you can use itertools.cycle(). Something like this:

Python 3.7.6 (default, Jan 30 2020, 09:44:41)
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from itertools import cycle
>>> c = cycle(map(pow,[1,2,3],[4,5,6]))
>>> next(c)
1
>>> next(c)
32
>>> next(c)
729
>>> next(c)
1
>>> next(c)
32
>>>
```

But take into consideration the comments on the OP before you choose this approach.

Body:
I'm learning Python by myself.

I've come across the following

sol=map(pow,[1,2,3],[4,5,6])

sol is an iterator.

When I run consecutively next(sol), I will iterate along the elements of sol, until I get StopIteration error.

However, how can I restart the iteration?

I've tried iter_1=itertools.cycle(sol), but I need to restart sol by running sol=map(pow,[1,2,3],[4,5,6]) and only then iter_1=itertools.cycle(sol).

Is there another way?

Body:
To achieve the effect you described on the OP, you can use itertools.cycle(). Something like this:

Python 3.7.6 (default, Jan 30 2020, 09:44:41)
[GCC 9.2.1 20190827 (Red Hat 9.2.1-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from itertools import cycle
>>> c = cycle(map(pow,[1,2,3],[4,5,6]))
>>> next(c)
1
>>> next(c)
32
>>> next(c)
729
>>> next(c)
1
>>> next(c)
32
>>>

But take into consideration the comments on the OP before you choose this approach.


问:
Java regex with replace
I need to replace string with a variable inside {} using a regex

For example:

```<code>"Hi, there are {online@US-server} players in the US server" to "Hi, there are 12 players in the US server"
</code>```

Inside the Strings variables inside {} can be more than 1

I need this code to allow users to modify messages. variable inside {} after @ like in the example 'US-server' are put in by users so there aren't list to check for variable. Variables could be as strange as possible ex: '{online@test-UK}' '{online@asdtest}'

```<code>public static String getReplaced(String d) {
    String result = d.split("\\{online@")[0];

    for (int i = 1; i < d.split("\\{online@").length; i++) {
        String dd = d.split("\\{online@")[i];

        Pattern p = Pattern.compile("(.*?)}(.*)");
        Matcher m = p.matcher(dd);

        if (m.lookingAt()) {
            int count = 12;

            result += count + m.group(2);
        } else {
            result += dd;
        }
    }

    return result;
}
</code>```

答:
With \\{online@(.+)\\}as the regex, use a matcher to get the first capturing group. That will give you the part after the @.

Regex means:

\\{: litteral character '{'

online@: the string online@

.+: at least one character (anyone)

(.+): capturing group

\\}: litteral character '}'

Then simply use String#replaceAll(String regex, String replacement) (doc here).

Example:

```<code>int myIntValue = 12;
String myString = "there are {online@US-server} players";
Pattern p = Pattern.compile("\\{online@(.+)\\}") ;
Matcher m = p.matcher(myString) ;

if (m.find()) { // true if the pattern is found anywhere in your string.
  System.out.println("Variable part is : " + m.group(1)); // group 1 is the capturing group
  System.out.println(myString.replaceAll("\\{online@.+\\}", String.valueOf(myIntValue)));
}
</code>```

If you need to find more than one placeholder in a single string:

```<code>String myString = "there are {online@US-server} players ,and {online@whatever}";
Pattern p = Pattern.compile("\\{online@(.+)\\}") ;
Matcher m = p.matcher(myString) ;

while (m.find()) { // true if the pattern is found anywhere in your string.
  System.out.println("Variable part is : " + m.group(1)); // group 1 is the capturing group
  System.out.println(myString.replace("{online@"+m.group(1)+"}", String.valueOf(myIntValue)));
}
</code>```

Title: Java regex with replace

Body:
I need to replace string with a variable inside {} using a regex

For example:

"Hi, there are {online@US-server} players in the US server" to "Hi, there are 12 players in the US server"

Inside the Strings variables inside {} can be more than 1

I need this code to allow users to modify messages. variable inside {} after @ like in the example 'US-server' are put in by users so there aren't list to check for variable. Variables could be as strange as possible ex: '{online@test-UK}' '{online@asdtest}'

public static String getReplaced(String d) {
    String result = d.split("\\{online@")[0];

    for (int i = 1; i < d.split("\\{online@").length; i++) {
        String dd = d.split("\\{online@")[i];

        Pattern p = Pattern.compile("(.*?)}(.*)");
        Matcher m = p.matcher(dd);

        if (m.lookingAt()) {
            int count = 12;

            result += count + m.group(2);
        } else {
            result += dd;
        }
    }

    return result;
}

Body:
With \\{online@(.+)\\}as the regex, use a matcher to get the first capturing group. That will give you the part after the @.

Regex means:

\\{: litteral character '{'

online@: the string online@

.+: at least one character (anyone)

(.+): capturing group

\\}: litteral character '}'

Then simply use String#replaceAll(String regex, String replacement) (doc here).

Example:

int myIntValue = 12;
String myString = "there are {online@US-server} players";
Pattern p = Pattern.compile("\\{online@(.+)\\}") ;
Matcher m = p.matcher(myString) ;

if (m.find()) { // true if the pattern is found anywhere in your string.
  System.out.println("Variable part is : " + m.group(1)); // group 1 is the capturing group
  System.out.println(myString.replaceAll("\\{online@.+\\}", String.valueOf(myIntValue)));
}

If you need to find more than one placeholder in a single string:

String myString = "there are {online@US-server} players ,and {online@whatever}";
Pattern p = Pattern.compile("\\{online@(.+)\\}") ;
Matcher m = p.matcher(myString) ;

while (m.find()) { // true if the pattern is found anywhere in your string.
  System.out.println("Variable part is : " + m.group(1)); // group 1 is the capturing group
  System.out.println(myString.replace("{online@"+m.group(1)+"}", String.valueOf(myIntValue)));
}


问:
How can I make it so my integer from earlier change numbers if something happens?
I am in a basic computer programming class in High School, and my teacher is no help. I want to make 3 numbers entered by the user to change to 5 if the total is greater than 15. So far I've learned:

if (g + h + i > 15)

else

I've also learned   int g = console.nextInt();  to get the user to type a number.

What I can't figure out is how to get all 3 integers entered by the user to change to 5 if their total greater than 15. I can get text to appear saying the number 5 or that all numbers are now 5, but i want the text from earlier to change. Is this possible?

Thanks so much for the help. I know this is probably a very easy thing to do, but I appreciate it none the less.

答:
Try this:</p>

```<code>int g = console.nextInt();
int h = console.nextInt();
int i = console.nextInt();

if (g + h + i > 15)
{
    g=5;
    h=5;
    i=5;
}
</code>```

Body:
Try this:

int g = console.nextInt();
int h = console.nextInt();
int i = console.nextInt();

if (g + h + i > 15)
{
    g=5;
    h=5;
    i=5;
}


问:
How can I write a short-hand expression that validates an integer, and returns an integer or a null?
I have a need to end up with a variable $id that contains either an integer, or a null value.

Currently I have this:

```<code>$id = $_POST['id'];
$id = filter_var($id, FILTER_VALIDATE_INT); //false or integer
if (!$id)
    $id = null;
</code>```

Is there a more concise way to write this?  I am looking to consolidate 3 statements into one line if possible.

答:
I think you are looking for something like: $id = $id ?: null;

EDIT:
Taking @treyBake's suggestion, your code block can be turned into a single line using this:
$id = filter_var($_POST['id'], FILTER_VALIDATE_INT) ?: null;

Body:
I have a need to end up with a variable $id that contains either an integer, or a null value.

Currently I have this:

$id = $_POST['id'];
$id = filter_var($id, FILTER_VALIDATE_INT); //false or integer
if (!$id)
    $id = null;

Is there a more concise way to write this?  I am looking to consolidate 3 statements into one line if possible.


问:
Lxml xpath returns an empty array
Well guys, Im scraping : https://twitter.com/iForex_com/status/1019547735614255104

I would appreciate it if someone can help me out

```<code>import requests
from lxml import html

        finalurl = f"https://www.twitter.com/user/status/{id}"
        response = requests.get(finalurl,allow_redirects=True)
            tree = html.fromstring(response.content)
            print("getting photolink")
            postPhotoLink = tree.xpath('//*[@id="react-root"]/div/div/div/main/div/div/div/div[1]/div/div[2]/div/section/div/div/div/div[1]/div/article/div/div[4]/div/div/div/a/div/div[2]/div/img/@src')
                        print(postPhotoLink)
</code>```

Result :

getting photolink
[]

答:
thanks all for the help. I had to use selenium for this, otherwise request wasnt working properly, still having some trouble selecting just the number 2 img in the xpath thought. im selecting manually from the array, still works...

Complete working code

```<code>import requests
from lxml import html
from selenium import webdriver
import time

finalurl = "https://twitter.com/iForex_com/status/1019547735614255104"
browser = webdriver.Safari()
browser.get(finalurl)
time.sleep(1)

tree = html.fromstring(browser.page_source)
print("getting photolink")

postPhotoLink = tree.xpath('//img[@class="css-9pa8cd"]/@src')
print(postPhotoLink[1])

browser.close()
</code>```

Title: Lxml xpath returns an empty array

Body:
Well guys, Im scraping : https://twitter.com/iForex_com/status/1019547735614255104

I would appreciate it if someone can help me out

import requests
from lxml import html

        finalurl = f"https://www.twitter.com/user/status/{id}"
        response = requests.get(finalurl,allow_redirects=True)
            tree = html.fromstring(response.content)
            print("getting photolink")
            postPhotoLink = tree.xpath('//*[@id="react-root"]/div/div/div/main/div/div/div/div[1]/div/div[2]/div/section/div/div/div/div[1]/div/article/div/div[4]/div/div/div/a/div/div[2]/div/img/@src')
                        print(postPhotoLink)

Result :

getting photolink
[]

Body:
thanks all for the help. I had to use selenium for this, otherwise request wasnt working properly, still having some trouble selecting just the number 2 img in the xpath thought. im selecting manually from the array, still works...

Complete working code

import requests
from lxml import html
from selenium import webdriver
import time

finalurl = "https://twitter.com/iForex_com/status/1019547735614255104"
browser = webdriver.Safari()
browser.get(finalurl)
time.sleep(1)

tree = html.fromstring(browser.page_source)
print("getting photolink")

postPhotoLink = tree.xpath('//img[@class="css-9pa8cd"]/@src')
print(postPhotoLink[1])

browser.close()


问:
Scheduler algorithms and scheduler policy
In linux operating system, what is the difference between "scheduler algorithms" and "scheduler policy"?

答:
From man 7 sched:

The scheduler is the kernel component that decides which runnable
         thread will be executed by the CPU next.  Each thread has an
         associated scheduling policy and a static scheduling priority,
         sched_priority.  The scheduler makes its decisions based on knowledge
         of the scheduling policy and static priority of all threads on the
         system.

So, in the case of scheduling on Linux, the scheduling algorithm schedules processes. It's simply the algorithm that solves that specific problem. Every thread has a scheduling policy, which determines how it is scheduled. Again from man 7 sched:

A  thread's scheduling policy determines where it will be inserted into
  the list of threads with equal static priority and  how  it  will  move
  inside this list.

Conclusion: the scheduling algorithm schedules according to one or more scheduling policies.


问:
Python - Generate a multiple row update query
My goal is dynamically generate in Python a SQL query similar to,

```<code>UPDATE SURV_SCF_ID_STATUS
    SET AGE_STATUS = CASE NAME
        WHEN 'entityXp1' THEN '1'
        WHEN 'entityXp3' THEN '0'
        WHEN 'entityXpto1' THEN '1'
        WHEN 'entityXpto3' THEN '1'
    END
WHERE NAME IN ('entityXp1', 'entityXp3', 'entityXpto1', 'entityXpto3')
</code>```

This is what I have so far,
but still feels like an ugly hack,

```<code>logs_age_list = [['entityXp1', '1'], ['entityXp3', '0'], ['entityXp1', '1'], ['entityXpto3', '1']]
conditions_list = []
where_list = []
for entity, status in logs_age_list:
conditions_list.append("\t\tWHEN %(entity)s THEN %(value)s" % locals() )
where_list.append(entity)

conditions_string = '\n'.join(conditions_list)
where_string = ', '.join(where_list)

sql = '''
UPDATE SURV_SCF_ID_STATUS
     SET AGE_STATUS = CASE NAME
%(conditions_string)s
END
WHERE NAME IN (%(where_string)s)
''' % locals()

print sql
</code>```

Is there some more obvious way to do it?
I didn't find any Python module which allow this.

Thanks

答:
You can build the condition_string via

```<code>conditions_string = ' '.join(["\t\tWHEN %s THEN %s\n" % (x, y) for x, y in logs_age_list])
</code>```

and the where_string as

```<code>where_string = ', '.join([duo[0] for duo inlogs_age_list])
</code>```

then do something like

```<code>sql = '''
UPDATE SURV_SCF_ID_STATUS
SET AGE_STATUS = CASE NAME
%s
END
WHERE NAME IN (%s)
''' % (conditions_string, where_string)
</code>```

But in generall you should try to use the execute methods of the DB modules to avoid SQL injection.

Here is an example taken from http://docs.python.org/library/sqlite3.html

```<code># Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)
</code>```

Body:
My goal is dynamically generate in Python a SQL query similar to,

UPDATE SURV_SCF_ID_STATUS
    SET AGE_STATUS = CASE NAME
        WHEN 'entityXp1' THEN '1'
        WHEN 'entityXp3' THEN '0'
        WHEN 'entityXpto1' THEN '1'
        WHEN 'entityXpto3' THEN '1'
    END
WHERE NAME IN ('entityXp1', 'entityXp3', 'entityXpto1', 'entityXpto3')

This is what I have so far,
but still feels like an ugly hack,

logs_age_list = [['entityXp1', '1'], ['entityXp3', '0'], ['entityXp1', '1'], ['entityXpto3', '1']]
conditions_list = []
where_list = []
for entity, status in logs_age_list:
conditions_list.append("\t\tWHEN %(entity)s THEN %(value)s" % locals() )
where_list.append(entity)

conditions_string = '\n'.join(conditions_list)
where_string = ', '.join(where_list)

sql = '''
UPDATE SURV_SCF_ID_STATUS
     SET AGE_STATUS = CASE NAME
%(conditions_string)s
END
WHERE NAME IN (%(where_string)s)
''' % locals()

print sql

Is there some more obvious way to do it?
I didn't find any Python module which allow this.

Thanks

Body:
You can build the condition_string via

conditions_string = ' '.join(["\t\tWHEN %s THEN %s\n" % (x, y) for x, y in logs_age_list])

and the where_string as

where_string = ', '.join([duo[0] for duo inlogs_age_list])

then do something like

sql = '''
UPDATE SURV_SCF_ID_STATUS
SET AGE_STATUS = CASE NAME
%s
END
WHERE NAME IN (%s)
''' % (conditions_string, where_string)

But in generall you should try to use the execute methods of the DB modules to avoid SQL injection.

Here is an example taken from http://docs.python.org/library/sqlite3.html

# Never do this -- insecure!
symbol = 'IBM'
c.execute("... where symbol = '%s'" % symbol)

# Do this instead
t = (symbol,)
c.execute('select * from stocks where symbol=?', t)


答:
You can add a SingleChildScrollView widget to enable scrolling when the keyboard appears.</p>

```<code> return SingleChildScrollView(
    child: Scaffold(
     body: Container(...)));
</code>```

Title: How can I ensure a button is visible when the keyboard is used?

Body:
You can add a SingleChildScrollView widget to enable scrolling when the keyboard appears.

 return SingleChildScrollView(
    child: Scaffold(
     body: Container(...)));


问:
Deny access to AWS S3 files for everyone but the application user
I am creating a web application where users sign in via Amazon Cognito. Once a user is logged in he can start uploading and downloading files from AWS S3 using a pre-signed url. The files are supposed to be secret and only the user who uploaded them should be able to read them. Is it possible to achieve this so that even the AWS account's root user cannot read the files?</p>

答: Only way to get this method to work is that the user will have to encrypt the file on their side, and then upload encrypted file, when they download the file later, it is decrypted so they can read.</p>


问:
Identify missing dates for ID & Date table
My approach to identify missing dates for IDs is to use a left table (t1) which is a calendar table of 100 years of dates and to LEFT join (on date=date) the master table (t2) which has date & ID .

I was hoping when I do the left join I would have a full list of dates ranging from 1-365 for each year in (t1) and then a joined id from (t2) when the dates match. When the date's are missing there should be a NULL.

The current output and the desired output from my script is attached here desired output

Simplified script below:

```<code>SELECT t1.date,
       t2.date,
       t2.id
FROM t1
LEFT JOIN t2 ON t1.date= t2.date
ORDER BY t1.date,t2.id ASC
</code>```

答:
Try This:</p>

```<code>SELECT t1.date, t2.date, t2.id
FROM t1 LEFT JOIN t2 ON t1.date= t2.date WHERE t2.ID = 28295 ORDER BY t1.date,t2.id ASC
</code>```

Body:
My approach to identify missing dates for IDs is to use a left table (t1) which is a calendar table of 100 years of dates and to LEFT join (on date=date) the master table (t2) which has date & ID .

I was hoping when I do the left join I would have a full list of dates ranging from 1-365 for each year in (t1) and then a joined id from (t2) when the dates match. When the date's are missing there should be a NULL.

The current output and the desired output from my script is attached here desired output

Simplified script below:

SELECT t1.date,
       t2.date,
       t2.id
FROM t1
LEFT JOIN t2 ON t1.date= t2.date
ORDER BY t1.date,t2.id ASC

Body:
Try This:

SELECT t1.date, t2.date, t2.id
FROM t1 LEFT JOIN t2 ON t1.date= t2.date WHERE t2.ID = 28295 ORDER BY t1.date,t2.id ASC


问:
New files added in a patch are removed during uninstall - even when marked permanent
Using InstallShield 2013 in a Basic MSI project. We have some ancient Microsoft COM DLLs that are shipped in merge modules which we include in our MSI. We now need to update a few of these DLLs with newer ones in a minor upgrade patch (MSP).  We don't have new merge modules from Microsoft so I'm trying to figure out how to get these new DLLs installed in our application.

I've added 2 new components, one for each file, and built the new MSP.  The files get installed properly, though I did have to register them manually in a custom action, otherwise the patch would be uninstallable (b/c I changed the Class table).  This is all good - so far.  However, when I remove the patch, these 2 new files are deleted!!  This is the problem. I would be OK with them being put back to the previous version - but no.  They're straight up deleted.  I marked the files as Permanent - same problem.  I nulled out the GUID for these two new files - same problem.  I would be OK with them being left at the new version since they're MS files.  I suspect it's not keeping these around because I'm only marking it permanent in the patch, not in the original MSI. Right?

```<code>Here's some MSI log info during the installation of the MSP:

MSI (s) (FC:C4) [16:53:38:949]: File = comctl32.ocx: Final State = Install
MSI (s) (FC:C4) [16:53:38:949]: File = osl.dll1.BD822168_4484_412B_AA08_455F82BE5E0F: Final State = Install
MSI (s) (FC:C4) [16:53:48:371]: SELMGR: Component 'comctl32.ocx' is a new component added to feature 'WDCoreComp'
MSI (s) (FC:C4) [16:53:49:371]: Component: comctl32.ocx; Installed: Absent;   Request: Local;   Action: Local;   Client State: Unknown
MSI (s) (FC:C4) [16:53:53:199]: Baseline: Existing comctl32.ocx version 6.0.81.5 does not match any baseline. Will not be cached.

Here's MSI log info from the uninstall of this MSP:
MSI (s) (FC:B8) [16:57:33:236]: File = comctl32.ocx: Final State = Remove
MSI (s) (FC:B8) [16:57:33:236]: File = osl.dll1.BD822168_4484_412B_AA08_455F82BE5E0F: Final State = Overwrite
MSI (s) (FC:B8) [16:58:01:939]: Executing op: FileRemove(,FileName=C:\Windows\SysWOW64\comctl32.ocx,,ComponentId={100B5DC4-FD2D-4311-9ADE-2B65B814F446})
</code>```

I included the osl.dll in there to indicate a normal patching routine for one of our DLLs where it's overwriting it with the old version, but it's removing the comctl32.ocx.

Other options seem VERY undesirable:

use Orca to hack the new bins into the old merge modules and rebuild the installer. Hopefully
the patch would recognize that they're new and install them properly

do this all manually in custom actions: during install save a copy of these files then install the new ones. During uninstall, restore the old versions from our saved copies

install the files in a temp folder, copy them to the official MS location, then register them there. Uninstall would only remove them from the temp folder and not the official MS location

Number 3 sounds least objectionable but still bad form to do all this manually in custom actions.

答: I first tried #3 but InstallShit thwarted me at every turn. I couldn't copy files into the "Common Files...\VBA" folder no matter what I tried. So, I ended up doing #1, though I used InstallShield to edit the merge modules. Fortunately, I was able to just replace the bins and resave the merge modules.</p>

Body:
Using InstallShield 2013 in a Basic MSI project. We have some ancient Microsoft COM DLLs that are shipped in merge modules which we include in our MSI. We now need to update a few of these DLLs with newer ones in a minor upgrade patch (MSP).  We don't have new merge modules from Microsoft so I'm trying to figure out how to get these new DLLs installed in our application.

I've added 2 new components, one for each file, and built the new MSP.  The files get installed properly, though I did have to register them manually in a custom action, otherwise the patch would be uninstallable (b/c I changed the Class table).  This is all good - so far.  However, when I remove the patch, these 2 new files are deleted!!  This is the problem. I would be OK with them being put back to the previous version - but no.  They're straight up deleted.  I marked the files as Permanent - same problem.  I nulled out the GUID for these two new files - same problem.  I would be OK with them being left at the new version since they're MS files.  I suspect it's not keeping these around because I'm only marking it permanent in the patch, not in the original MSI. Right?

Here's some MSI log info during the installation of the MSP:

MSI (s) (FC:C4) [16:53:38:949]: File = comctl32.ocx: Final State = Install
MSI (s) (FC:C4) [16:53:38:949]: File = osl.dll1.BD822168_4484_412B_AA08_455F82BE5E0F: Final State = Install
MSI (s) (FC:C4) [16:53:48:371]: SELMGR: Component 'comctl32.ocx' is a new component added to feature 'WDCoreComp'
MSI (s) (FC:C4) [16:53:49:371]: Component: comctl32.ocx; Installed: Absent;   Request: Local;   Action: Local;   Client State: Unknown
MSI (s) (FC:C4) [16:53:53:199]: Baseline: Existing comctl32.ocx version 6.0.81.5 does not match any baseline. Will not be cached.

Here's MSI log info from the uninstall of this MSP:
MSI (s) (FC:B8) [16:57:33:236]: File = comctl32.ocx: Final State = Remove
MSI (s) (FC:B8) [16:57:33:236]: File = osl.dll1.BD822168_4484_412B_AA08_455F82BE5E0F: Final State = Overwrite
MSI (s) (FC:B8) [16:58:01:939]: Executing op: FileRemove(,FileName=C:\Windows\SysWOW64\comctl32.ocx,,ComponentId={100B5DC4-FD2D-4311-9ADE-2B65B814F446})

I included the osl.dll in there to indicate a normal patching routine for one of our DLLs where it's overwriting it with the old version, but it's removing the comctl32.ocx.

Other options seem VERY undesirable:

use Orca to hack the new bins into the old merge modules and rebuild the installer. Hopefully
the patch would recognize that they're new and install them properly

do this all manually in custom actions: during install save a copy of these files then install the new ones. During uninstall, restore the old versions from our saved copies

install the files in a temp folder, copy them to the official MS location, then register them there. Uninstall would only remove them from the temp folder and not the official MS location

Number 3 sounds least objectionable but still bad form to do all this manually in custom actions.


问:
Aeson parse JSON with default value from previous parse
I want to parse the following json:

```<code>{
  "defaults": {
    "align": "left"
  },
  "animals": [
    {
      "kind": "cat",
      "name": "Oscar",
      "align": "center"
    },
    {
      "kind": "dog",
      "name": "Max"
    }
  ]
}
</code>```

Parse align:

data Align = Left | Center | Right

instance FromJSON Align where
  parseJSON (String "left")   = pure Left
  parseJSON (String "center") = pure Center
  parseJSON (String "right")  = pure Right
  parseJSON _ = fail "Expect one of [left, center, right]."
```

<p>Parse defaults:</p>

<pre class="lang-hs prettyprint-override"><code>data BlockDefaults = BlockDefaults { align :: Align }

-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }

instance FromJSON BlockDefaults where
  parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults
</code>```

Now I want to parse dog and cat.
If align does not exist (as in dog), it should take the value from defaults (left).
So dog should become Dog{name="Max", align=Center} and cat Cat{name="Oscar", align=Left}.

But how do I access the default align value in parseJSON?

-- pseudo parse code
instance FromJSON Animal where
  parseJSON = withObject "animal" $ \o ->
    Animal <$>
    o .: "kind" <*>
    o .: "name" <*>
    o .:? "align" .!= <DefaultValue> -- How to access value from defaults object?
```

<p>I do not want to parse defaults for every animal again, so how can I access those defaults values parsed before?
Assume there are much more values in <code>defaults</code> and other <code>animals</code>.</p>

<hr>

<p>So the animal parser code looks like this now:</p>

<pre class="lang-hs prettyprint-override"><code>parseAnimal :: BlockDefaults -> Value -> Parser Animal
parseAnimal defaults = withObject "animal" $ \o ->
  Animal <$>
    o .: "kind" <*>
    o .: "name" <*>
    (
      BlockDefaults <$>
      o .:? "align" .!= align defaults
    )
</code>```

答:
My commented suggestion was to use BlockDefaults -> Animal as the instance.  For example:

```<code>#!/usr/bin/env cabal
{- cabal:
     build-depends: base, aeson
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}

import Prelude hiding (Either(..)) -- This is why you don't name your constructors 'Left' and 'Right'
import Data.Aeson

data Align = Left | Center | Right
    deriving (Show)

instance FromJSON Align where
  parseJSON (String "left")   = pure Left
  parseJSON (String "center") = pure Center
  parseJSON (String "right")  = pure Right
  parseJSON _ = fail "Expect one of [left, center, right]."

data BlockDefaults = BlockDefaults { align :: Align }

-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }

instance FromJSON BlockDefaults where
  parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults

data Animal = Animal { kind   :: String
                     , name   :: String
                     , aalign :: Align
                     }
    deriving (Show)

instance FromJSON (BlockDefaults -> Animal) where
    parseJSON = withObject "Animal" $ \o ->
        do k <- o  .: "kind"
           n <- o  .: "name"
           a <- o .:? "align"
           pure $ \def -> Animal k n (maybe (align def) id a)

main :: IO ()
main = print (decode "{ \"kind\": \"k\", \"name\" : \"n\" }" <*> Just blockDefaults :: Maybe Animal)
</code>```

Body:
I want to parse the following json:

{
  "defaults": {
    "align": "left"
  },
  "animals": [
    {
      "kind": "cat",
      "name": "Oscar",
      "align": "center"
    },
    {
      "kind": "dog",
      "name": "Max"
    }
  ]
}

Parse align:

data Align = Left | Center | Right

instance FromJSON Align where
  parseJSON (String "left")   = pure Left
  parseJSON (String "center") = pure Center
  parseJSON (String "right")  = pure Right
  parseJSON _ = fail "Expect one of [left, center, right]."

Parse defaults:

data BlockDefaults = BlockDefaults { align :: Align }

-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }

instance FromJSON BlockDefaults where
  parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults

Now I want to parse dog and cat.
If align does not exist (as in dog), it should take the value from defaults (left).
So dog should become Dog{name="Max", align=Center} and cat Cat{name="Oscar", align=Left}.

But how do I access the default align value in parseJSON?

-- pseudo parse code
instance FromJSON Animal where
  parseJSON = withObject "animal" $ \o ->
    Animal <$>
    o .: "kind" <*>
    o .: "name" <*>
    o .:? "align" .!= <DefaultValue> -- How to access value from defaults object?

I do not want to parse defaults for every animal again, so how can I access those defaults values parsed before?
Assume there are much more values in defaults and other animals.

So the animal parser code looks like this now:

parseAnimal :: BlockDefaults -> Value -> Parser Animal
parseAnimal defaults = withObject "animal" $ \o ->
  Animal <$>
    o .: "kind" <*>
    o .: "name" <*>
    (
      BlockDefaults <$>
      o .:? "align" .!= align defaults
    )

Body:
My commented suggestion was to use BlockDefaults -> Animal as the instance.  For example:

#!/usr/bin/env cabal
{- cabal:
     build-depends: base, aeson
-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}

import Prelude hiding (Either(..)) -- This is why you don't name your constructors 'Left' and 'Right'
import Data.Aeson

data Align = Left | Center | Right
    deriving (Show)

instance FromJSON Align where
  parseJSON (String "left")   = pure Left
  parseJSON (String "center") = pure Center
  parseJSON (String "right")  = pure Right
  parseJSON _ = fail "Expect one of [left, center, right]."

data BlockDefaults = BlockDefaults { align :: Align }

-- default value Center if key does not exist
blockDefaults :: BlockDefaults
blockDefaults = BlockDefaults { align = Center }

instance FromJSON BlockDefaults where
  parseJSON = withObject "defaults" $ \o -> BlockDefaults <$> o .:? "align" .!= align blockDefaults

data Animal = Animal { kind   :: String
                     , name   :: String
                     , aalign :: Align
                     }
    deriving (Show)

instance FromJSON (BlockDefaults -> Animal) where
    parseJSON = withObject "Animal" $ \o ->
        do k <- o  .: "kind"
           n <- o  .: "name"
           a <- o .:? "align"
           pure $ \def -> Animal k n (maybe (align def) id a)

main :: IO ()
main = print (decode "{ \"kind\": \"k\", \"name\" : \"n\" }" <*> Just blockDefaults :: Maybe Animal)


问:
Updating a List of Object from another list of object using java stream
I have a list of Object A

```<code>A{
name
age
dob
}
</code>```

and list of Object B

```<code>B{
name
dob
}
</code>```

.

I always get the List of A with A.dob as null. and List of B with B.dob having value.
I need to loop thru List of A and List of B find the common objects using the name field in each A and B object and  update A.dob using B.dob

Can this be done using streams?

答:
You should not use Stream APIs to change the state of an Object.

If you still want to modify it then,
You can iterate each element from the list of A, filter if dob is null, find dob against the respective name in the list of B.

```<code>List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

aList.stream()
        .filter( a  -> a.dob == null)
        .forEach( a -> {
            Predicate<B> nameFilter = b -> b.name.equals(a.name);
            a.dob = findDob(nameFilter, bList);
        });

static String findDob(Predicate<B> nameFilter, List<B> bList) {
    B b = bList.stream()
            .filter(nameFilter)
            .findFirst()
            .orElse(new B());

    return b.dob;
}
</code>```

Alternate  efficient solution: Considering you have a unique name for each object B, you can prepare lookup and find age using that map, this way you do not need to iterate bList for every iteration of aList

```<code>List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

Map<String, String> nameDobLookup = bList.stream()
                        .collect(Collectors.toMap(b -> b.name, b -> b.dob));

aList.stream()
        .filter(a -> a.dob == null)
        .forEach(a -> a.dob = nameDobLookup.get(a.name));
</code>```

Body:
I have a list of Object A

A{
name
age
dob
}

and list of Object B

B{
name
dob
}

.

I always get the List of A with A.dob as null. and List of B with B.dob having value.
I need to loop thru List of A and List of B find the common objects using the name field in each A and B object and  update A.dob using B.dob

Can this be done using streams?

Body:
You should not use Stream APIs to change the state of an Object.

If you still want to modify it then,
You can iterate each element from the list of A, filter if dob is null, find dob against the respective name in the list of B.

List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

aList.stream()
        .filter( a  -> a.dob == null)
        .forEach( a -> {
            Predicate<B> nameFilter = b -> b.name.equals(a.name);
            a.dob = findDob(nameFilter, bList);
        });

static String findDob(Predicate<B> nameFilter, List<B> bList) {
    B b = bList.stream()
            .filter(nameFilter)
            .findFirst()
            .orElse(new B());

    return b.dob;
}

Alternate  efficient solution: Considering you have a unique name for each object B, you can prepare lookup and find age using that map, this way you do not need to iterate bList for every iteration of aList

List<A> aList = new ArrayList<>();
List<B> bList = new ArrayList<>();

Map<String, String> nameDobLookup = bList.stream()
                        .collect(Collectors.toMap(b -> b.name, b -> b.dob));

aList.stream()
        .filter(a -> a.dob == null)
        .forEach(a -> a.dob = nameDobLookup.get(a.name));