问:
Is this possible in SQL? Min and Max Dates On a Total. Where it changes in between Dates
I am trying to figure out how to write a query that will give me the correct historical data between dates. But only using sql. I know it is possible coding a loop, but I'm not sure if this is possible in a SQL query. Dates: DD/MM/YYYY

An Example of Data

ID
Points
DATE

1
10
01/01/2018

1
20
02/01/2019

1
25
03/01/2020

1
10
04/01/2021

With a simple query

```<code>SELECT ID, Points, MIN(Date), MAX(Date)
FROM table
GROUP BY ID,POINTS
</code>```

The Min date for 10 points would be 01/01/2018, and the Max Date would be 04/01/2021. Which would be wrong in this instance. As It should be:

ID
Points
Min DATE
Max DATE

1
10
01/01/2018
01/01/2019

1
20
02/01/2019
02/01/2020

1
25
03/01/2020
03/01/2021

1
10
04/01/2021
04/01/2021

I was thinking of using LAG, but need some ideas here. What I haven't told you is there is a record per day. So I would need to group until a change of points. This is to create a view from the data that I already have.

答:
(I am adding this as an alternative (and simpler) interpretation of the OP's question.)

Problem restatement: Given a collection if IDs, Dates, and Points values, a group is defined as any consecutive sequence of the same Points value for a given ID and ascending dates. For each such group, calculate the min and max dates.

The start of such a group can be identified as a row where the Points value changes from the preceding value, or if there is no preceding value for a given ID.  If we first tag such rows (NewGroup = 1), we can then assign group numbers based on a count of preceding tagged rows (including the current row). Once we have assigned group numbers, it is then a simple matter to apply a group and aggregate operation.

Below is a sample that includes some additional test data to show multiple IDs and repeating values.

```<code>DECLARE @Data TABLE (Id INT, Points INT, Date DATE)
INSERT @Data
VALUES
    (1, 10, '2018-01-01'), -- Start
    (1, 20, '2019-01-02'), -- Updated
    (1, 25, '2020-01-03'), -- Updated
    (1, 10, '2021-01-04'), -- Updated
    (2, 10, '2022-01-01'), -- Start
    (2, 20, '2022-02-01'), -- Updated
    (2, 20, '2022-03-01'), -- No change
    (2, 20, '2022-04-01'), -- No change
    (2, 20, '2022-05-01'), -- No change
    (2, 25, '2022-06-01'), -- Updated
    (2, 25, '2022-07-01'), -- No change
    (2, 20, '2022-08-01'), -- Updated
    (2, 25, '2022-09-08'), -- Updated
    (2, 10, '2022-10-09'), -- Updated
    (3, 10, '2022-01-01'), -- Start
    (3, 10, '2022-01-02'), -- No change
    (3, 20, '2022-01-03'), -- Updated
    (3, 20, '2022-01-04'), -- No change
    (3, 20, '2022-01-05'), -- No change
    (3, 10, '2022-01-06'), -- Updated
    (3, 10, '2022-01-07'); -- No change
</code>```
```<code>WITH CTE AS (
    SELECT *,
        PriorPoints = LAG(Points) OVER (PARTITION BY Id ORDER BY Date)
    FROM @Data
)
, CTE2 AS (
    SELECT *,
        NewGroup = CASE WHEN (PriorPoints <> Points OR PriorPoints IS NULL)
            THEN 1 ELSE 0 END
    FROM CTE
)
, CTE3 AS (
    SELECT *, GroupNo = SUM(NewGroup) OVER(
        PARTITION BY ID
        ORDER BY Date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        )
    FROM CTE2
)
SELECT Id, Points, MinDate = MIN(Date), MaxDate = MAX(Date)
FROM CTE3
GROUP BY Id, GroupNo, Points
ORDER BY Id, GroupNo
</code>```

Results:

Id
Points
MinDate
MaxDate

1
10
2018-01-01
2018-01-01

1
20
2019-01-02
2019-01-02

1
25
2020-01-03
2020-01-03

1
10
2021-01-04
2021-01-04

2
10
2022-01-01
2022-01-01

2
20
2022-02-01
2022-05-01

2
25
2022-06-01
2022-07-01

2
20
2022-08-01
2022-08-01

2
25
2022-09-08
2022-09-08

2
10
2022-10-09
2022-10-09

3
10
2022-01-01
2022-01-02

3
20
2022-01-03
2022-01-05

3
10
2022-01-06
2022-01-07

To see the intermediate results, replace the final select with SELECT * FROM CTE3 ORDER BY Id, Date.

If you wish to treat gaps in dates as group criteria, add a PriorDate calculation to CTE and add OR Date <> PriorDate to the NewGroup condition.

db<>fiddle

Caution: In your original post, you state that "this is to create a view". Beware that if the above logic is included in a view, the entire result may be recalculated every time the view is accessed, regardless of any ID or date criteria applied. It might make more sense to use the above to populate and periodically refresh a historic roll-up data table for efficient access. Another alternative is to make a stored procedure with appropriate parameters that could filter that data before feeding it into the above.

Body:
I am trying to figure out how to write a query that will give me the correct historical data between dates. But only using sql. I know it is possible coding a loop, but I'm not sure if this is possible in a SQL query. Dates: DD/MM/YYYY

An Example of Data

ID
Points
DATE

1
10
01/01/2018

1
20
02/01/2019

1
25
03/01/2020

1
10
04/01/2021

With a simple query

SELECT ID, Points, MIN(Date), MAX(Date)
FROM table
GROUP BY ID,POINTS

The Min date for 10 points would be 01/01/2018, and the Max Date would be 04/01/2021. Which would be wrong in this instance. As It should be:

ID
Points
Min DATE
Max DATE

1
10
01/01/2018
01/01/2019

1
20
02/01/2019
02/01/2020

1
25
03/01/2020
03/01/2021

1
10
04/01/2021
04/01/2021

I was thinking of using LAG, but need some ideas here. What I haven't told you is there is a record per day. So I would need to group until a change of points. This is to create a view from the data that I already have.

Body:
(I am adding this as an alternative (and simpler) interpretation of the OP's question.)

Problem restatement: Given a collection if IDs, Dates, and Points values, a group is defined as any consecutive sequence of the same Points value for a given ID and ascending dates. For each such group, calculate the min and max dates.

The start of such a group can be identified as a row where the Points value changes from the preceding value, or if there is no preceding value for a given ID.  If we first tag such rows (NewGroup = 1), we can then assign group numbers based on a count of preceding tagged rows (including the current row). Once we have assigned group numbers, it is then a simple matter to apply a group and aggregate operation.

Below is a sample that includes some additional test data to show multiple IDs and repeating values.

DECLARE @Data TABLE (Id INT, Points INT, Date DATE)
INSERT @Data
VALUES
    (1, 10, '2018-01-01'), -- Start
    (1, 20, '2019-01-02'), -- Updated
    (1, 25, '2020-01-03'), -- Updated
    (1, 10, '2021-01-04'), -- Updated
    (2, 10, '2022-01-01'), -- Start
    (2, 20, '2022-02-01'), -- Updated
    (2, 20, '2022-03-01'), -- No change
    (2, 20, '2022-04-01'), -- No change
    (2, 20, '2022-05-01'), -- No change
    (2, 25, '2022-06-01'), -- Updated
    (2, 25, '2022-07-01'), -- No change
    (2, 20, '2022-08-01'), -- Updated
    (2, 25, '2022-09-08'), -- Updated
    (2, 10, '2022-10-09'), -- Updated
    (3, 10, '2022-01-01'), -- Start
    (3, 10, '2022-01-02'), -- No change
    (3, 20, '2022-01-03'), -- Updated
    (3, 20, '2022-01-04'), -- No change
    (3, 20, '2022-01-05'), -- No change
    (3, 10, '2022-01-06'), -- Updated
    (3, 10, '2022-01-07'); -- No change

WITH CTE AS (
    SELECT *,
        PriorPoints = LAG(Points) OVER (PARTITION BY Id ORDER BY Date)
    FROM @Data
)
, CTE2 AS (
    SELECT *,
        NewGroup = CASE WHEN (PriorPoints <> Points OR PriorPoints IS NULL)
            THEN 1 ELSE 0 END
    FROM CTE
)
, CTE3 AS (
    SELECT *, GroupNo = SUM(NewGroup) OVER(
        PARTITION BY ID
        ORDER BY Date
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
        )
    FROM CTE2
)
SELECT Id, Points, MinDate = MIN(Date), MaxDate = MAX(Date)
FROM CTE3
GROUP BY Id, GroupNo, Points
ORDER BY Id, GroupNo

Results:

Id
Points
MinDate
MaxDate

1
10
2018-01-01
2018-01-01

1
20
2019-01-02
2019-01-02

1
25
2020-01-03
2020-01-03

1
10
2021-01-04
2021-01-04

2
10
2022-01-01
2022-01-01

2
20
2022-02-01
2022-05-01

2
25
2022-06-01
2022-07-01

2
20
2022-08-01
2022-08-01

2
25
2022-09-08
2022-09-08

2
10
2022-10-09
2022-10-09

3
10
2022-01-01
2022-01-02

3
20
2022-01-03
2022-01-05

3
10
2022-01-06
2022-01-07

To see the intermediate results, replace the final select with SELECT * FROM CTE3 ORDER BY Id, Date.

If you wish to treat gaps in dates as group criteria, add a PriorDate calculation to CTE and add OR Date <> PriorDate to the NewGroup condition.

db<>fiddle

Caution: In your original post, you state that "this is to create a view". Beware that if the above logic is included in a view, the entire result may be recalculated every time the view is accessed, regardless of any ID or date criteria applied. It might make more sense to use the above to populate and periodically refresh a historic roll-up data table for efficient access. Another alternative is to make a stored procedure with appropriate parameters that could filter that data before feeding it into the above.


来源: stackexchange

问:
How do I deploy a Node.js app to a Azure App Service from Visual Studio 2019?
I created a simple node.js express app that I want to host in an Azure Windows App Service.
The App Service resource was created successfully on Azure.
The project was created using the "Node.js Web Application" template.

When I attempt to deploy from Visual Studio 2019, I get the following error message:

web.config not found in project, to create a project to deploy to
Microsoft Azure you must create an Azure Node.js project.

Is there a different template I should be using?
If not, what the contents of the web.config file look like, so I can attempt to create it by hand.

答:
For deploying Node js Application to Azure you need to select
Azure Node js Web Application Template.

You have selected Node.js Web Application.

If you select Azure Node js App, by default web.config will be generated.

Copy the already created source files to the newly created Azure node.js Application.

Update

You might not have selected Node.js development option while installing Visual studio.
Click on the Install more tools and features option and select Node.js and update the VS

ContentLicense: CC BY-SA 4.0


问:
How does one extract a unified-diff style patch subset?
Every time I want to take a subset of a patch, I'm forced to write a script to only extract the indices that I want.

e.g. I have a patch that applies to sub directories
'yay' and 'foo'.

Is there a way to create a new patch or apply only a subset of a patch?  i.e. create a new patch from the existing patch that only takes all indices that are under sub directory 'yay'. Or all indices that are not under sub directory 'foo'

If I have a patch like  ( excuse the below pseudo-patch):

```<code>Index : foo/bar
 yada
 yada
- asdf
+ jkl
 yada
 yada
Index : foo/bah
 blah
 blah
- 28
+ 29
 blah
 blah
 blah
Index : yay/team
 go
 huskies
- happy happy
+ joy joy
 cougars
 suck
</code>```

How can I extract or apply only the 'yay' subdirectory like:

```<code>Index : yay/team
 go
 huskies
- happy happy
+ joy joy
 cougars
 suck
</code>```

I know if I script up a solution I'll be re-inventing the wheel...

答:
Here's my quick and dirty Perl solution.</p>

```<code>perl -ne '@a = split /^Index :/m, join "", <>; END { for(@a) {print "Index :", $_ if (m, yay/team,)}}' < foo.patch
</code>```

OwnerDisplayName: Ross Rogers

ContentLicense: CC BY-SA 2.5

Body:
Every time I want to take a subset of a patch, I'm forced to write a script to only extract the indices that I want.

e.g. I have a patch that applies to sub directories
'yay' and 'foo'.

Is there a way to create a new patch or apply only a subset of a patch?  i.e. create a new patch from the existing patch that only takes all indices that are under sub directory 'yay'. Or all indices that are not under sub directory 'foo'

If I have a patch like  ( excuse the below pseudo-patch):

Index : foo/bar
 yada
 yada
- asdf
+ jkl
 yada
 yada
Index : foo/bah
 blah
 blah
- 28
+ 29
 blah
 blah
 blah
Index : yay/team
 go
 huskies
- happy happy
+ joy joy
 cougars
 suck

How can I extract or apply only the 'yay' subdirectory like:

Index : yay/team
 go
 huskies
- happy happy
+ joy joy
 cougars
 suck

I know if I script up a solution I'll be re-inventing the wheel...

Body:
Here's my quick and dirty Perl solution.

perl -ne '@a = split /^Index :/m, join "", <>; END { for(@a) {print "Index :", $_ if (m, yay/team,)}}' < foo.patch

OwnerDisplayName: sigjuice

LastEditorDisplayName: sigjuice


问:
selenium hide chromdriver console window
I have created a program with python where I am using selenium. I also created a .exe with pyinstaller. If I run the .exe chrome opens normally. But for some reason, the console appears too. This only happens if I am launching the .exe. If I launch the code in VS Code only the chrome window appears.

I found something that is written in C#:

```<code>var driverService = ChromeDriverService.CreateDefaultService();
driverService.HideCommandPromptWindow = true;

var driver = new ChromeDriver(driverService, new ChromeOptions());
</code>```

My chromdriver setup:

```<code>option = webdriver.ChromeOptions()
option.add_argument("--incogneto")
chromedriver_path = driverPath
browser = webdriver.Chrome(chromedriver_path)
browser.set_window_size(1100, 800)
browser.get("myurl")
</code>```

How can I do this in Python?

答:
Selenium4 is released with this feature! No need to edit library code.

```<code>from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService # Similar thing for firefox also!
from subprocess import CREATE_NO_WINDOW # This flag will only be available in windows

# Define your own service object with the `CREATE_NO_WINDOW ` flag
# If chromedriver.exe is not in PATH, then use:
# ChromeService('/path/to/chromedriver')
chrome_service = ChromeService('chromedriver')
chrome_service.creationflags = CREATE_NO_WINDOW

driver = webdriver.Chrome(service=chrome_service)
</code>```

Update with pip install selenium OR upgrade the package pip install selenium --upgrade

Body:
I have created a program with python where I am using selenium. I also created a .exe with pyinstaller. If I run the .exe chrome opens normally. But for some reason, the console appears too. This only happens if I am launching the .exe. If I launch the code in VS Code only the chrome window appears.

I found something that is written in C#:

var driverService = ChromeDriverService.CreateDefaultService();
driverService.HideCommandPromptWindow = true;

var driver = new ChromeDriver(driverService, new ChromeOptions());

My chromdriver setup:

option = webdriver.ChromeOptions()
option.add_argument("--incogneto")
chromedriver_path = driverPath
browser = webdriver.Chrome(chromedriver_path)
browser.set_window_size(1100, 800)
browser.get("myurl")

How can I do this in Python?

Body:
Selenium4 is released with this feature! No need to edit library code.

from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService # Similar thing for firefox also!
from subprocess import CREATE_NO_WINDOW # This flag will only be available in windows

# Define your own service object with the `CREATE_NO_WINDOW ` flag
# If chromedriver.exe is not in PATH, then use:
# ChromeService('/path/to/chromedriver')
chrome_service = ChromeService('chromedriver')
chrome_service.creationflags = CREATE_NO_WINDOW

driver = webdriver.Chrome(service=chrome_service)

Update with pip install selenium OR upgrade the package pip install selenium --upgrade


问:
#ORA-01834 not a valid month
When I insert data into DB, it shows the messege "ORA-01834 not a valid month  ".
My inserted value is like '17-07-19 06.34.11', I Want to know what's the correct value</p>

答:
Use TO_DATE function with appropriate format mask, e.g.

```<code>insert into your_table (date_column)
  values (to_date('17-07-19 06.34.11', 'dd-mm-yy hh24:mi:ss'));
</code>```

By the way, switch to a 4-digit year ("2019" instead of "19").

Title: #ORA-01834 not a valid month

Body:
Use TO_DATE function with appropriate format mask, e.g.

insert into your_table (date_column)
  values (to_date('17-07-19 06.34.11', 'dd-mm-yy hh24:mi:ss'));

By the way, switch to a 4-digit year ("2019" instead of "19").


问:
Compare two array of objects and remove objects from first array if a property value is matched
I have 2 array of objects like

```<code>    const arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
    const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
</code>```

Here, I need to compare both these arrays and remove matching objects from arrayOne, which should finally give

```<code> this.arrayOne = [{id: 1, name: 'one'}];
</code>```

I tried like below but it is removing all objects from the array

```<code>this.arrayOne = this.arrayOne.filter(o1 => this.arrayTwo.some(o2 => o1.id === o2.id));
</code>```

What I am doing wrong here? Please suggest. Thanks

答:
You can find it by comparing it with id.

And arrayOne must be a let.

   let arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
   const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];

   arrayOne = arrayOne.filter(one => !arrayTwo.find(two => one.id == two.id));

   console.log(arrayOne);

```

Body:
I have 2 array of objects like

    const arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
    const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];

Here, I need to compare both these arrays and remove matching objects from arrayOne, which should finally give

 this.arrayOne = [{id: 1, name: 'one'}];

I tried like below but it is removing all objects from the array

this.arrayOne = this.arrayOne.filter(o1 => this.arrayTwo.some(o2 => o1.id === o2.id));

What I am doing wrong here? Please suggest. Thanks


问:
Does #id override the :hover change?
I've seen different similar answers but none with the level of nesting I'm dealing with. I have two sets of buttons, circular ones and rectangular ones that I want the background to change to white on hover. The only thing I have been able to successfully change is the text color for the rectangular ones.

I previously had the button styles inline and thought that was the issue. Guess not :/

Does the ID override the :hover change? And if so do I need to reformat all of my buttons? Thank you!

(previous code solutions involve jquery and I have no knowledge of it whatsoever)

/*
    CS 81 Final - Noah Derby
*/

//Global Variables
"use strict";
let gameActive = false;
let dealerValue = 0;
let playerValue = 0;
let buttons = document.getElementsByTagName('button');
let totalAmount = document.getElementById('betAmount');
let bank = document.getElementById('bank');

//Card Functions and
function Card(value, name, suit) {
    this.value = value;
    this.name = name
    this.suit = suit
}

function newDeck() {
    let suits = ['Hearts','Diamonds','Spades','Clubs'];
    let names = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
    let deck = []
    for(let i of suits) {
        for(let n=0; n < names.length; n++) {
            deck.push(new Card(n+1, names[n], i));
        }
    }

    for (let i = deck.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        const temp = deck[i];
        deck[i] = deck[j];
        deck[j] = temp;
    }
    return deck;
}

function addTo(player, card){
    let ascii_char;
    let div = document.createElement('card');
    div.className = 'card';

    if(card.suit === 'Diamonds'){
        ascii_char = "♦";
        div.style.color = 'red';
    } else if (card.suit === 'Hearts') {
        ascii_char = '♥'
        div.style.color = 'red';
    } else {
        ascii_char = "&" + card.suit.toLowerCase() + ";"
    }

    div.innerHTML = "" + card.name + "" + ascii_char + "";

    if(player.id === "dealerTotal"){
        document.querySelector(".dealerCards").appendChild(div);
    } else {
        document.querySelector(".playerCards").appendChild(div);
    }

    if (card.value > 10){
        player.value = parseInt(player.value, 10) + 10;
    } else if (card.value === 1) {
        let handValue = parseInt(player.value, 10);
        if(handValue <= 10) {
            player.value = handValue + 11
        } else {
            player.value = handValue + 1
        }
    } else {
        player.value = parseInt(player.value, 10) + card.value;
    }
}

function clearCards() {
    document.querySelector(".dealerCards").innerHTML = "";
    document.querySelector(".playerCards").innerHTML = "";
}

//Button Handlers
for (let i=0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', () => {
        let playerTotal = document.getElementById("playerTotal");
        let dealerTotal = document.getElementById("dealerTotal");
        let bankValue = parseInt(bank.value, 10);
        let amountValue = parseInt(totalAmount.value, 10);
        let cards = newDeck();

        switch (buttons[i].id) {
            case "one":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1;
                    break;
                }
                break;
            case "five":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 5;
                    break;
                }
                break;
            case "ten":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 10;
                    break;
                }
                break;
            case "twentyfive":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 25;
                    break;
                }
                break;
            case "hundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 100;
                    break;
                }
                break
            case "fivehundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 500;
                    break;
                }
                break;
            case "thousand":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1000;
                    break;
                }
                break;
            case "reset":
                if (!gameActive){
                    totalAmount.value = 0;
                    break;
                }
                break;
            case "submit":
                if(!gameActive){
                    if (bankValue === 0) {
                        alert("No funds available :(");
                        break;
                    } else if (amountValue === 0) {
                        alert("Please Enter a valid amount")
                        break;
                    } else if(amountValue > bankValue){
                        totalAmount.value = bank.value;
                        bank.value = 0;
                    } else{
                        bank.value = bankValue - amountValue;
                    }
                    clearCards();
                    playerTotal.value = dealerTotal.value = '0';
                    addTo(playerTotal, cards.pop());
                    addTo(playerTotal, cards.pop());
                    addTo(dealerTotal, cards.pop());

                    dealerTotal.style.color = "transparent";
                    gameActive = true;
                    break;
                }
                break;
            case "hit":
                if(gameActive) {
                    addTo(playerTotal, cards.pop())
                    if(parseInt(playerTotal.value, 10) > 21){
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        dealerTotal.style.color = "black";
                        totalAmount.value= '0';
                        gameActive = false;
                        break;
                    }
                }
                break;
            case 'stand':
                if (gameActive) {
                    playerValue = parseInt(playerTotal.value, 10);
                    while(parseInt(dealerTotal.value, 10) <= 17){
                        addTo(dealerTotal, cards.pop());
                    }
                    dealerValue = parseInt(dealerTotal.value, 10);
                    if (dealerValue > 21){
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = 0;
                        gameActive = false;
                        dealerTotal.style.color = "black";
                        break;
                    }

                    if (playerValue < dealerValue) {
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        totalAmount.value= '0';
                    } else if (playerValue > dealerValue) {
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = '0';
                    } else {
                        alert(`Its a tie! Funds refunded!`);
                        bank.value = bankValue + amountValue;
                        totalAmount.value= '0';
                    }
                    dealerTotal.style.color = "black";
                    gameActive = false;
                }
                break;
        }
    }, false)
}```
<pre class="snippet-code-css lang-css prettyprint-override"><code>/*   CS 81 Final - Noah Derby   */

body {
    background-image: url('https://cdn.hipwallpaper.com/i/46/65/hEiUkp.jpg');
    background-size: cover;
    font-family: Verdana, sans-serif, bold;
    font-weight: bold;
    margin: 5px;
}

header {
    text-align: center;
    font-size: 50px;
    margin: 50px 500px -50px;
}

label{
    font-size: 25px;
}

input{
    font-size: 25px;
    color: black;
    background-color: white;
}

div {
    margin: 5px;
}

.economyWrap{
    position: relative;
    float: left;
    width: 480px;
    height: 500px;
    top: 100px;
    left: 50px;
}

.playWrap{
    position: relative;
    border: 5px solid black;
    float: left;
    top: 100px;
    width: 260px;
    height: 300px;
    margin-left: 140px;
}

.textContainer{
    padding: 5px;
    background: rgba(0, 128, 0, 0.02);
    margin: 200px 0 0 125px;
    width: 400px;
    float: left;
}

.playButtonContainer{
    position: absolute;
    margin: 17px;
    bottom:-90px;
}

.earningsContainer{
    position: absolute;
    width: 450px;
    height: 35px;
    padding: 5px;
    top:0;
    left:85px;
}

.submitContainer {
    margin: auto;
    position: absolute;
    width: 340px;
    bottom: 220px;
    left: 120px;
}

.chipContainer{
    margin: auto;
    position: absolute;
    height: 210px;
    width: 250px;
    left: 140px;
    bottom: 0;
}

/*
    Buttons
*/

button.chip{
    display: inline-block;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 15px;
    font-weight: bold;
    border-radius: 50%;
    height: 52px;
    width: 52px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#one {
    background-color: rgba(34,31,32,0.95);
    color:white;
    border: 5px solid rgba(209,212,213,0.95);
}

#five {
    background-color: rgba(242,122,128,0.95);
    color: rgba(148,30,28,0.95);
    border: 5px solid rgba(235,53,45,0.95);
}

#ten {
    background-color: rgba(169,219,203,0.95);
    color: rgba(13,45,76,0.95);
    border: 5px solid rgba(3,90,136,0.95);
}

#twentyfive {
    background-color: rgba(235,232,64,0.95);
    color: rgba(51,123,18,0.95);
    border: 5px solid rgba(57,134,63,0.95);
}

#hundred {
    background-color: #fdf049;
    color: rgb(235,53,45);
    border: 5px solid rgb(235,53,45);
}

#fivehundred {
    background-color: #b6b0d5;
    color: rgb(71,45,126);
    border: 5px solid rgb(126,70,155);
}

#thousand {
    background-color: #fffef6;
    color: rgb(34,31,31);
    border: 5px solid #59585a;
}

button.bet {
    display: inline-block;
    border-radius: 10px;
    border: 4px solid saddlebrown;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 14px;
    font-weight: bold;
    height: 50px;
    width: 100px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#submit {
    background-color: #358535;
}

#reset {
    background-color: yellow;
}

#hit {
    background-color: lightcoral;
}

#stand {
    background-color: lightgreen;
}

.card{
    background-color: white;
    width:40px;
    height:60px;
    border:1px solid #151718;
    float:left;
    border-radius:2px;
}

.number, .suit{
    width:100%;
    display:block;
    text-align:center;
    padding-top:8px;
}

button:hover {
    background-color: white;
}</code>```

<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>Blackjack!</title>
    <link rel="stylesheet" href="style.css">

Blackjack!

        Your Balance is: $ <input type="number" id="bank" value="1000" style="width: 100px;" disabled>

        <button id="one" class="chip">1</button>
        <button id="five" class="chip">5</button>
        <button id="ten" class="chip" >10</button>
        <button id="twentyfive" class="chip">25</button>
        <button id="hundred" class="chip">100</button>
        <button id="fivehundred" class="chip">500</button>
        <button id="thousand" class="chip">1k</button>

        Bet Amount: $ <input type="number" id="betAmount" value="0" style="margin:5px; width: 100px;" disabled>
        <button id="reset" class="bet">Reset</button>
        <button id="submit" class="bet">Submit</button>

        Dealer Total: <input value="0" id="dealerTotal" style=" width: 50px;" disabled>

        Your Total: <input value="0" id="playerTotal" style="bottom:0; width: 50px;" disabled>

        <button class="bet" id="hit" style="background-color: lightgreen;">Hit</button>
        <button class="bet" id="stand" style="background-color: lightcoral;">Stand</button>

Welcome to Blackjack!

        To start, click the corresponding chips to place your bets and click "Submit" to start the game!
        The goal is to reach 21, so you can decide to either hit (gain another card) or stand (wait for the dealer).
        Whoever is closer to 21 without going over wins!

```

答:
Question - Does the ID override the :hover change?

Answer -
The style rule for a:hover will override the paragraph as long as it is written in the CSS after the rule for p or #id.
The problem is that the selector handling your :hover behavior has a lower Specificity than the rule for the default behavior (p#id selector).

Question -  If so do I need to reformat all of my buttons?

Answer - No, you don't need to reformat all the buttons as you can use !important on the button:hover in the CSS file.

/*
    CS 81 Final - Noah Derby
*/

//Global Variables
"use strict";
let gameActive = false;
let dealerValue = 0;
let playerValue = 0;
let buttons = document.getElementsByTagName('button');
let totalAmount = document.getElementById('betAmount');
let bank = document.getElementById('bank');

//Card Functions and
function Card(value, name, suit) {
    this.value = value;
    this.name = name
    this.suit = suit
}

function newDeck() {
    let suits = ['Hearts','Diamonds','Spades','Clubs'];
    let names = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
    let deck = []
    for(let i of suits) {
        for(let n=0; n < names.length; n++) {
            deck.push(new Card(n+1, names[n], i));
        }
    }

    for (let i = deck.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        const temp = deck[i];
        deck[i] = deck[j];
        deck[j] = temp;
    }
    return deck;
}

function addTo(player, card){
    let ascii_char;
    let div = document.createElement('card');
    div.className = 'card';

    if(card.suit === 'Diamonds'){
        ascii_char = "♦";
        div.style.color = 'red';
    } else if (card.suit === 'Hearts') {
        ascii_char = '♥'
        div.style.color = 'red';
    } else {
        ascii_char = "&" + card.suit.toLowerCase() + ";"
    }

    div.innerHTML = "" + card.name + "" + ascii_char + "";

    if(player.id === "dealerTotal"){
        document.querySelector(".dealerCards").appendChild(div);
    } else {
        document.querySelector(".playerCards").appendChild(div);
    }

    if (card.value > 10){
        player.value = parseInt(player.value, 10) + 10;
    } else if (card.value === 1) {
        let handValue = parseInt(player.value, 10);
        if(handValue <= 10) {
            player.value = handValue + 11
        } else {
            player.value = handValue + 1
        }
    } else {
        player.value = parseInt(player.value, 10) + card.value;
    }
}

function clearCards() {
    document.querySelector(".dealerCards").innerHTML = "";
    document.querySelector(".playerCards").innerHTML = "";
}

//Button Handlers
for (let i=0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', () => {
        let playerTotal = document.getElementById("playerTotal");
        let dealerTotal = document.getElementById("dealerTotal");
        let bankValue = parseInt(bank.value, 10);
        let amountValue = parseInt(totalAmount.value, 10);
        let cards = newDeck();

        switch (buttons[i].id) {
            case "one":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1;
                    break;
                }
                break;
            case "five":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 5;
                    break;
                }
                break;
            case "ten":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 10;
                    break;
                }
                break;
            case "twentyfive":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 25;
                    break;
                }
                break;
            case "hundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 100;
                    break;
                }
                break
            case "fivehundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 500;
                    break;
                }
                break;
            case "thousand":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1000;
                    break;
                }
                break;
            case "reset":
                if (!gameActive){
                    totalAmount.value = 0;
                    break;
                }
                break;
            case "submit":
                if(!gameActive){
                    if (bankValue === 0) {
                        alert("No funds available :(");
                        break;
                    } else if (amountValue === 0) {
                        alert("Please Enter a valid amount")
                        break;
                    } else if(amountValue > bankValue){
                        totalAmount.value = bank.value;
                        bank.value = 0;
                    } else{
                        bank.value = bankValue - amountValue;
                    }
                    clearCards();
                    playerTotal.value = dealerTotal.value = '0';
                    addTo(playerTotal, cards.pop());
                    addTo(playerTotal, cards.pop());
                    addTo(dealerTotal, cards.pop());

                    dealerTotal.style.color = "transparent";
                    gameActive = true;
                    break;
                }
                break;
            case "hit":
                if(gameActive) {
                    addTo(playerTotal, cards.pop())
                    if(parseInt(playerTotal.value, 10) > 21){
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        dealerTotal.style.color = "black";
                        totalAmount.value= '0';
                        gameActive = false;
                        break;
                    }
                }
                break;
            case 'stand':
                if (gameActive) {
                    playerValue = parseInt(playerTotal.value, 10);
                    while(parseInt(dealerTotal.value, 10) <= 17){
                        addTo(dealerTotal, cards.pop());
                    }
                    dealerValue = parseInt(dealerTotal.value, 10);
                    if (dealerValue > 21){
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = 0;
                        gameActive = false;
                        dealerTotal.style.color = "black";
                        break;
                    }

                    if (playerValue < dealerValue) {
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        totalAmount.value= '0';
                    } else if (playerValue > dealerValue) {
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = '0';
                    } else {
                        alert(`Its a tie! Funds refunded!`);
                        bank.value = bankValue + amountValue;
                        totalAmount.value= '0';
                    }
                    dealerTotal.style.color = "black";
                    gameActive = false;
                }
                break;
        }
    }, false)
}```
<pre class="snippet-code-css lang-css prettyprint-override"><code>/*   CS 81 Final - Noah Derby   */

body {
    background-image: url('https://cdn.hipwallpaper.com/i/46/65/hEiUkp.jpg');
    background-size: cover;
    font-family: Verdana, sans-serif, bold;
    font-weight: bold;
    margin: 5px;
}

header {
    text-align: center;
    font-size: 50px;
    margin: 50px 500px -50px;
}

label{
    font-size: 25px;
}

input{
    font-size: 25px;
    color: black;
    background-color: white;
}

div {
    margin: 5px;
}

.economyWrap{
    position: relative;
    float: left;
    width: 480px;
    height: 500px;
    top: 100px;
    left: 50px;
}

.playWrap{
    position: relative;
    border: 5px solid black;
    float: left;
    top: 100px;
    width: 260px;
    height: 300px;
    margin-left: 140px;
}

.textContainer{
    padding: 5px;
    background: rgba(0, 128, 0, 0.02);
    margin: 200px 0 0 125px;
    width: 400px;
    float: left;
}

.playButtonContainer{
    position: absolute;
    margin: 17px;
    bottom:-90px;
}

.earningsContainer{
    position: absolute;
    width: 450px;
    height: 35px;
    padding: 5px;
    top:0;
    left:85px;
}

.submitContainer {
    margin: auto;
    position: absolute;
    width: 340px;
    bottom: 220px;
    left: 120px;
}

.chipContainer{
    margin: auto;
    position: absolute;
    height: 210px;
    width: 250px;
    left: 140px;
    bottom: 0;
}

/*
    Buttons
*/

button.chip{
    display: inline-block;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 15px;
    font-weight: bold;
    border-radius: 50%;
    height: 52px;
    width: 52px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#one {
    background-color: rgba(34,31,32,0.95);
    color:white;
    border: 5px solid rgba(209,212,213,0.95);
}

#five {
    background-color: rgba(242,122,128,0.95);
    color: rgba(148,30,28,0.95);
    border: 5px solid rgba(235,53,45,0.95);
}

#ten {
    background-color: rgba(169,219,203,0.95);
    color: rgba(13,45,76,0.95);
    border: 5px solid rgba(3,90,136,0.95);
}

#twentyfive {
    background-color: rgba(235,232,64,0.95);
    color: rgba(51,123,18,0.95);
    border: 5px solid rgba(57,134,63,0.95);
}

#hundred {
    background-color: #fdf049;
    color: rgb(235,53,45);
    border: 5px solid rgb(235,53,45);
}

#fivehundred {
    background-color: #b6b0d5;
    color: rgb(71,45,126);
    border: 5px solid rgb(126,70,155);
}

#thousand {
    background-color: #fffef6;
    color: rgb(34,31,31);
    border: 5px solid #59585a;
}

button.bet {
    display: inline-block;
    border-radius: 10px;
    border: 4px solid saddlebrown;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 14px;
    font-weight: bold;
    height: 50px;
    width: 100px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#submit {
    background-color: #358535;
}

#reset {
    background-color: yellow;
}

#hit {
    background-color: lightcoral;
}

#stand {
    background-color: lightgreen;
}

.card{
    background-color: white;
    width:40px;
    height:60px;
    border:1px solid #151718;
    float:left;
    border-radius:2px;
}

.number, .suit{
    width:100%;
    display:block;
    text-align:center;
    padding-top:8px;
}

button:hover {
    background-color: white !important;
}</code>```

<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>Blackjack!</title>
    <link rel="stylesheet" href="style.css">

Blackjack!

        Your Balance is: $ <input type="number" id="bank" value="1000" style="width: 100px;" disabled>

        <button id="one" class="chip">1</button>
        <button id="five" class="chip">5</button>
        <button id="ten" class="chip" >10</button>
        <button id="twentyfive" class="chip">25</button>
        <button id="hundred" class="chip">100</button>
        <button id="fivehundred" class="chip">500</button>
        <button id="thousand" class="chip">1k</button>

        Bet Amount: $ <input type="number" id="betAmount" value="0" style="margin:5px; width: 100px;" disabled>
        <button id="reset" class="bet">Reset</button>
        <button id="submit" class="bet">Submit</button>

        Dealer Total: <input value="0" id="dealerTotal" style=" width: 50px;" disabled>

        Your Total: <input value="0" id="playerTotal" style="bottom:0; width: 50px;" disabled>

        <button class="bet" id="hit" style="background-color: lightgreen;">Hit</button>
        <button class="bet" id="stand" style="background-color: lightcoral;">Stand</button>

Welcome to Blackjack!

        To start, click the corresponding chips to place your bets and click "Submit" to start the game!
        The goal is to reach 21, so you can decide to either hit (gain another card) or stand (wait for the dealer).
        Whoever is closer to 21 without going over wins!

```

Title: Does #id override the :hover change?

Body:
I've seen different similar answers but none with the level of nesting I'm dealing with. I have two sets of buttons, circular ones and rectangular ones that I want the background to change to white on hover. The only thing I have been able to successfully change is the text color for the rectangular ones.

I previously had the button styles inline and thought that was the issue. Guess not :/

Does the ID override the :hover change? And if so do I need to reformat all of my buttons? Thank you!

(previous code solutions involve jquery and I have no knowledge of it whatsoever)

/*
    CS 81 Final - Noah Derby
*/

//Global Variables
"use strict";
let gameActive = false;
let dealerValue = 0;
let playerValue = 0;
let buttons = document.getElementsByTagName('button');
let totalAmount = document.getElementById('betAmount');
let bank = document.getElementById('bank');

//Card Functions and
function Card(value, name, suit) {
    this.value = value;
    this.name = name
    this.suit = suit
}

function newDeck() {
    let suits = ['Hearts','Diamonds','Spades','Clubs'];
    let names = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
    let deck = []
    for(let i of suits) {
        for(let n=0; n < names.length; n++) {
            deck.push(new Card(n+1, names[n], i));
        }
    }

    for (let i = deck.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        const temp = deck[i];
        deck[i] = deck[j];
        deck[j] = temp;
    }
    return deck;
}

function addTo(player, card){
    let ascii_char;
    let div = document.createElement('card');
    div.className = 'card';

    if(card.suit === 'Diamonds'){
        ascii_char = "♦";
        div.style.color = 'red';
    } else if (card.suit === 'Hearts') {
        ascii_char = '♥'
        div.style.color = 'red';
    } else {
        ascii_char = "&" + card.suit.toLowerCase() + ";"
    }

    div.innerHTML = "" + card.name + "" + ascii_char + "";

    if(player.id === "dealerTotal"){
        document.querySelector(".dealerCards").appendChild(div);
    } else {
        document.querySelector(".playerCards").appendChild(div);
    }

    if (card.value > 10){
        player.value = parseInt(player.value, 10) + 10;
    } else if (card.value === 1) {
        let handValue = parseInt(player.value, 10);
        if(handValue <= 10) {
            player.value = handValue + 11
        } else {
            player.value = handValue + 1
        }
    } else {
        player.value = parseInt(player.value, 10) + card.value;
    }
}

function clearCards() {
    document.querySelector(".dealerCards").innerHTML = "";
    document.querySelector(".playerCards").innerHTML = "";
}

//Button Handlers
for (let i=0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', () => {
        let playerTotal = document.getElementById("playerTotal");
        let dealerTotal = document.getElementById("dealerTotal");
        let bankValue = parseInt(bank.value, 10);
        let amountValue = parseInt(totalAmount.value, 10);
        let cards = newDeck();

        switch (buttons[i].id) {
            case "one":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1;
                    break;
                }
                break;
            case "five":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 5;
                    break;
                }
                break;
            case "ten":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 10;
                    break;
                }
                break;
            case "twentyfive":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 25;
                    break;
                }
                break;
            case "hundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 100;
                    break;
                }
                break
            case "fivehundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 500;
                    break;
                }
                break;
            case "thousand":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1000;
                    break;
                }
                break;
            case "reset":
                if (!gameActive){
                    totalAmount.value = 0;
                    break;
                }
                break;
            case "submit":
                if(!gameActive){
                    if (bankValue === 0) {
                        alert("No funds available :(");
                        break;
                    } else if (amountValue === 0) {
                        alert("Please Enter a valid amount")
                        break;
                    } else if(amountValue > bankValue){
                        totalAmount.value = bank.value;
                        bank.value = 0;
                    } else{
                        bank.value = bankValue - amountValue;
                    }
                    clearCards();
                    playerTotal.value = dealerTotal.value = '0';
                    addTo(playerTotal, cards.pop());
                    addTo(playerTotal, cards.pop());
                    addTo(dealerTotal, cards.pop());

                    dealerTotal.style.color = "transparent";
                    gameActive = true;
                    break;
                }
                break;
            case "hit":
                if(gameActive) {
                    addTo(playerTotal, cards.pop())
                    if(parseInt(playerTotal.value, 10) > 21){
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        dealerTotal.style.color = "black";
                        totalAmount.value= '0';
                        gameActive = false;
                        break;
                    }
                }
                break;
            case 'stand':
                if (gameActive) {
                    playerValue = parseInt(playerTotal.value, 10);
                    while(parseInt(dealerTotal.value, 10) <= 17){
                        addTo(dealerTotal, cards.pop());
                    }
                    dealerValue = parseInt(dealerTotal.value, 10);
                    if (dealerValue > 21){
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = 0;
                        gameActive = false;
                        dealerTotal.style.color = "black";
                        break;
                    }

                    if (playerValue < dealerValue) {
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        totalAmount.value= '0';
                    } else if (playerValue > dealerValue) {
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = '0';
                    } else {
                        alert(`Its a tie! Funds refunded!`);
                        bank.value = bankValue + amountValue;
                        totalAmount.value= '0';
                    }
                    dealerTotal.style.color = "black";
                    gameActive = false;
                }
                break;
        }
    }, false)
}

/*   CS 81 Final - Noah Derby   */

body {
    background-image: url('https://cdn.hipwallpaper.com/i/46/65/hEiUkp.jpg');
    background-size: cover;
    font-family: Verdana, sans-serif, bold;
    font-weight: bold;
    margin: 5px;
}

header {
    text-align: center;
    font-size: 50px;
    margin: 50px 500px -50px;
}

label{
    font-size: 25px;
}

input{
    font-size: 25px;
    color: black;
    background-color: white;
}

div {
    margin: 5px;
}

.economyWrap{
    position: relative;
    float: left;
    width: 480px;
    height: 500px;
    top: 100px;
    left: 50px;
}

.playWrap{
    position: relative;
    border: 5px solid black;
    float: left;
    top: 100px;
    width: 260px;
    height: 300px;
    margin-left: 140px;
}

.textContainer{
    padding: 5px;
    background: rgba(0, 128, 0, 0.02);
    margin: 200px 0 0 125px;
    width: 400px;
    float: left;
}

.playButtonContainer{
    position: absolute;
    margin: 17px;
    bottom:-90px;
}

.earningsContainer{
    position: absolute;
    width: 450px;
    height: 35px;
    padding: 5px;
    top:0;
    left:85px;
}

.submitContainer {
    margin: auto;
    position: absolute;
    width: 340px;
    bottom: 220px;
    left: 120px;
}

.chipContainer{
    margin: auto;
    position: absolute;
    height: 210px;
    width: 250px;
    left: 140px;
    bottom: 0;
}

/*
    Buttons
*/

button.chip{
    display: inline-block;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 15px;
    font-weight: bold;
    border-radius: 50%;
    height: 52px;
    width: 52px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#one {
    background-color: rgba(34,31,32,0.95);
    color:white;
    border: 5px solid rgba(209,212,213,0.95);
}

#five {
    background-color: rgba(242,122,128,0.95);
    color: rgba(148,30,28,0.95);
    border: 5px solid rgba(235,53,45,0.95);
}

#ten {
    background-color: rgba(169,219,203,0.95);
    color: rgba(13,45,76,0.95);
    border: 5px solid rgba(3,90,136,0.95);
}

#twentyfive {
    background-color: rgba(235,232,64,0.95);
    color: rgba(51,123,18,0.95);
    border: 5px solid rgba(57,134,63,0.95);
}

#hundred {
    background-color: #fdf049;
    color: rgb(235,53,45);
    border: 5px solid rgb(235,53,45);
}

#fivehundred {
    background-color: #b6b0d5;
    color: rgb(71,45,126);
    border: 5px solid rgb(126,70,155);
}

#thousand {
    background-color: #fffef6;
    color: rgb(34,31,31);
    border: 5px solid #59585a;
}

button.bet {
    display: inline-block;
    border-radius: 10px;
    border: 4px solid saddlebrown;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 14px;
    font-weight: bold;
    height: 50px;
    width: 100px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#submit {
    background-color: #358535;
}

#reset {
    background-color: yellow;
}

#hit {
    background-color: lightcoral;
}

#stand {
    background-color: lightgreen;
}

.card{
    background-color: white;
    width:40px;
    height:60px;
    border:1px solid #151718;
    float:left;
    border-radius:2px;
}

.number, .suit{
    width:100%;
    display:block;
    text-align:center;
    padding-top:8px;
}

button:hover {
    background-color: white;
}

<!DOCTYPE html>

    <meta charset="UTF-8">
    <title>Blackjack!</title>
    <link rel="stylesheet" href="style.css">

Blackjack!

        Your Balance is: $ <input type="number" id="bank" value="1000" style="width: 100px;" disabled>

        <button id="one" class="chip">1</button>
        <button id="five" class="chip">5</button>
        <button id="ten" class="chip" >10</button>
        <button id="twentyfive" class="chip">25</button>
        <button id="hundred" class="chip">100</button>
        <button id="fivehundred" class="chip">500</button>
        <button id="thousand" class="chip">1k</button>

        Bet Amount: $ <input type="number" id="betAmount" value="0" style="margin:5px; width: 100px;" disabled>
        <button id="reset" class="bet">Reset</button>
        <button id="submit" class="bet">Submit</button>

        Dealer Total: <input value="0" id="dealerTotal" style=" width: 50px;" disabled>

        Your Total: <input value="0" id="playerTotal" style="bottom:0; width: 50px;" disabled>

        <button class="bet" id="hit" style="background-color: lightgreen;">Hit</button>
        <button class="bet" id="stand" style="background-color: lightcoral;">Stand</button>

Welcome to Blackjack!

        To start, click the corresponding chips to place your bets and click "Submit" to start the game!
        The goal is to reach 21, so you can decide to either hit (gain another card) or stand (wait for the dealer).
        Whoever is closer to 21 without going over wins!

Body:
Question - Does the ID override the :hover change?

Answer -
The style rule for a:hover will override the paragraph as long as it is written in the CSS after the rule for p or #id.
The problem is that the selector handling your :hover behavior has a lower Specificity than the rule for the default behavior (p#id selector).

Question -  If so do I need to reformat all of my buttons?

Answer - No, you don't need to reformat all the buttons as you can use !important on the button:hover in the CSS file.

/*
    CS 81 Final - Noah Derby
*/

//Global Variables
"use strict";
let gameActive = false;
let dealerValue = 0;
let playerValue = 0;
let buttons = document.getElementsByTagName('button');
let totalAmount = document.getElementById('betAmount');
let bank = document.getElementById('bank');

//Card Functions and
function Card(value, name, suit) {
    this.value = value;
    this.name = name
    this.suit = suit
}

function newDeck() {
    let suits = ['Hearts','Diamonds','Spades','Clubs'];
    let names = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
    let deck = []
    for(let i of suits) {
        for(let n=0; n < names.length; n++) {
            deck.push(new Card(n+1, names[n], i));
        }
    }

    for (let i = deck.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        const temp = deck[i];
        deck[i] = deck[j];
        deck[j] = temp;
    }
    return deck;
}

function addTo(player, card){
    let ascii_char;
    let div = document.createElement('card');
    div.className = 'card';

    if(card.suit === 'Diamonds'){
        ascii_char = "&diams;";
        div.style.color = 'red';
    } else if (card.suit === 'Hearts') {
        ascii_char = '&hearts;'
        div.style.color = 'red';
    } else {
        ascii_char = "&" + card.suit.toLowerCase() + ";"
    }

    div.innerHTML = "<span class='number'>" + card.name + "</span><span class='suit'>" + ascii_char + "</span>";

    if(player.id === "dealerTotal"){
        document.querySelector(".dealerCards").appendChild(div);
    } else {
        document.querySelector(".playerCards").appendChild(div);
    }

    if (card.value > 10){
        player.value = parseInt(player.value, 10) + 10;
    } else if (card.value === 1) {
        let handValue = parseInt(player.value, 10);
        if(handValue <= 10) {
            player.value = handValue + 11
        } else {
            player.value = handValue + 1
        }
    } else {
        player.value = parseInt(player.value, 10) + card.value;
    }
}

function clearCards() {
    document.querySelector(".dealerCards").innerHTML = "";
    document.querySelector(".playerCards").innerHTML = "";
}

//Button Handlers
for (let i=0; i < buttons.length; i++) {
    buttons[i].addEventListener('click', () => {
        let playerTotal = document.getElementById("playerTotal");
        let dealerTotal = document.getElementById("dealerTotal");
        let bankValue = parseInt(bank.value, 10);
        let amountValue = parseInt(totalAmount.value, 10);
        let cards = newDeck();

        switch (buttons[i].id) {
            case "one":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1;
                    break;
                }
                break;
            case "five":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 5;
                    break;
                }
                break;
            case "ten":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 10;
                    break;
                }
                break;
            case "twentyfive":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 25;
                    break;
                }
                break;
            case "hundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 100;
                    break;
                }
                break
            case "fivehundred":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 500;
                    break;
                }
                break;
            case "thousand":
                if(!gameActive){
                    totalAmount.value = parseInt(totalAmount.value, 10) + 1000;
                    break;
                }
                break;
            case "reset":
                if (!gameActive){
                    totalAmount.value = 0;
                    break;
                }
                break;
            case "submit":
                if(!gameActive){
                    if (bankValue === 0) {
                        alert("No funds available :(");
                        break;
                    } else if (amountValue === 0) {
                        alert("Please Enter a valid amount")
                        break;
                    } else if(amountValue > bankValue){
                        totalAmount.value = bank.value;
                        bank.value = 0;
                    } else{
                        bank.value = bankValue - amountValue;
                    }
                    clearCards();
                    playerTotal.value = dealerTotal.value = '0';
                    addTo(playerTotal, cards.pop());
                    addTo(playerTotal, cards.pop());
                    addTo(dealerTotal, cards.pop());

                    dealerTotal.style.color = "transparent";
                    gameActive = true;
                    break;
                }
                break;
            case "hit":
                if(gameActive) {
                    addTo(playerTotal, cards.pop())
                    if(parseInt(playerTotal.value, 10) > 21){
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        dealerTotal.style.color = "black";
                        totalAmount.value= '0';
                        gameActive = false;
                        break;
                    }
                }
                break;
            case 'stand':
                if (gameActive) {
                    playerValue = parseInt(playerTotal.value, 10);
                    while(parseInt(dealerTotal.value, 10) <= 17){
                        addTo(dealerTotal, cards.pop());
                    }
                    dealerValue = parseInt(dealerTotal.value, 10);
                    if (dealerValue > 21){
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = 0;
                        gameActive = false;
                        dealerTotal.style.color = "black";
                        break;
                    }

                    if (playerValue < dealerValue) {
                        alert(`You lost $${amountValue} :( \n Submit another bet to play again!`);
                        totalAmount.value= '0';
                    } else if (playerValue > dealerValue) {
                        alert(`You won $${amountValue*2}!!!`);
                        bank.value = bankValue + amountValue * 2;
                        totalAmount.value = '0';
                    } else {
                        alert(`Its a tie! Funds refunded!`);
                        bank.value = bankValue + amountValue;
                        totalAmount.value= '0';
                    }
                    dealerTotal.style.color = "black";
                    gameActive = false;
                }
                break;
        }
    }, false)
}

/*   CS 81 Final - Noah Derby   */

body {
    background-image: url('https://cdn.hipwallpaper.com/i/46/65/hEiUkp.jpg');
    background-size: cover;
    font-family: Verdana, sans-serif, bold;
    font-weight: bold;
    margin: 5px;
}

header {
    text-align: center;
    font-size: 50px;
    margin: 50px 500px -50px;
}

label{
    font-size: 25px;
}

input{
    font-size: 25px;
    color: black;
    background-color: white;
}

div {
    margin: 5px;
}

.economyWrap{
    position: relative;
    float: left;
    width: 480px;
    height: 500px;
    top: 100px;
    left: 50px;
}

.playWrap{
    position: relative;
    border: 5px solid black;
    float: left;
    top: 100px;
    width: 260px;
    height: 300px;
    margin-left: 140px;
}

.textContainer{
    padding: 5px;
    background: rgba(0, 128, 0, 0.02);
    margin: 200px 0 0 125px;
    width: 400px;
    float: left;
}

.playButtonContainer{
    position: absolute;
    margin: 17px;
    bottom:-90px;
}

.earningsContainer{
    position: absolute;
    width: 450px;
    height: 35px;
    padding: 5px;
    top:0;
    left:85px;
}

.submitContainer {
    margin: auto;
    position: absolute;
    width: 340px;
    bottom: 220px;
    left: 120px;
}

.chipContainer{
    margin: auto;
    position: absolute;
    height: 210px;
    width: 250px;
    left: 140px;
    bottom: 0;
}

/*
    Buttons
*/

button.chip{
    display: inline-block;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 15px;
    font-weight: bold;
    border-radius: 50%;
    height: 52px;
    width: 52px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#one {
    background-color: rgba(34,31,32,0.95);
    color:white;
    border: 5px solid rgba(209,212,213,0.95);
}

#five {
    background-color: rgba(242,122,128,0.95);
    color: rgba(148,30,28,0.95);
    border: 5px solid rgba(235,53,45,0.95);
}

#ten {
    background-color: rgba(169,219,203,0.95);
    color: rgba(13,45,76,0.95);
    border: 5px solid rgba(3,90,136,0.95);
}

#twentyfive {
    background-color: rgba(235,232,64,0.95);
    color: rgba(51,123,18,0.95);
    border: 5px solid rgba(57,134,63,0.95);
}

#hundred {
    background-color: #fdf049;
    color: rgb(235,53,45);
    border: 5px solid rgb(235,53,45);
}

#fivehundred {
    background-color: #b6b0d5;
    color: rgb(71,45,126);
    border: 5px solid rgb(126,70,155);
}

#thousand {
    background-color: #fffef6;
    color: rgb(34,31,31);
    border: 5px solid #59585a;
}

button.bet {
    display: inline-block;
    border-radius: 10px;
    border: 4px solid saddlebrown;
    text-align: center;
    font-family: "Verdana", sans-serif;
    font-size: 14px;
    font-weight: bold;
    height: 50px;
    width: 100px;
    margin: 5px;
    cursor: pointer;
    transition-duration: .5s;
}

#submit {
    background-color: #358535;
}

#reset {
    background-color: yellow;
}

#hit {
    background-color: lightcoral;
}

#stand {
    background-color: lightgreen;
}

.card{
    background-color: white;
    width:40px;
    height:60px;
    border:1px solid #151718;
    float:left;
    border-radius:2px;
}

.number, .suit{
    width:100%;
    display:block;
    text-align:center;
    padding-top:8px;
}

button:hover {
    background-color: white !important;
}

<!DOCTYPE html>
<html lang="en">

<!-- CS 81 Final Project - Noah Derby-->
<!-- A simple blackjack game. I hope you enjoy!!!!!!-->

<head>
    <meta charset="UTF-8">
    <title>Blackjack!</title>
    <link rel="stylesheet" href="style.css">
</head>

<body>
<header>Blackjack!</header>
<div class="economyWrap">
    <div class="earningsContainer">
        <label for="bank" style="font-size: 25px;">Your Balance is: $ </label><input type="number" id="bank" value="1000" style="width: 100px;" disabled>
    </div>
    <div class="chipContainer">
        <button id="one" class="chip">1</button>
        <button id="five" class="chip">5</button>
        <button id="ten" class="chip" >10</button>
        <button id="twentyfive" class="chip">25</button>
        <button id="hundred" class="chip">100</button>
        <button id="fivehundred" class="chip">500</button>
        <button id="thousand" class="chip">1k</button>
    </div>
    <div class="submitContainer">
        <label for="betAmount" style="font-size: 25px;">Bet Amount: $ </label><input type="number" id="betAmount" value="0" style="margin:5px; width: 100px;" disabled>
        <button id="reset" class="bet">Reset</button>
        <button id="submit" class="bet">Submit</button>
    </div>
</div>

<div class="playWrap">
    <div class="dealerContainer">
        <label for="dealerTotal">Dealer Total: </label><input value="0" id="dealerTotal" style=" width: 50px;" disabled>
        <div class="dealerCards"></div>
    </div>
    <div class="playerContainer" style="position: absolute; bottom:0;">
        <label for="playerTotal">Your Total: </label><input value="0" id="playerTotal" style="bottom:0; width: 50px;" disabled>
        <div class="playerCards"></div>
    </div>
    <div class="playButtonContainer">
        <button class="bet" id="hit" style="background-color: lightgreen;">Hit</button>
        <button class="bet" id="stand" style="background-color: lightcoral;">Stand</button>
    </div>
</div>

<div class="textContainer">
    <h2>Welcome to Blackjack!</h2>
    <h4>
        To start, click the corresponding chips to place your bets and click "Submit" to start the game!
        The goal is to reach 21, so you can decide to either hit (gain another card) or stand (wait for the dealer).
        Whoever is closer to 21 without going over wins!
    </h4>
</div>

</body>
<script src="main.js"></script>

</html>


问:
Toggling A Click Handler Function On an Input Event Listener — Javascript
I'm setting up a form that submits to a MySQL database via PHP and there are server-side validations that take place for security reasons. I would like the frontend validation messages to be handled with JavasScript because there are many similar forms on the site, and would like these linked to the input event listener.

In the following code the submit button has a preventDefault() method on it until the title is more than 10 characters long. I've read that the best way to add and remove preventDefault is via a click handler function, which I'm using.

By default the button has a .prevent-default class on it and this is removed when the input passes the validation.

The Issue I'm Experiencing

The preventDefault and the error message work if the form is submitted when less than 10 characters are typed, and of course if more than 10 characters are typed the form will just submit as expected.

However, when more than 10 characters are initially typed, and the user then deletes some characters to bring the count back below 10, the form still submits on the front end? I would like it to fail again, with the same error message showing after the submit button is clicked.

I think the solution is to toggle the checkValidations() function. I can't seem to be able to do this though.

NOTE: Some of the elements use the forEach loop because on the full site there will be multiple instances of the form.

CodePen Link: https://codepen.io/thechewy/pen/GROEmoN

var dmForm = document.querySelector("form"),

// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"),
dmTitle = document.querySelector("#dm-title"),

// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")

// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
    evt.preventDefault()
    if(dmTitle.value.length < 10) {
        dmTitleError.classList.add('warning')
        dmTitleError.textContent = "Title must be more than 10 characters"
    }
}

// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
  preventSubmit.forEach(item => {
    item.addEventListener('click', clickHandler, false)
})

  // removes warning when the user types more than 10 characters
  if (dmForm) {
    dmTitle.addEventListener('input', () => {
      if( dmTitle.value.length > 10) {
        dmTitleError.classList.remove('warning')
        dmTitleError.textContent = ""

        // call the function that removes the preventDefault method
        checkValidations()
      }
    })
  }

function checkValidations(){
  if (dmTitle.value.length > 10) {
    preventSubmit.forEach(item => {
      item.removeEventListener('click', clickHandler, false)
      item.classList.remove('prevent-submit')
    })
  }
}

} // end of 'if (preventSubmit)' statement```
<pre class="snippet-code-css lang-css prettyprint-override"><code>body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

input,
button {
  padding: 0.5rem;
}

.js-error-message.warning {
    background: #cc1f1f;
    transition: background .5s;
    padding: 0.2rem 0.5rem;
    margin-top: 0.5rem;
    display: inline-block;
    position: absolute;
    bottom: -5rem;
}</code>```

<form method="post">

    <input id="dm-title" name="dm-title">

  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>```

答:
This is easier to implement if you use the inbuilt DOM Constraint Validation API :

let form = document.querySelector("form");
let error = document.querySelector(".js-dm-title-error")
let title = document.getElementById('dm-title');

title.setAttribute("minLength", '10');

title.addEventListener('input', function(e) {
  if (!title.validity.valid) {
    // if you want to nag on every character entered
    //showError("Title must be more than 10 characters");
  } else {
    showError('');
  }
});

form.addEventListener('submit', function(event) {
  // check each field
  if (!title.validity.valid) {
    showError("Title must be more than 10 characters");
    event.preventDefault();
    return false;
  }

  // mimicking form submit
  output.innerHTML += `Sending ${title.value}...<br>`;
  event.preventDefault();
  return false;
});

function showError(msg) {
  if (msg) {
    error.classList.add('warning')
    error.textContent = msg;
  } else {
    error.classList.remove('warning');
  }
}```
<pre class="snippet-code-css lang-css prettyprint-override"><code>body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
}

input {
  display: block;
  margin-right: 0.5rem;
  border-radius: 0.3rem;
}

input:invalid {
  background-color: rgb(255, 220, 220);
}

input:invalid:required {
  border: 1px dashed red;
}

input:valid {
  background-color: rgb(211, 255, 211);
}

.js-error-message {
  display: none;
  position: absolute;
  top: 100%;
}

.js-error-message.warning {
  display: inline-block;
  padding: .2rem;
  width: 169px;
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
  box-sizing: border-box;
}</code>```

<form method="post" novalidate>

    <input id="dm-title" name="dm-title" required>

  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>

```

Body:
I'm setting up a form that submits to a MySQL database via PHP and there are server-side validations that take place for security reasons. I would like the frontend validation messages to be handled with JavasScript because there are many similar forms on the site, and would like these linked to the input event listener.

In the following code the submit button has a preventDefault() method on it until the title is more than 10 characters long. I've read that the best way to add and remove preventDefault is via a click handler function, which I'm using.

By default the button has a .prevent-default class on it and this is removed when the input passes the validation.

The Issue I'm Experiencing

The preventDefault and the error message work if the form is submitted when less than 10 characters are typed, and of course if more than 10 characters are typed the form will just submit as expected.

However, when more than 10 characters are initially typed, and the user then deletes some characters to bring the count back below 10, the form still submits on the front end? I would like it to fail again, with the same error message showing after the submit button is clicked.

I think the solution is to toggle the checkValidations() function. I can't seem to be able to do this though.

NOTE: Some of the elements use the forEach loop because on the full site there will be multiple instances of the form.

CodePen Link: https://codepen.io/thechewy/pen/GROEmoN

var dmForm = document.querySelector("form"),

// class name on the submit button
preventSubmit = document.querySelectorAll(".prevent-submit"),
dmTitle = document.querySelector("#dm-title"),

// empty element for error message
dmTitleError = document.querySelector(".js-dm-title-error")

// function that prevents default click action on button and adds warning message
var clickHandler = function(evt) {
    evt.preventDefault()
    if(dmTitle.value.length < 10) {
        dmTitleError.classList.add('warning')
        dmTitleError.textContent = "Title must be more than 10 characters"
    }
}

// checks for 'prevent-submit' class and if present invokes the clickHander function above
if (preventSubmit) {
  preventSubmit.forEach(item => {
    item.addEventListener('click', clickHandler, false)
})

  // removes warning when the user types more than 10 characters
  if (dmForm) {
    dmTitle.addEventListener('input', () => {
      if( dmTitle.value.length > 10) {
        dmTitleError.classList.remove('warning')
        dmTitleError.textContent = ""

        // call the function that removes the preventDefault method
        checkValidations()
      }
    })
  }

function checkValidations(){
  if (dmTitle.value.length > 10) {
    preventSubmit.forEach(item => {
      item.removeEventListener('click', clickHandler, false)
      item.classList.remove('prevent-submit')
    })
  }
}

} // end of 'if (preventSubmit)' statement

body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
}

input,
button {
  padding: 0.5rem;
}

.js-error-message.warning {
    background: #cc1f1f;
    transition: background .5s;
    padding: 0.2rem 0.5rem;
    margin-top: 0.5rem;
    display: inline-block;
    position: absolute;
    bottom: -5rem;
}

<form method="post">

    <input id="dm-title" name="dm-title">

  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form>

Body:
This is easier to implement if you use the inbuilt DOM Constraint Validation API :

let form = document.querySelector("form");
let error = document.querySelector(".js-dm-title-error")
let title = document.getElementById('dm-title');

title.setAttribute("minLength", '10');

title.addEventListener('input', function(e) {
  if (!title.validity.valid) {
    // if you want to nag on every character entered
    //showError("Title must be more than 10 characters");
  } else {
    showError('');
  }
});

form.addEventListener('submit', function(event) {
  // check each field
  if (!title.validity.valid) {
    showError("Title must be more than 10 characters");
    event.preventDefault();
    return false;
  }

  // mimicking form submit
  output.innerHTML += `Sending ${title.value}...<br>`;
  event.preventDefault();
  return false;
});

function showError(msg) {
  if (msg) {
    error.classList.add('warning')
    error.textContent = msg;
  } else {
    error.classList.remove('warning');
  }
}

body {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 0;
}

form {
  display: flex;
  align-items: center;
}

.input-wrapper {
  position: relative;
}

input {
  display: block;
  margin-right: 0.5rem;
  border-radius: 0.3rem;
}

input:invalid {
  background-color: rgb(255, 220, 220);
}

input:invalid:required {
  border: 1px dashed red;
}

input:valid {
  background-color: rgb(211, 255, 211);
}

.js-error-message {
  display: none;
  position: absolute;
  top: 100%;
}

.js-error-message.warning {
  display: inline-block;
  padding: .2rem;
  width: 169px;
  font-size: 80%;
  color: white;
  background-color: #900;
  border-radius: 0 0 5px 5px;
  box-sizing: border-box;
}

<form method="post" novalidate>
  <div class="input-wrapper">
    <input id="dm-title" name="dm-title" required>
    <div class="js-error-message js-dm-title-error"></div>
  </div>
  <button name="dm-submit" class="prevent-submit">SEND MESSAGE</button>
</form><br>
<div id=output></div>


问:
Are SQS and Kafka same?
Are Kafka and SQS same?
I see that both are messaging queue systems and are event-based.
Do they serve the same purpose, If not how are they different?</p>

答:
SQS and Kafka are both messaging systems.
The primary differences are :

Ordering at scale.
Kafka - Produced messages are always consumed in order irrespective of the number of items in the queue.
SQS - "A FIFO queue looks through the first 20k messages to determine available message groups. This means that if you have a backlog of messages in a single message group, you can't consume messages from other message groups that were sent to the queue at a later time until you successfully consume the messages from the backlog"

Limit on the Number of groups/topic/partitions
Kafka - Although the limit is quite high, but the number of topics/partitions is usually in the order of thousands (which can increase depending on the cluster size). SQS - "There is no quota to the number of message groups within a FIFO queue."

Deduplication - Kafka does not support deduplication of data in case same data is produced multiple times. SQS tries to dedup messages based on the dedup-id and the dedup-interval. "Assuming that the producer receives at least one acknowledgement before the deduplication interval expires, multiple retries neither affect the ordering of messages nor introduce duplicates."

Partition management. Kafka - Creations or additions of partitions are created and managed by the user. SQS controls the number of partitions and it can increase or decrease it depending on the load and usage pattern.

Dead letter queue - Kafka does not have the concept of a DL queue (it can be explicitly created and maintained by the user thought). SQS inherently supports a DL queue by itself.

Overall if we want so summarise the points above, we can say that SQS is meant for offloading background tasks to an async pipeline. Kafka is much more scalable and should be used as a stream processing pipeline.

Title: Are SQS and Kafka same?


问:
Mixing NHibernate session threading in WPF application
I'm in the process of creating a WPF application with a rich front end. The issue I was running with from the beginning is that the UI would lock up whenever the user would change their filters. I originally fixed the issue by querying the database using NHibernate in a BackgroundWorker. It worked reasonably well for a short amount of time but NHibernate often throws various exceptions such as complaining that a session is already open.

How can I mix NHibernate session and threading in a WPF application?

I'm thinking that because I inject an open ISession instance into my repository and use that repository in several different threads that maybe I'd be better off simply injecting ISessionFactory instead and open a new session in my repository functions.

Update

The scenario in which this BackgroundWorker is being used is the user are able to select one of many roles. Every time a role is checked or unchecked I use my background worker to query the database. If you check two roles really fast then NHibernate throws an exception saying the session is already in use because because it's still trying to fetch the data for the first check action.

Essentially, it would be nice to detect that if NHIbernate is already running a query then to cancel it and start executing the new one. This would make sense because if a user selects 2 roles (thus, requiring 2 queries) then the first query is no longer valid.

Any ideas?

答: You need to make sure you have one session per thread. You can't spread sessions across multiple threads. When you kick off your background thread, create a new session. When you no longer need the thread, kill it and close the session. </p>

ContentLicense: CC BY-SA 3.0


问:
Get SessionID and UserHostAddress in .Net Core
In normal asp.net, we can get the value of this by giving:

```<code>UserSessionID = System.Web.HttpContext.Current.Session.SessionID;
IPAddress = System.Web.HttpContext.Current.Request.UserHostAddress;
</code>```

How can we get the same in .Net Core. Can anyone help?

答:
Assuming your session is setup like this:

```<code>HttpContext.Session.SetString("mysession", "mySessionValue");
</code>```

Then you can get the Session id:

```<code>UserSessionID = HttpContext.Session.Id;
</code>```

And the user host address:

```<code>IPAddress = HttpContext.Connection.RemoteIpAddress;
</code>```

Body:
In normal asp.net, we can get the value of this by giving:

UserSessionID = System.Web.HttpContext.Current.Session.SessionID;
IPAddress = System.Web.HttpContext.Current.Request.UserHostAddress;

How can we get the same in .Net Core. Can anyone help?

Body:
Assuming your session is setup like this:

HttpContext.Session.SetString("mysession", "mySessionValue");

Then you can get the Session id:

UserSessionID = HttpContext.Session.Id;

And the user host address:

IPAddress = HttpContext.Connection.RemoteIpAddress;


问:
How to upgrade Python venv version
I installed Python3.10 and I have a venv in a project I have been working on. I don't understand how to upgrade this easily. My background is mostly in Node and JS which is must simpler and more straightforward to change versions.

I was just trying to create a new venv but that didn't work

```<code>mpaccione@T430:~/Projects/investing/react-flask-app/server$ python3.10 -m venv ~/Projects/investing/react-flask-app/server
Error: Command '['/home/mpaccione/Projects/investing/react-flask-app/server/bin/python3.10', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1.
</code>```

I also thought maybe I could change the pyvenv config could be changed but that didn't work either

```<code>home = /usr/bin
include-system-site-packages = false
version = 3.8
</code>```

to

```<code>home = /usr/bin/python3.10
include-system-site-packages = false
version = 3.10
</code>```

Is there just a simply straightforward way to change this? I'm sure it's a common use case!

答:
According to the official docs venv has an --upgrade command, so if your interpreter-hook of the most current version is python3.10, it should be:

```<code>python3.10 -m venv --upgrade ~/Projects/investing/react-flask-app/server
</code>```

However, it might be that this fails because your hook-alias changed and that the python installation is different from the one used to create the venv. From the docs regarding --upgrade:
Upgrade the environment directory to use this version of Python, assuming Python has been upgraded in-place.

I would recommend to simply store the dependencies in a requirements.txt file, delete the venv, and recreate it with the new python version to make a clean new venv:

Activate the old venv

Store the dependencies in a file with python -m pip freeze > requirements.txt

Delete the old venv folder, keep the requirements file

Create a new venv & activate it

Install requirements with: python -m pip install -r requirements.txt

Title: How to upgrade Python venv version

Body:
I installed Python3.10 and I have a venv in a project I have been working on. I don't understand how to upgrade this easily. My background is mostly in Node and JS which is must simpler and more straightforward to change versions.

I was just trying to create a new venv but that didn't work

mpaccione@T430:~/Projects/investing/react-flask-app/server$ python3.10 -m venv ~/Projects/investing/react-flask-app/server
Error: Command '['/home/mpaccione/Projects/investing/react-flask-app/server/bin/python3.10', '-Im', 'ensurepip', '--upgrade', '--default-pip']' returned non-zero exit status 1.

I also thought maybe I could change the pyvenv config could be changed but that didn't work either

home = /usr/bin
include-system-site-packages = false
version = 3.8

to

home = /usr/bin/python3.10
include-system-site-packages = false
version = 3.10

Is there just a simply straightforward way to change this? I'm sure it's a common use case!

Body:
According to the official docs venv has an --upgrade command, so if your interpreter-hook of the most current version is python3.10, it should be:

python3.10 -m venv --upgrade ~/Projects/investing/react-flask-app/server

However, it might be that this fails because your hook-alias changed and that the python installation is different from the one used to create the venv. From the docs regarding --upgrade:
Upgrade the environment directory to use this version of Python, assuming Python has been upgraded in-place.

I would recommend to simply store the dependencies in a requirements.txt file, delete the venv, and recreate it with the new python version to make a clean new venv:

Activate the old venv

Store the dependencies in a file with python -m pip freeze > requirements.txt

Delete the old venv folder, keep the requirements file

Create a new venv & activate it

Install requirements with: python -m pip install -r requirements.txt


问:
Add a column of buttons over an image in Flutter
I have a flutter app that I want to add "stories" to, but I am unable to do so cause I can't place 3 buttons over an image.

That's my desired look...

And this is what I can do so far...

And this is my code:-

```<code>

child: GestureDetector(
          child: Center(
            child: Stack(
              alignment: Alignment.bottomRight,
              children: [
                Image.network(
                  widget.url,
                ),
                Container(
                  child: Column(children: [
                    Container(
                      color: Colors.grey,
                      child:
                          Column(children: [Icon(Icons.share), Text('مشاركة')]),
                    ),
                    Container(
                      color: Colors.grey,
                      child:
                          Column(children: [Icon(Icons.share), Text('مشاركة')]),
                    ),
                    Container(
                      color: Colors.grey,
                      child:
                          Column(children: [Icon(Icons.share), Text('مشاركة')]),
                    )
                  ]),
                )
              ],
            ),
          ),
          onTap: () => controller.next(),
        ),

</code>```

How can I achieve this effect?

Am I doing something with the Stack widget?

答:
GestureDetector(
        child: Center(
          child: Stack(
            children: [
              Container(
                height: double.infinity,
                width: double.infinity,
                decoration: const BoxDecoration(
                  image: DecorationImage(
                    fit: BoxFit.cover,
                    image: NetworkImage(
                      "https://st2.depositphotos.com/3759967/5593/i/600/depositphotos_55936567-stock-photo-swirling-frosty-multi-colored-fractal.jpg",
                    ),
                  ),
                ),
              ),
              Positioned(
                bottom: MediaQuery.of(context).size.height * 0.1,
                child: Column(
                  children: [
                  Container(
                    margin: const EdgeInsets.only(bottom: 10.0),
                    color: Colors.grey,
                    child: Column(
                        children: const [Icon(Icons.share), Text('مشاركة')]),
                  ),
                  Container(
                    margin: const EdgeInsets.only(bottom: 10.0),
                    color: Colors.grey,
                    child: Column(
                        children: const [Icon(Icons.share), Text('مشاركة')]),
                  ),
                  Container(
                    margin: const EdgeInsets.only(bottom: 10.0),
                    color: Colors.grey,
                    child: Column(
                        children: const [Icon(Icons.share), Text('مشاركة')]),
                  )
                ]),
              ),
            ],
          ),
        ),
      ),
```

You can do like this, place image as background of a container, and your column in a positioned widget.
example

Body:
I have a flutter app that I want to add "stories" to, but I am unable to do so cause I can't place 3 buttons over an image.

That's my desired look...

And this is what I can do so far...

And this is my code:-

child: GestureDetector(
          child: Center(
            child: Stack(
              alignment: Alignment.bottomRight,
              children: [
                Image.network(
                  widget.url,
                ),
                Container(
                  child: Column(children: [
                    Container(
                      color: Colors.grey,
                      child:
                          Column(children: [Icon(Icons.share), Text('مشاركة')]),
                    ),
                    Container(
                      color: Colors.grey,
                      child:
                          Column(children: [Icon(Icons.share), Text('مشاركة')]),
                    ),
                    Container(
                      color: Colors.grey,
                      child:
                          Column(children: [Icon(Icons.share), Text('مشاركة')]),
                    )
                  ]),
                )
              ],
            ),
          ),
          onTap: () => controller.next(),
        ),

How can I achieve this effect?

Am I doing something with the Stack widget?

Body:
GestureDetector(
        child: Center(
          child: Stack(
            children: [
              Container(
                height: double.infinity,
                width: double.infinity,
                decoration: const BoxDecoration(
                  image: DecorationImage(
                    fit: BoxFit.cover,
                    image: NetworkImage(
                      "https://st2.depositphotos.com/3759967/5593/i/600/depositphotos_55936567-stock-photo-swirling-frosty-multi-colored-fractal.jpg",
                    ),
                  ),
                ),
              ),
              Positioned(
                bottom: MediaQuery.of(context).size.height * 0.1,
                child: Column(
                  children: [
                  Container(
                    margin: const EdgeInsets.only(bottom: 10.0),
                    color: Colors.grey,
                    child: Column(
                        children: const [Icon(Icons.share), Text('مشاركة')]),
                  ),
                  Container(
                    margin: const EdgeInsets.only(bottom: 10.0),
                    color: Colors.grey,
                    child: Column(
                        children: const [Icon(Icons.share), Text('مشاركة')]),
                  ),
                  Container(
                    margin: const EdgeInsets.only(bottom: 10.0),
                    color: Colors.grey,
                    child: Column(
                        children: const [Icon(Icons.share), Text('مشاركة')]),
                  )
                ]),
              ),
            ],
          ),
        ),
      ),

You can do like this, place image as background of a container, and your column in a positioned widget.
example


问:
Facebook ads "<CAMPAIGN-ID>/insights" endpoint returns error
In PHP SDK when I try to fetch the insights of a campaign using "/insights" endpoint, it returns error :

You are calling a deprecated version of the Ads API. Please update to the latest version: v11.0.

The version of my app and php-ads-sdk is v11.0.

When I tested the endpoint in Graph API explorer, it's working.

```<code>$fb = new Facebook([
    'app_id' => $app_id,
    'app_secret' => $app_secret,
]);
$response = $fb->get(
      '<CAMPAIGN_ID>/insights?fields=actions',
      $access_token,
);
</code>```

NB: A valid campaign id is used.

答:
I believe you can prepend the version in your call, could not be a guaranteed fix but worth trying:</p>
```<code>$response = $fb->get(
      'https://graph.facebook.com/v11.0/<CAMPAIGN_ID>/insights?fields=actions',
      $access_token,
);
</code>```

Body:
In PHP SDK when I try to fetch the insights of a campaign using "/insights" endpoint, it returns error :

You are calling a deprecated version of the Ads API. Please update to the latest version: v11.0.

The version of my app and php-ads-sdk is v11.0.

When I tested the endpoint in Graph API explorer, it's working.

$fb = new Facebook([
    'app_id' => $app_id,
    'app_secret' => $app_secret,
]);
$response = $fb->get(
      '<CAMPAIGN_ID>/insights?fields=actions',
      $access_token,
);

NB: A valid campaign id is used.

Body:
I believe you can prepend the version in your call, could not be a guaranteed fix but worth trying:

$response = $fb->get(
      'https://graph.facebook.com/v11.0/<CAMPAIGN_ID>/insights?fields=actions',
      $access_token,
);