问:
Prisma client not marking property as null
I am using Prisma version 3.8.1. Prisma client does not mark the User.oauthData property as nullable in TS. Can someone help? Prisma schema and generated SQL files below:

```<code>// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native", "rhel-openssl-1.0.x"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Account {
  id BigInt @id
  createdAt DateTime @db.Timestamptz(3) @default(now())
  updatedAt DateTime @db.Timestamptz(3) @updatedAt
  name String
  users User[]
}

model User {
  id BigInt @id
  createdAt DateTime @db.Timestamptz(3) @default(now())
  updatedAt DateTime @db.Timestamptz(3) @updatedAt
  accountId BigInt
  account Account @relation(fields: [accountId], references: [id])
  fullName String
  email String
  oauthData Json?
}

</code>```
```<code>-- CreateTable
CREATE TABLE "Account" (
    "id" BIGINT NOT NULL,
    "createdAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMPTZ(3) NOT NULL,
    "name" TEXT NOT NULL,

    CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "User" (
    "id" BIGINT NOT NULL,
    "createdAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMPTZ(3) NOT NULL,
    "accountId" BIGINT NOT NULL,
    "fullName" TEXT NOT NULL,
    "email" TEXT NOT NULL,
    "oauthData" JSONB,

    CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "User" ADD CONSTRAINT "User_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

</code>```

I am using Prisma version 3.8.1. Prisma client does not mark the User.oauthData property as nullable in TS. Can someone help? Prisma schema and generated SQL files below:

答:
When working with JSONB fields, there are two types of null allowed: JSON null and DB null.

This is explained in more detail in the Prisma docs for working with JSON fields.

To avoid this ambiguity between the two types of null allowed by the database, we allow one of the following two values:

Prisma.DbNull: The value in the database is a NULL.

Prisma.JsonNull: value in the database contains a JSON value that is null.

This is what those two null values look like in the database (same schema as the one you shared):

```<code>prisma-script> select id, "oauthData" from "User"
+---------+-------------+
| id      | oauthData   |
|---------+-------------|
| 124124  | null        |
| 1241241 | <null>      |
+---------+-------------+
</code>```

You can also see this in the generated type for the model User

Body:
I am using Prisma version 3.8.1. Prisma client does not mark the User.oauthData property as nullable in TS. Can someone help? Prisma schema and generated SQL files below:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native", "rhel-openssl-1.0.x"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model Account {
  id BigInt @id
  createdAt DateTime @db.Timestamptz(3) @default(now())
  updatedAt DateTime @db.Timestamptz(3) @updatedAt
  name String
  users User[]
}

model User {
  id BigInt @id
  createdAt DateTime @db.Timestamptz(3) @default(now())
  updatedAt DateTime @db.Timestamptz(3) @updatedAt
  accountId BigInt
  account Account @relation(fields: [accountId], references: [id])
  fullName String
  email String
  oauthData Json?
}

-- CreateTable
CREATE TABLE "Account" (
    "id" BIGINT NOT NULL,
    "createdAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMPTZ(3) NOT NULL,
    "name" TEXT NOT NULL,

    CONSTRAINT "Account_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "User" (
    "id" BIGINT NOT NULL,
    "createdAt" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    "updatedAt" TIMESTAMPTZ(3) NOT NULL,
    "accountId" BIGINT NOT NULL,
    "fullName" TEXT NOT NULL,
    "email" TEXT NOT NULL,
    "oauthData" JSONB,

    CONSTRAINT "User_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "User" ADD CONSTRAINT "User_accountId_fkey" FOREIGN KEY ("accountId") REFERENCES "Account"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

I am using Prisma version 3.8.1. Prisma client does not mark the User.oauthData property as nullable in TS. Can someone help? Prisma schema and generated SQL files below:

Body:
When working with JSONB fields, there are two types of null allowed: JSON null and DB null.

This is explained in more detail in the Prisma docs for working with JSON fields.

To avoid this ambiguity between the two types of null allowed by the database, we allow one of the following two values:

Prisma.DbNull: The value in the database is a NULL.

Prisma.JsonNull: value in the database contains a JSON value that is null.

This is what those two null values look like in the database (same schema as the one you shared):

prisma-script> select id, "oauthData" from "User"
+---------+-------------+
| id      | oauthData   |
|---------+-------------|
| 124124  | null        |
| 1241241 | <null>      |
+---------+-------------+

You can also see this in the generated type for the model User


来源: stackexchange

问:
WCF 413 Request Entity Too Large - Self Hosted WebHttpBinding
There are many discussions about this problem, however I have now tried every possible solution and we are still getting 413 Request Entity Too Large errors from the server.

Our WCF service is self hosted via an Azure Worker role, and does not use IIS. All of our configuration is specified in code:

```<code>var host = new ServiceHost(searchEngine);

// Create binding
var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;

var readerQuotas = new XmlDictionaryReaderQuotas
{
    MaxStringContentLength = 2147483647,
    MaxArrayLength = 2147483647,
    MaxBytesPerRead = 2147483647,
    MaxDepth = 2147483647,
    MaxNameTableCharCount = 2147483647
};

// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);

binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);

// Add the service endpoint
var ep = host.AddServiceEndpoint(
    typeof(ISearchEngine),
    binding,
    string.Format("https://{0}/SearchEngine", externalEndpoint));

ep.Behaviors.Add(new WebHttpBehavior());

// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in ep.Contract.Operations)
{
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}

return host;
</code>```

And this is our client configuration - also specified in code:

```<code>var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;

var readerQuotas = new XmlDictionaryReaderQuotas
{
    MaxStringContentLength = 2147483647,
    MaxArrayLength = 2147483647,
    MaxBytesPerRead = 2147483647,
    MaxDepth = 2147483647,
    MaxNameTableCharCount = 2147483647
};

// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);

binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

var channelFactory = new ChannelFactory<ISearchEngine>(binding, endpointAddress);

channelFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());

// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in channelFactory.Endpoint.Contract.Operations)
{
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}

return channelFactory.CreateChannel();
</code>```

My only hunch could be a problem with the SSL connection? There are some articles mentioning a problem specific to IIS, however I'm not sure if this is relevant to self hosted services.

Any advice very much appreciated.

UPDATE:

To confirm my hunch that SSL was the problem, I temporarily disabled SSL and lo and behold the problem disappeared.

So now I need to figure out why SSL would be causing the problem. There is a fair bit of documentation about a similar problem, but it relates to IIS hosted services only (ours is self hosted from a windows service):

IIS7 - (413) Request Entity Too Large | uploadReadAheadSize

Would anyone out there know an equivalent setting that would apply to self hosted WCF services only?

答:
```<code><webHttpBinding>
   <binding name="TransportSecurity" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647">
        <security mode="Transport" />
      <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="16384" />
   </binding>
</code>```

ContentLicense: CC BY-SA 3.0

Body:
There are many discussions about this problem, however I have now tried every possible solution and we are still getting 413 Request Entity Too Large errors from the server.

Our WCF service is self hosted via an Azure Worker role, and does not use IIS. All of our configuration is specified in code:

var host = new ServiceHost(searchEngine);

// Create binding
var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;

var readerQuotas = new XmlDictionaryReaderQuotas
{
    MaxStringContentLength = 2147483647,
    MaxArrayLength = 2147483647,
    MaxBytesPerRead = 2147483647,
    MaxDepth = 2147483647,
    MaxNameTableCharCount = 2147483647
};

// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);

binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);

// Add the service endpoint
var ep = host.AddServiceEndpoint(
    typeof(ISearchEngine),
    binding,
    string.Format("https://{0}/SearchEngine", externalEndpoint));

ep.Behaviors.Add(new WebHttpBehavior());

// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in ep.Contract.Operations)
{
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}

return host;

And this is our client configuration - also specified in code:

var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;

var readerQuotas = new XmlDictionaryReaderQuotas
{
    MaxStringContentLength = 2147483647,
    MaxArrayLength = 2147483647,
    MaxBytesPerRead = 2147483647,
    MaxDepth = 2147483647,
    MaxNameTableCharCount = 2147483647
};

// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);

binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

var channelFactory = new ChannelFactory<ISearchEngine>(binding, endpointAddress);

channelFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());

// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in channelFactory.Endpoint.Contract.Operations)
{
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}

return channelFactory.CreateChannel();

My only hunch could be a problem with the SSL connection? There are some articles mentioning a problem specific to IIS, however I'm not sure if this is relevant to self hosted services.

Any advice very much appreciated.

UPDATE:

To confirm my hunch that SSL was the problem, I temporarily disabled SSL and lo and behold the problem disappeared.

So now I need to figure out why SSL would be causing the problem. There is a fair bit of documentation about a similar problem, but it relates to IIS hosted services only (ours is self hosted from a windows service):

IIS7 - (413) Request Entity Too Large | uploadReadAheadSize

Would anyone out there know an equivalent setting that would apply to self hosted WCF services only?

ContentLicense: CC BY-SA 4.0


问:
how to apply audio filter using discord.py/ffmpeg
I'm building a discord bot using discord.py and ffmpeg, I saw some js bot that can apply audio filters like this , I really can't find anything similar using discord.py. It is possible to do it?</p>

答:
The example you listed plays music from youtube (as most discord bots seem to be doing) with the ytdl library. Ytdl is the one that can interact with the ffmpeg to convert video to audio only (as can be seen in this documentation: https://github.com/ytdl-org/youtube-dl#post-processing-options).

This video implements something similar with ffmpeg: https://youtu.be/ml-5tXRmmFk?t=948 (added the approximate timestamp). So what you will need to do is to pass the filter flags, similarly to the JS example you linked.

If you don't want to use Ytdl you will need to interface with ffmpeg directly.


问:
Appcenter iOS install error "this app cannot be installed because its integrity could not be verified"
I see that this question has been asked many times but I see no solution that works for me so I'm hoping that providing more info might shed some light.

We use appcenter.ms to test iOS apps. Until our iOS certificate expired this method worked fine. We generated a new enterprise certificate and ad hoc provisioning profile for new releases of the iOS app. Which led to the first curiosity.

I see how to upload a certificate on appcenter.ms but not a provisioning profile. I thought there was an option to do this in the past but perhaps I am mistaken. However, the app is signed with a provisioning profile before upload, so perhaps this is not needed now.

Once the app is uploaded, it can't be installed. It remains grey and when you tap it, you get the "this app cannot be installed because its integrity could not be verified" error. Again, that the .ipa is created with an ad hoc certificate and profile in Xamarin (VS for Mac).

Also, I can't install the provisioning profile on a device from appcenter.ms. You basically get stuck in a loop where you seem to successfully install the profile but have to keep doing it because it never actually installs.

I hope this is enough info for some insight and thanks in advance for any feedback.

答:
I removed the Entitlements file from the Addition Resources in iOS Bundle Signing and it worked.
I think the MSAL configuration was set to debug in entitlements.plist</p>


问:
req.checkBody is not a function with Express-Validator NODEJS
Hi I'm trying doing a login page, after clicking on submit I'm getting this error with express-validator version 5.3.1

```<code>req.checkBody is not a function
TypeError: req.checkBody is not a function
    at Strategy._verify (C:\Users\aless\Desktop\js_cart-master\config\passport.js:67:7)
    at Strategy.authenticate (C:\Users\aless\Desktop\js_cart-master\node_modules\passport-local\lib\strategy.js:90:12)
    at attempt (C:\Users\aless\Desktop\js_cart-master\node_modules\passport\lib\middleware\authenticate.js:369:16)
    at authenticate (C:\Users\aless\Desktop\js_cart-master\node_modules\passport\lib\middleware\authenticate.js:370:7)
    at Layer.handle [as handle_request] (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:275:10)
    at C:\Users\aless\Desktop\js_cart-master\routes\user.js:39:3
    at Layer.handle [as handle_request] (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:335:12)
</code>```

In my app.js I have required express-validator with const validator = require('express-validator');//@5.3.1
and used it with app.use(validator());

```<code>const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
const passport =require('passport');
const flash = require('connect-flash');
const bcrypt = require('bcrypt');
const validator = require('express-validator');//@5.3.1
const session = require('express-session');
const MongoStore = require('connect-mongo');
const env = require('dotenv').config()
const app = express();

mongoose.connect(process.env.URI,{ useNewUrlParser: true });
require('./config/passport');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(validator());
app.use(cookieParser());
app.use(session({
    secret: "key per i cookie",
    saveUninitialized: false,
    resave: false,
    store: MongoStore.create({
        mongoUrl: process.env.URI,
        autoRemove: 'disabled'
    }),
    cookie: { maxAge:30000,secure:false }
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));

//verify if authenticated
app.use((req, res, next)=>{
  res.locals.login =req.isAuthenticated();
  //access sessions through templates
  res.locals.session = req.session;
  next();
});

//routes
app.use('/',  require('./routes/index'));
app.use('/user', require('./routes/user'));

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;
</code>```

Using this express-validator version I got this error when submit, using last express-validator version I get same error in console.
Why I'm getting this error??

答:
The reason is the way you are requiring it.

```<code>const { body, validationResult } = require('express-validator');
</code>```

In your code you can make these changes and try:

```<code>const { validationResult } = require('express-validator');//@5.3.1
.
.
.
app.use(validationResult());
</code>```

Note: check this link for more information.

Body:
Hi I'm trying doing a login page, after clicking on submit I'm getting this error with express-validator version 5.3.1

req.checkBody is not a function
TypeError: req.checkBody is not a function
    at Strategy._verify (C:\Users\aless\Desktop\js_cart-master\config\passport.js:67:7)
    at Strategy.authenticate (C:\Users\aless\Desktop\js_cart-master\node_modules\passport-local\lib\strategy.js:90:12)
    at attempt (C:\Users\aless\Desktop\js_cart-master\node_modules\passport\lib\middleware\authenticate.js:369:16)
    at authenticate (C:\Users\aless\Desktop\js_cart-master\node_modules\passport\lib\middleware\authenticate.js:370:7)
    at Layer.handle [as handle_request] (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:275:10)
    at C:\Users\aless\Desktop\js_cart-master\routes\user.js:39:3
    at Layer.handle [as handle_request] (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\layer.js:95:5)
    at trim_prefix (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:317:13)
    at C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:284:7
    at Function.process_params (C:\Users\aless\Desktop\js_cart-master\node_modules\express\lib\router\index.js:335:12)

In my app.js I have required express-validator with const validator = require('express-validator');//@5.3.1
and used it with app.use(validator());

const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require('mongoose');
const passport =require('passport');
const flash = require('connect-flash');
const bcrypt = require('bcrypt');
const validator = require('express-validator');//@5.3.1
const session = require('express-session');
const MongoStore = require('connect-mongo');
const env = require('dotenv').config()
const app = express();

mongoose.connect(process.env.URI,{ useNewUrlParser: true });
require('./config/passport');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(validator());
app.use(cookieParser());
app.use(session({
    secret: "key per i cookie",
    saveUninitialized: false,
    resave: false,
    store: MongoStore.create({
        mongoUrl: process.env.URI,
        autoRemove: 'disabled'
    }),
    cookie: { maxAge:30000,secure:false }
}));
app.use(flash());
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static(path.join(__dirname, 'public')));

//verify if authenticated
app.use((req, res, next)=>{
  res.locals.login =req.isAuthenticated();
  //access sessions through templates
  res.locals.session = req.session;
  next();
});

//routes
app.use('/',  require('./routes/index'));
app.use('/user', require('./routes/user'));

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

Using this express-validator version I got this error when submit, using last express-validator version I get same error in console.
Why I'm getting this error??

Body:
The reason is the way you are requiring it.

const { body, validationResult } = require('express-validator');

In your code you can make these changes and try:

const { validationResult } = require('express-validator');//@5.3.1
.
.
.
app.use(validationResult());

Note: check this link for more information.


问:
Infinite recursive call minimax algorithm
I have recently implemented the code for a 4X4 tic tac toe game which is using minimax algorithm.
However, my minimax function is calling itself recursively infinite no. of times.

Initial Board (4X4) tic tac toe ->

```<code>board = np.array([['_','_','_', '_'],['_','_','_', '_'],['_','_','_', '_'],['_','_','_', '_']])
</code>```

Code for the computer's turn ->

```<code>import math
from utility import *

def minimax(board, spotsLeft, maximizing):
    bestIdx = (0,0)
    p1 = 'X'
    p2 = 'O'
    res, stat = checkGameOver(board, spotsLeft)
    if res==True:
        if stat == 'X': return 17-spotsLeft, bestIdx
        elif stat == 'O': return -17+spotsLeft, bestIdx
        else: return 0, bestIdx

    if maximizing:
        # return max score
        bestMove = -math.inf
        for i in range(4):
            for j in range(4):
                if board[i][j] == '_':
                    board[i][j] = p1
                    score, idx = minimax(board, spotsLeft-1, False)
                    print(score, idx)
                    board[i][j] = '_'
                    if bestMove<score:
                        bestMove = score
                        bestIdx = (i,j)
        return bestMove, bestIdx
    else:
        # return min score
        bestMove = math.inf
        for i in range(4):
            for j in range(4):
                if board[i][j] == '_':
                    board[i][j] = p2
                    score, idx = minimax(board, spotsLeft-1, True)
                    print(score, idx)
                    board[i][j] = '_'
                    if bestMove>score:
                        bestMove = score
                        bestIdx = (i,j)
        return bestMove, bestIdx

def ai(board):
    spotsLeft = 16
    p1 = 'X'    # Computer
    p2 = 'O'    # Player
    turn = p1
    while True:
        res, stat = checkGameOver(board, spotsLeft)
        if res==False:
            if turn == p1:
                # AI
                boardCopy = board[:]
                score, idx = minimax(boardCopy, spotsLeft, True)
                board[idx[0]][idx[1]] = turn
                turn = p2
                spotsLeft-=1
            else:
                # Human
                inp = int(input(f"Your turn: "))
                i, j = spotToIdx(inp)
                if board[i][j]=='_':
                    board[i][j] = turn
                    turn = p1
                    spotsLeft-=1
        else: return stat
        printBoard(board)
</code>```

In the above code
spotsLeft is the empty places on board,
checkGameOver returns "X" (if Player X wins), returns "O" (if Player O wins) & returns "T" (if game is tied)

checkGameOver function ->

```<code>def checkWin(board):
    # Check Row
    for i in board:
        if len(set(i)) == 1 and i[0]!='_':
            return i[0]

    # Check Column
    for i in range(4):
        if (board[0][i] == board[1][i] == board[2][i] == board[3][i]) and board[0][i]!='_':
            return board[0][i]

    # Check Diagonals
    if (board[0][0]==board[1][1]==board[2][2]==board[3][3]) and board[0][0]!='_':
            return board[0][0]
    if (board[0][3]==board[1][2]==board[2][1]==board[3][0]) and board[0][3]!='_':
        return board[0][3]

    # No One Won Yet
    return -1

def checkGameOver(board, spotsLeft):
    # t -> Game Tied
    # x -> Player X won
    # o -> Player O won

    # if tied - all spots filled
    if spotsLeft == 0:
        return True, 'T'

    # if any player won the game
    result = checkWin(board)
    if result!=-1:
        return True, result

    return False, -1
</code>```

答:
As Jenny has very well explained, the search tree is too large. Even if you would make improvements to the data structure and move-mechanics to make them more efficient and reduce the memory footprint, it will still be a challenge to have this search finish within an acceptable time.

In general you would go for the following measures to cut down on the search tree:

Stop at a certain search depth (like 4) and perform a static evaluation of the board instead. This evaluation will be a heuristic. For instance it will give a high value to a 3-in-a-row with a free cell available to complete it to a win. It would also give a significant value to a pair on a line that is not blocked by the opponent, ...etc.

Use alpha-beta pruning to avoid searching in branches that could never lead to a better choice at an earlier stage in the search tree.

Use killer moves: a move that was found good after a certain opponent move, could also turn out to be good in reply to another opponent move. And trying that one first may work well in combination with alpha-beta pruning.

Memoize positions that were already evaluated (by swapping of moves), and mirror positions to equivalent positions to reduce the size of that dictionary.

But to be honest, 4x4 Tic Tac Toe is quite boring: it is very easy to play a draw, and it requires really inferior moves for a player to give the game away to the other. For instance, neither player can make a bad first move. Whatever they play on their first move, it will still be a draw with correct play.

So... I would propose to only use a heuristic evaluation function, and not search at all. Or, perform a shallow minimax, and use such a heuristic evaluation at that fixed depth. But even replacing the minimax algorithm with just an evaluation function works quite well.

What to change

To implement that idea, proceed as follows:

Replace the AI part with this:

```<code>     if turn == p1:
         # AI -- a heuristic based approach
         bestScore = -math.inf
         bestMove = None
         for i in range(4):
             for j in range(4):
                 if board[i][j] == '_':
                     board[i][j] = turn
                     score = evaluate(board, turn)
                     if score > bestScore:
                         bestScore = score
                         bestMove = (i, j)
                     board[i][j] = '_'
         i, j = bestMove
         board[i][j] = turn
         turn = p2
         spotsLeft-=1
</code>```

This calls evaluate which will give a numeric score that is higher the better it is for the given player (argument).

Add the definition for evaluate:

```<code># winning lines
lines = [
    [(i, j) for i in range(4)] for j in range(4)
] + [
    [(j, i) for i in range(4)] for j in range(4)
] + [
    [(i, i) for i in range(4)],
    [(3-i, i) for i in range(4)]
]

def evaluate(board, player):
    score = 0
    for line in lines:
        discs = [board[i][j] for i, j in line]
        # The more discs in one line the better
        value = [1000, 10, 6, 1, 0][sum(ch == "_" for ch in discs)]
        if "X" in discs:
            if not "O" in discs: # X could still win in this line
                score += value
        elif "O" in discs: # O could still win in this line
            score -= value
    # Change the sign depending on which player has just played
    return score if player == "X" else -score
</code>```

That's it! Optionally you can use the evaluate function to simplify the checkWin function:

```<code>def checkWin(board):
    score = evaluate(board, "X")
    if abs(score) > 500:  # Take into account there could be some reduction
        return "X" if score > 0 else "O"
    # No One Won Yet
    return -1
</code>```

With this implementation you don't need the minimax function anymore, but you might want to keep it, and limit the search depth. When that depth is reached, make the call to evaluate, ...etc. Still I found the above implementation to play fine. You can't win a game against it.

Body:
I have recently implemented the code for a 4X4 tic tac toe game which is using minimax algorithm.
However, my minimax function is calling itself recursively infinite no. of times.

Initial Board (4X4) tic tac toe ->

board = np.array([['_','_','_', '_'],['_','_','_', '_'],['_','_','_', '_'],['_','_','_', '_']])

Code for the computer's turn ->

import math
from utility import *

def minimax(board, spotsLeft, maximizing):
    bestIdx = (0,0)
    p1 = 'X'
    p2 = 'O'
    res, stat = checkGameOver(board, spotsLeft)
    if res==True:
        if stat == 'X': return 17-spotsLeft, bestIdx
        elif stat == 'O': return -17+spotsLeft, bestIdx
        else: return 0, bestIdx

    if maximizing:
        # return max score
        bestMove = -math.inf
        for i in range(4):
            for j in range(4):
                if board[i][j] == '_':
                    board[i][j] = p1
                    score, idx = minimax(board, spotsLeft-1, False)
                    print(score, idx)
                    board[i][j] = '_'
                    if bestMove<score:
                        bestMove = score
                        bestIdx = (i,j)
        return bestMove, bestIdx
    else:
        # return min score
        bestMove = math.inf
        for i in range(4):
            for j in range(4):
                if board[i][j] == '_':
                    board[i][j] = p2
                    score, idx = minimax(board, spotsLeft-1, True)
                    print(score, idx)
                    board[i][j] = '_'
                    if bestMove>score:
                        bestMove = score
                        bestIdx = (i,j)
        return bestMove, bestIdx

def ai(board):
    spotsLeft = 16
    p1 = 'X'    # Computer
    p2 = 'O'    # Player
    turn = p1
    while True:
        res, stat = checkGameOver(board, spotsLeft)
        if res==False:
            if turn == p1:
                # AI
                boardCopy = board[:]
                score, idx = minimax(boardCopy, spotsLeft, True)
                board[idx[0]][idx[1]] = turn
                turn = p2
                spotsLeft-=1
            else:
                # Human
                inp = int(input(f"Your turn: "))
                i, j = spotToIdx(inp)
                if board[i][j]=='_':
                    board[i][j] = turn
                    turn = p1
                    spotsLeft-=1
        else: return stat
        printBoard(board)

In the above code
spotsLeft is the empty places on board,
checkGameOver returns "X" (if Player X wins), returns "O" (if Player O wins) & returns "T" (if game is tied)

checkGameOver function ->

def checkWin(board):
    # Check Row
    for i in board:
        if len(set(i)) == 1 and i[0]!='_':
            return i[0]

    # Check Column
    for i in range(4):
        if (board[0][i] == board[1][i] == board[2][i] == board[3][i]) and board[0][i]!='_':
            return board[0][i]

    # Check Diagonals
    if (board[0][0]==board[1][1]==board[2][2]==board[3][3]) and board[0][0]!='_':
            return board[0][0]
    if (board[0][3]==board[1][2]==board[2][1]==board[3][0]) and board[0][3]!='_':
        return board[0][3]

    # No One Won Yet
    return -1

def checkGameOver(board, spotsLeft):
    # t -> Game Tied
    # x -> Player X won
    # o -> Player O won

    # if tied - all spots filled
    if spotsLeft == 0:
        return True, 'T'

    # if any player won the game
    result = checkWin(board)
    if result!=-1:
        return True, result

    return False, -1

Body:
As Jenny has very well explained, the search tree is too large. Even if you would make improvements to the data structure and move-mechanics to make them more efficient and reduce the memory footprint, it will still be a challenge to have this search finish within an acceptable time.

In general you would go for the following measures to cut down on the search tree:

Stop at a certain search depth (like 4) and perform a static evaluation of the board instead. This evaluation will be a heuristic. For instance it will give a high value to a 3-in-a-row with a free cell available to complete it to a win. It would also give a significant value to a pair on a line that is not blocked by the opponent, ...etc.

Use alpha-beta pruning to avoid searching in branches that could never lead to a better choice at an earlier stage in the search tree.

Use killer moves: a move that was found good after a certain opponent move, could also turn out to be good in reply to another opponent move. And trying that one first may work well in combination with alpha-beta pruning.

Memoize positions that were already evaluated (by swapping of moves), and mirror positions to equivalent positions to reduce the size of that dictionary.

But to be honest, 4x4 Tic Tac Toe is quite boring: it is very easy to play a draw, and it requires really inferior moves for a player to give the game away to the other. For instance, neither player can make a bad first move. Whatever they play on their first move, it will still be a draw with correct play.

So... I would propose to only use a heuristic evaluation function, and not search at all. Or, perform a shallow minimax, and use such a heuristic evaluation at that fixed depth. But even replacing the minimax algorithm with just an evaluation function works quite well.

What to change

To implement that idea, proceed as follows:

Replace the AI part with this:

     if turn == p1:
         # AI -- a heuristic based approach
         bestScore = -math.inf
         bestMove = None
         for i in range(4):
             for j in range(4):
                 if board[i][j] == '_':
                     board[i][j] = turn
                     score = evaluate(board, turn)
                     if score > bestScore:
                         bestScore = score
                         bestMove = (i, j)
                     board[i][j] = '_'
         i, j = bestMove
         board[i][j] = turn
         turn = p2
         spotsLeft-=1

This calls evaluate which will give a numeric score that is higher the better it is for the given player (argument).

Add the definition for evaluate:

# winning lines
lines = [
    [(i, j) for i in range(4)] for j in range(4)
] + [
    [(j, i) for i in range(4)] for j in range(4)
] + [
    [(i, i) for i in range(4)],
    [(3-i, i) for i in range(4)]
]

def evaluate(board, player):
    score = 0
    for line in lines:
        discs = [board[i][j] for i, j in line]
        # The more discs in one line the better
        value = [1000, 10, 6, 1, 0][sum(ch == "_" for ch in discs)]
        if "X" in discs:
            if not "O" in discs: # X could still win in this line
                score += value
        elif "O" in discs: # O could still win in this line
            score -= value
    # Change the sign depending on which player has just played
    return score if player == "X" else -score

That's it! Optionally you can use the evaluate function to simplify the checkWin function:

def checkWin(board):
    score = evaluate(board, "X")
    if abs(score) > 500:  # Take into account there could be some reduction
        return "X" if score > 0 else "O"
    # No One Won Yet
    return -1

With this implementation you don't need the minimax function anymore, but you might want to keep it, and limit the search depth. When that depth is reached, make the call to evaluate, ...etc. Still I found the above implementation to play fine. You can't win a game against it.


问:
Google AdMob Unity: Only test ads work (in Unity Editor) but no real ads
My admob account is linked to the app in play store, status "ready", AdMob app ID also added into ad settings in Unity, added in the real ad unit ID, test ad showing in Unity, waited a week...

Result: no real ads

My event is calling RequestAndLoadInterstitialAd() and ShowInterstitialAd(), which works in Unity with the test ad. I expected it to work once the test ad implemented successfully.

```<code>    using UnityEngine.Events;
    using UnityEngine;
    using GoogleMobileAds.Api;
    using GoogleMobileAds.Common;
    using UnityEngine.UI;
    using System;
    using System.Collections.Generic;

    public class GoogleAdMobController : MonoBehaviour
    {
        private AppOpenAd appOpenAd;
        private BannerView bannerView;
        private InterstitialAd interstitialAd;
        private RewardedAd rewardedAd;
        private RewardedInterstitialAd rewardedInterstitialAd;
        private float deltaTime;
        private bool isShowingAppOpenAd;
        public UnityEvent OnAdLoadedEvent;
        public UnityEvent OnAdFailedToLoadEvent;
        public UnityEvent OnAdOpeningEvent;
        public UnityEvent OnAdFailedToShowEvent;
        public UnityEvent OnUserEarnedRewardEvent;
        public UnityEvent OnAdClosedEvent;
        public bool showFpsMeter = true;
        public Text fpsMeter;
        public Text statusText;

        #region UNITY MONOBEHAVIOR METHODS

        public void Start()
        {
            MobileAds.SetiOSAppPauseOnBackground(true);

            List<String> deviceIds = new List<String>() { AdRequest.TestDeviceSimulator };

            // Add some test device IDs (replace with your own device IDs).
    #if UNITY_IPHONE
            deviceIds.Add("b77a5c561934e089)--a185c62eba2497c95197140e5282b27a");
    #elif UNITY_ANDROID
            deviceIds.Add("b77a5c561934e089)--a185c62eba2497c95197140e5282b27a");
    #endif

            // Configure TagForChildDirectedTreatment and test device IDs.
            RequestConfiguration requestConfiguration =
                new RequestConfiguration.Builder()
                .SetTagForChildDirectedTreatment(TagForChildDirectedTreatment.Unspecified)
                .SetTestDeviceIds(deviceIds).build();
            MobileAds.SetRequestConfiguration(requestConfiguration);

            // Initialize the Google Mobile Ads SDK.
            MobileAds.Initialize(HandleInitCompleteAction);
        }

        private void HandleInitCompleteAction(InitializationStatus initstatus)
        {
            // Callbacks from GoogleMobileAds are not guaranteed to be called on
            // main thread.
            // In this example we use MobileAdsEventExecutor to schedule these calls on
            // the next Update() loop.
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                statusText.text = "Initialization complete";
            //  RequestBannerAd();
            });
        }

        private void Update()
        {
            if (showFpsMeter)
            {
                fpsMeter.gameObject.SetActive(true);
                deltaTime += (Time.deltaTime - deltaTime) * 0.1f;
                float fps = 1.0f / deltaTime;
                fpsMeter.text = string.Format("{0:0.} fps", fps);
            }
            else
            {
                fpsMeter.gameObject.SetActive(false);
            }
        }

        #endregion

        #region HELPER METHODS

        private AdRequest CreateAdRequest()
        {
            return new AdRequest.Builder()
                .AddKeyword("unity-admob-sample")
                .Build();
        }

        public void OnApplicationPause(bool paused)
        {
            // Display the app open ad when the app is foregrounded.
            if (!paused)
            {
                ShowAppOpenAd();
            }
        }

        #endregion

        #region BANNER ADS

        public void RequestBannerAd()
        {
            statusText.text = "Requesting Banner Ad.";

            // These ad units are configured to always serve test ads.
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-3940256099942544/6300978111";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/2934735716";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // Clean up banner before reusing
            if (bannerView != null)
            {
                bannerView.Destroy();
            }

            // Create a 320x50 banner at top of the screen
            bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Top);

            // Add Event Handlers
            bannerView.OnAdLoaded += (sender, args) => OnAdLoadedEvent.Invoke();
            bannerView.OnAdFailedToLoad += (sender, args) => OnAdFailedToLoadEvent.Invoke();
            bannerView.OnAdOpening += (sender, args) => OnAdOpeningEvent.Invoke();
            bannerView.OnAdClosed += (sender, args) => OnAdClosedEvent.Invoke();

            // Load a banner ad
            bannerView.LoadAd(CreateAdRequest());
        }

        public void DestroyBannerAd()
        {
            if (bannerView != null)
            {
                bannerView.Destroy();
            }
        }

        #endregion

        #region INTERSTITIAL ADS

        public void RequestAndLoadInterstitialAd()
        {
            // statusText.text = "Requesting Interstitial Ad.";

    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-2334240444886107/9358512518";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/4411468910";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // Clean up interstitial before using it
            if (interstitialAd != null)
            {
                interstitialAd.Destroy();
            }
            interstitialAd = new InterstitialAd(adUnitId);

            // Add Event Handlers
            interstitialAd.OnAdLoaded += (sender, args) => OnAdLoadedEvent.Invoke();
            interstitialAd.OnAdFailedToLoad += (sender, args) => OnAdFailedToLoadEvent.Invoke();
            interstitialAd.OnAdOpening += (sender, args) => OnAdOpeningEvent.Invoke();
            interstitialAd.OnAdClosed += (sender, args) => OnAdClosedEvent.Invoke();

            // Load an interstitial ad
            interstitialAd.LoadAd(CreateAdRequest());
        }

        public void ShowInterstitialAd()
        {
            if (interstitialAd.IsLoaded())
            {
                interstitialAd.Show();
            }
            else
            {
                statusText.text = "Interstitial ad is not ready yet";
            }
        }

        public void DestroyInterstitialAd()
        {
            if (interstitialAd != null)
            {
                interstitialAd.Destroy();
            }
        }

        #endregion

        #region REWARDED ADS

        public void RequestAndLoadRewardedAd()
        {
            statusText.text = "Requesting Rewarded Ad.";
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-3940256099942544/5224354917";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/1712485313";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // create new rewarded ad instance
            rewardedAd = new RewardedAd(adUnitId);

            // Add Event Handlers
            rewardedAd.OnAdLoaded += (sender, args) => OnAdLoadedEvent.Invoke();
            rewardedAd.OnAdFailedToLoad += (sender, args) => OnAdFailedToLoadEvent.Invoke();
            rewardedAd.OnAdOpening += (sender, args) => OnAdOpeningEvent.Invoke();
            rewardedAd.OnAdFailedToShow += (sender, args) => OnAdFailedToShowEvent.Invoke();
            rewardedAd.OnAdClosed += (sender, args) => OnAdClosedEvent.Invoke();
            rewardedAd.OnUserEarnedReward += (sender, args) => OnUserEarnedRewardEvent.Invoke();

            // Create empty ad request
            rewardedAd.LoadAd(CreateAdRequest());
        }

        public void ShowRewardedAd()
        {
            if (rewardedAd != null)
            {
                rewardedAd.Show();
            }
            else
            {
                statusText.text = "Rewarded ad is not ready yet.";
            }
        }

        public void RequestAndLoadRewardedInterstitialAd()
        {
            statusText.text = "Requesting Rewarded Interstitial Ad.";

            // These ad units are configured to always serve test ads.
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
                string adUnitId = "ca-app-pub-3940256099942544/5354046379";
    #elif UNITY_IPHONE
                string adUnitId = "ca-app-pub-3940256099942544/6978759866";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // Create an interstitial.
            RewardedInterstitialAd.LoadAd(adUnitId, CreateAdRequest(), (rewardedInterstitialAd, error) =>
            {
                if (error != null)
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "RewardedInterstitialAd load failed, error: " + error;
                    });
                    return;
                }
                this.rewardedInterstitialAd = rewardedInterstitialAd;
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    statusText.text = "RewardedInterstitialAd loaded";
                });
                // Register for ad events.
                this.rewardedInterstitialAd.OnAdDidPresentFullScreenContent += (sender, args) =>
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Rewarded Interstitial presented.";
                    });
                };
                this.rewardedInterstitialAd.OnAdDidDismissFullScreenContent += (sender, args) =>
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Rewarded Interstitial dismissed.";
                    });
                    this.rewardedInterstitialAd = null;
                };
                this.rewardedInterstitialAd.OnAdFailedToPresentFullScreenContent += (sender, args) =>
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Rewarded Interstitial failed to present.";
                    });
                    this.rewardedInterstitialAd = null;
                };
            });
        }

        public void ShowRewardedInterstitialAd()
        {
            if (rewardedInterstitialAd != null)
            {
                rewardedInterstitialAd.Show((reward) => {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "User Rewarded: " + reward.Amount;
                    });
                });
            }
            else
            {
                statusText.text = "Rewarded ad is not ready yet.";
            }
        }

        #endregion

        #region APPOPEN ADS

        public void RequestAndLoadAppOpenAd()
        {
            statusText.text = "Requesting App Open Ad.";
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-3940256099942544/3419835294";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/5662855259";
    #else
            string adUnitId = "unexpected_platform";
    #endif
            // create new app open ad instance
            AppOpenAd.LoadAd(adUnitId, ScreenOrientation.Portrait, CreateAdRequest(), (appOpenAd, error) =>
            {
                if (error != null)
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "AppOpenAd load failed, error: " + error;
                    });
                    return;
                }
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    statusText.text = "AppOpenAd loaded. Please background the app and return.";
                });
                this.appOpenAd = appOpenAd;
            });
        }

        public void ShowAppOpenAd()
        {
            if (isShowingAppOpenAd)
            {
                return;
            }
            if (appOpenAd == null)
            {
                return;
            }
            // Register for ad events.
            this.appOpenAd.OnAdDidDismissFullScreenContent += (sender, args) =>
            {
                isShowingAppOpenAd = false;
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    Debug.Log("AppOpenAd dismissed.");
                    if (this.appOpenAd != null)
                    {
                        this.appOpenAd.Destroy();
                        this.appOpenAd = null;
                    }
                });
            };
            this.appOpenAd.OnAdFailedToPresentFullScreenContent += (sender, args) =>
            {
                isShowingAppOpenAd = false;
                var msg = args.AdError.GetMessage();
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    statusText.text = "AppOpenAd present failed, error: " + msg;
                    if (this.appOpenAd != null)
                    {
                        this.appOpenAd.Destroy();
                        this.appOpenAd = null;
                    }
                });
            };
            this.appOpenAd.OnAdDidPresentFullScreenContent += (sender, args) =>
            {
                isShowingAppOpenAd = true;
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    Debug.Log("AppOpenAd presented.");
                });
            };
            this.appOpenAd.OnAdDidRecordImpression += (sender, args) =>
            {
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    Debug.Log("AppOpenAd recorded an impression.");
                });
            };
            this.appOpenAd.OnPaidEvent += (sender, args) =>
            {
                string currencyCode = args.AdValue.CurrencyCode;
                long adValue = args.AdValue.Value;
                string suffix = "AppOpenAd received a paid event.";
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    string msg = string.Format("{0} (currency: {1}, value: {2}", suffix, currencyCode, adValue);
                    statusText.text = msg;
                });
            };
            appOpenAd.Show();
        }

        #endregion

        #region AD INSPECTOR

        public void OpenAdInspector()
        {
            statusText.text = "Open Ad Inspector.";

            MobileAds.OpenAdInspector((error) =>
            {
                if (error != null)
                {
                    string errorMessage = error.GetMessage();
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Ad Inspector failed to open, error: " + errorMessage;
                    });
                }
                else
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Ad Inspector closed.";
                    });
                }
            });
        }

        #endregion
    }
</code>```

答:
If your test device (You can add this from Admob) shows your ADs as expected you should be fine. After some requests, your game will start to show real ads. Admob does not give real ads immediately, it needs some request to show real ads. But as I say you have to be sure your test devices show ads correctly.

And I also recommend check compatible admob SDK and Unity versions. Because they have bugs sometimes. You can check it in Admob GitHub page.
You can check here:

https://github.com/googleads/googleads-mobile-unity/releases

Body:
My admob account is linked to the app in play store, status "ready", AdMob app ID also added into ad settings in Unity, added in the real ad unit ID, test ad showing in Unity, waited a week...

Result: no real ads

My event is calling RequestAndLoadInterstitialAd() and ShowInterstitialAd(), which works in Unity with the test ad. I expected it to work once the test ad implemented successfully.

    using UnityEngine.Events;
    using UnityEngine;
    using GoogleMobileAds.Api;
    using GoogleMobileAds.Common;
    using UnityEngine.UI;
    using System;
    using System.Collections.Generic;

    public class GoogleAdMobController : MonoBehaviour
    {
        private AppOpenAd appOpenAd;
        private BannerView bannerView;
        private InterstitialAd interstitialAd;
        private RewardedAd rewardedAd;
        private RewardedInterstitialAd rewardedInterstitialAd;
        private float deltaTime;
        private bool isShowingAppOpenAd;
        public UnityEvent OnAdLoadedEvent;
        public UnityEvent OnAdFailedToLoadEvent;
        public UnityEvent OnAdOpeningEvent;
        public UnityEvent OnAdFailedToShowEvent;
        public UnityEvent OnUserEarnedRewardEvent;
        public UnityEvent OnAdClosedEvent;
        public bool showFpsMeter = true;
        public Text fpsMeter;
        public Text statusText;

        #region UNITY MONOBEHAVIOR METHODS

        public void Start()
        {
            MobileAds.SetiOSAppPauseOnBackground(true);

            List<String> deviceIds = new List<String>() { AdRequest.TestDeviceSimulator };

            // Add some test device IDs (replace with your own device IDs).
    #if UNITY_IPHONE
            deviceIds.Add("b77a5c561934e089)--a185c62eba2497c95197140e5282b27a");
    #elif UNITY_ANDROID
            deviceIds.Add("b77a5c561934e089)--a185c62eba2497c95197140e5282b27a");
    #endif

            // Configure TagForChildDirectedTreatment and test device IDs.
            RequestConfiguration requestConfiguration =
                new RequestConfiguration.Builder()
                .SetTagForChildDirectedTreatment(TagForChildDirectedTreatment.Unspecified)
                .SetTestDeviceIds(deviceIds).build();
            MobileAds.SetRequestConfiguration(requestConfiguration);

            // Initialize the Google Mobile Ads SDK.
            MobileAds.Initialize(HandleInitCompleteAction);
        }

        private void HandleInitCompleteAction(InitializationStatus initstatus)
        {
            // Callbacks from GoogleMobileAds are not guaranteed to be called on
            // main thread.
            // In this example we use MobileAdsEventExecutor to schedule these calls on
            // the next Update() loop.
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                statusText.text = "Initialization complete";
            //  RequestBannerAd();
            });
        }

        private void Update()
        {
            if (showFpsMeter)
            {
                fpsMeter.gameObject.SetActive(true);
                deltaTime += (Time.deltaTime - deltaTime) * 0.1f;
                float fps = 1.0f / deltaTime;
                fpsMeter.text = string.Format("{0:0.} fps", fps);
            }
            else
            {
                fpsMeter.gameObject.SetActive(false);
            }
        }

        #endregion

        #region HELPER METHODS

        private AdRequest CreateAdRequest()
        {
            return new AdRequest.Builder()
                .AddKeyword("unity-admob-sample")
                .Build();
        }

        public void OnApplicationPause(bool paused)
        {
            // Display the app open ad when the app is foregrounded.
            if (!paused)
            {
                ShowAppOpenAd();
            }
        }

        #endregion

        #region BANNER ADS

        public void RequestBannerAd()
        {
            statusText.text = "Requesting Banner Ad.";

            // These ad units are configured to always serve test ads.
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-3940256099942544/6300978111";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/2934735716";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // Clean up banner before reusing
            if (bannerView != null)
            {
                bannerView.Destroy();
            }

            // Create a 320x50 banner at top of the screen
            bannerView = new BannerView(adUnitId, AdSize.SmartBanner, AdPosition.Top);

            // Add Event Handlers
            bannerView.OnAdLoaded += (sender, args) => OnAdLoadedEvent.Invoke();
            bannerView.OnAdFailedToLoad += (sender, args) => OnAdFailedToLoadEvent.Invoke();
            bannerView.OnAdOpening += (sender, args) => OnAdOpeningEvent.Invoke();
            bannerView.OnAdClosed += (sender, args) => OnAdClosedEvent.Invoke();

            // Load a banner ad
            bannerView.LoadAd(CreateAdRequest());
        }

        public void DestroyBannerAd()
        {
            if (bannerView != null)
            {
                bannerView.Destroy();
            }
        }

        #endregion

        #region INTERSTITIAL ADS

        public void RequestAndLoadInterstitialAd()
        {
            // statusText.text = "Requesting Interstitial Ad.";

    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-2334240444886107/9358512518";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/4411468910";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // Clean up interstitial before using it
            if (interstitialAd != null)
            {
                interstitialAd.Destroy();
            }
            interstitialAd = new InterstitialAd(adUnitId);

            // Add Event Handlers
            interstitialAd.OnAdLoaded += (sender, args) => OnAdLoadedEvent.Invoke();
            interstitialAd.OnAdFailedToLoad += (sender, args) => OnAdFailedToLoadEvent.Invoke();
            interstitialAd.OnAdOpening += (sender, args) => OnAdOpeningEvent.Invoke();
            interstitialAd.OnAdClosed += (sender, args) => OnAdClosedEvent.Invoke();

            // Load an interstitial ad
            interstitialAd.LoadAd(CreateAdRequest());
        }

        public void ShowInterstitialAd()
        {
            if (interstitialAd.IsLoaded())
            {
                interstitialAd.Show();
            }
            else
            {
                statusText.text = "Interstitial ad is not ready yet";
            }
        }

        public void DestroyInterstitialAd()
        {
            if (interstitialAd != null)
            {
                interstitialAd.Destroy();
            }
        }

        #endregion

        #region REWARDED ADS

        public void RequestAndLoadRewardedAd()
        {
            statusText.text = "Requesting Rewarded Ad.";
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-3940256099942544/5224354917";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/1712485313";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // create new rewarded ad instance
            rewardedAd = new RewardedAd(adUnitId);

            // Add Event Handlers
            rewardedAd.OnAdLoaded += (sender, args) => OnAdLoadedEvent.Invoke();
            rewardedAd.OnAdFailedToLoad += (sender, args) => OnAdFailedToLoadEvent.Invoke();
            rewardedAd.OnAdOpening += (sender, args) => OnAdOpeningEvent.Invoke();
            rewardedAd.OnAdFailedToShow += (sender, args) => OnAdFailedToShowEvent.Invoke();
            rewardedAd.OnAdClosed += (sender, args) => OnAdClosedEvent.Invoke();
            rewardedAd.OnUserEarnedReward += (sender, args) => OnUserEarnedRewardEvent.Invoke();

            // Create empty ad request
            rewardedAd.LoadAd(CreateAdRequest());
        }

        public void ShowRewardedAd()
        {
            if (rewardedAd != null)
            {
                rewardedAd.Show();
            }
            else
            {
                statusText.text = "Rewarded ad is not ready yet.";
            }
        }

        public void RequestAndLoadRewardedInterstitialAd()
        {
            statusText.text = "Requesting Rewarded Interstitial Ad.";

            // These ad units are configured to always serve test ads.
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
                string adUnitId = "ca-app-pub-3940256099942544/5354046379";
    #elif UNITY_IPHONE
                string adUnitId = "ca-app-pub-3940256099942544/6978759866";
    #else
            string adUnitId = "unexpected_platform";
    #endif

            // Create an interstitial.
            RewardedInterstitialAd.LoadAd(adUnitId, CreateAdRequest(), (rewardedInterstitialAd, error) =>
            {
                if (error != null)
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "RewardedInterstitialAd load failed, error: " + error;
                    });
                    return;
                }
                this.rewardedInterstitialAd = rewardedInterstitialAd;
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    statusText.text = "RewardedInterstitialAd loaded";
                });
                // Register for ad events.
                this.rewardedInterstitialAd.OnAdDidPresentFullScreenContent += (sender, args) =>
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Rewarded Interstitial presented.";
                    });
                };
                this.rewardedInterstitialAd.OnAdDidDismissFullScreenContent += (sender, args) =>
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Rewarded Interstitial dismissed.";
                    });
                    this.rewardedInterstitialAd = null;
                };
                this.rewardedInterstitialAd.OnAdFailedToPresentFullScreenContent += (sender, args) =>
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Rewarded Interstitial failed to present.";
                    });
                    this.rewardedInterstitialAd = null;
                };
            });
        }

        public void ShowRewardedInterstitialAd()
        {
            if (rewardedInterstitialAd != null)
            {
                rewardedInterstitialAd.Show((reward) => {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "User Rewarded: " + reward.Amount;
                    });
                });
            }
            else
            {
                statusText.text = "Rewarded ad is not ready yet.";
            }
        }

        #endregion

        #region APPOPEN ADS

        public void RequestAndLoadAppOpenAd()
        {
            statusText.text = "Requesting App Open Ad.";
    #if UNITY_EDITOR
            string adUnitId = "unused";
    #elif UNITY_ANDROID
            string adUnitId = "ca-app-pub-3940256099942544/3419835294";
    #elif UNITY_IPHONE
            string adUnitId = "ca-app-pub-3940256099942544/5662855259";
    #else
            string adUnitId = "unexpected_platform";
    #endif
            // create new app open ad instance
            AppOpenAd.LoadAd(adUnitId, ScreenOrientation.Portrait, CreateAdRequest(), (appOpenAd, error) =>
            {
                if (error != null)
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "AppOpenAd load failed, error: " + error;
                    });
                    return;
                }
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    statusText.text = "AppOpenAd loaded. Please background the app and return.";
                });
                this.appOpenAd = appOpenAd;
            });
        }

        public void ShowAppOpenAd()
        {
            if (isShowingAppOpenAd)
            {
                return;
            }
            if (appOpenAd == null)
            {
                return;
            }
            // Register for ad events.
            this.appOpenAd.OnAdDidDismissFullScreenContent += (sender, args) =>
            {
                isShowingAppOpenAd = false;
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    Debug.Log("AppOpenAd dismissed.");
                    if (this.appOpenAd != null)
                    {
                        this.appOpenAd.Destroy();
                        this.appOpenAd = null;
                    }
                });
            };
            this.appOpenAd.OnAdFailedToPresentFullScreenContent += (sender, args) =>
            {
                isShowingAppOpenAd = false;
                var msg = args.AdError.GetMessage();
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    statusText.text = "AppOpenAd present failed, error: " + msg;
                    if (this.appOpenAd != null)
                    {
                        this.appOpenAd.Destroy();
                        this.appOpenAd = null;
                    }
                });
            };
            this.appOpenAd.OnAdDidPresentFullScreenContent += (sender, args) =>
            {
                isShowingAppOpenAd = true;
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    Debug.Log("AppOpenAd presented.");
                });
            };
            this.appOpenAd.OnAdDidRecordImpression += (sender, args) =>
            {
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    Debug.Log("AppOpenAd recorded an impression.");
                });
            };
            this.appOpenAd.OnPaidEvent += (sender, args) =>
            {
                string currencyCode = args.AdValue.CurrencyCode;
                long adValue = args.AdValue.Value;
                string suffix = "AppOpenAd received a paid event.";
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    string msg = string.Format("{0} (currency: {1}, value: {2}", suffix, currencyCode, adValue);
                    statusText.text = msg;
                });
            };
            appOpenAd.Show();
        }

        #endregion

        #region AD INSPECTOR

        public void OpenAdInspector()
        {
            statusText.text = "Open Ad Inspector.";

            MobileAds.OpenAdInspector((error) =>
            {
                if (error != null)
                {
                    string errorMessage = error.GetMessage();
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Ad Inspector failed to open, error: " + errorMessage;
                    });
                }
                else
                {
                    MobileAdsEventExecutor.ExecuteInUpdate(() => {
                        statusText.text = "Ad Inspector closed.";
                    });
                }
            });
        }

        #endregion
    }


问:
This function has a return type of 'Widget', but doesn't end with a return statement. Build widget returning error
I have the following warning => This function has a return type of 'Widget', but doesn't end with a return statement. (Documentation)  Try adding a return statement, or changing the return type to 'void'.

When I add the return statement in the void function, I encounter the following error:

A value of type 'void' can't be returned from the method 'build' because it has a return type of 'Widget'. (Documentation)

```<code>   [...]else if (state is CancelOrderErrorState) {
          showCoreMessageSnackBar(
            CoreMessageWidget.error(title: strings.cancelOrderFailureText.localize(context)),
            autoDismiss: true,
          );
    [...]
</code>```

Can someone help me fix this return statement?

答:
To expand your code a little bit:

```<code>@override
Widget build(BuildContext context) {
...
    else if (state is CancelOrderErrorState) {
          showCoreMessageSnackBar(
            CoreMessageWidget.error(title: strings.cancelOrderFailureText.localize(context)),
            autoDismiss: true,
          );
        return Container(); //<--add this
    }
...
}
</code>```

You HAVE to return what the method is defined to return which is a Widget. Since the build method is overridden you can't change the return type. Sometimes returning something simple is all you can do.

Body:
I have the following warning => This function has a return type of 'Widget', but doesn't end with a return statement. (Documentation)  Try adding a return statement, or changing the return type to 'void'.

When I add the return statement in the void function, I encounter the following error:

A value of type 'void' can't be returned from the method 'build' because it has a return type of 'Widget'. (Documentation)

   [...]else if (state is CancelOrderErrorState) {
          showCoreMessageSnackBar(
            CoreMessageWidget.error(title: strings.cancelOrderFailureText.localize(context)),
            autoDismiss: true,
          );
    [...]

Can someone help me fix this return statement?

Body:
To expand your code a little bit:

@override
Widget build(BuildContext context) {
...
    else if (state is CancelOrderErrorState) {
          showCoreMessageSnackBar(
            CoreMessageWidget.error(title: strings.cancelOrderFailureText.localize(context)),
            autoDismiss: true,
          );
        return Container(); //<--add this
    }
...
}

You HAVE to return what the method is defined to return which is a Widget. Since the build method is overridden you can't change the return type. Sometimes returning something simple is all you can do.


问:
How to parse a string of version numbers in Groovy?
I have a string containing a version number like major.minor.patch.build but I only want to keep major.minor.patch where each number can have 1-3 digits.
How can I do this in groovy?

Examples for a result:
1.20.30.44 -> 1.20.30
or
1.21.1.1 -> 1.21.1

答:
This expression returns the substring of an versionString before the last dot - and so results exactly what you have specified in your question:</p>
```<code>versionString = '1.20.30.44'
println versionString[0..versionString.lastIndexOf('.')-1]
// => 1.20.30
</code>```

Body:
This expression returns the substring of an versionString before the last dot - and so results exactly what you have specified in your question:

versionString = '1.20.30.44'
println versionString[0..versionString.lastIndexOf('.')-1]
// => 1.20.30


问:
Gevent's libev, and Twisted's reactor
I'm trying to figure out how Gevent works with respect to other asynchronous frameworks in python, like Twisted.

The key difference between Gevent and Twisted is that Gevent uses greenlets and monkey patching the standard library for an implicit behavior and a synchronous programming model whereas Twisted requires specific libraries and callbacks for an explicit behavior. The event loop in Gevent is libev/libevent, which is written in C, and the event loop in Twisted is the reactor, which is written in python.

Is there anything special about libev/libevent that allows for this implicit behavior? Why not use an event loop written in Python? Conversely, why isn't Twisted using libev/libevent? Is there any particular reason? Maybe it was simply a design choice and could have gone either way...

Theoretically, can Gevent's libev be replaced with another event loop, written in python, like Twisted's reactor? And can Twisted's reactor be replaced with libev?

答:
Short answer: Twisted is a network framework. Gevent tries to act as a library without requiring from the programmer to change the way he programs. That's their focus.. and not so much how that is achieved under the hood.

Long answer:

All asyncio libraries (Gevent, Asyncio, etc.) work pretty much the same:

Have a main loop running endlessly on a single thread.

When an event occurs, it's captured by the main loop.

The main loop decides based on different rules (scheduling) if it should continue checking for events or switch temporarily and give control to any subscriber functions to the event.

greenlet is a different library. It's very simple in that it just changes the order that Python code is run and lets you change jumping back and forth between functions. Gevent uses it under the hood to implement its async features.

asyncio which comes with Python3 is like gevent. The big difference is the interface again. It requires the programmer to mark functions with async and allow him to explicitly wait for a subscribed function in the main loop with await.

Gevent is like asyncio. But instead of the keywords it patches existing code where appropriate. It uses greenlet under the hood to switch between main loop and subscribed functions and make it all work seamlessly.

Twisted as mentioned feels more like a framework than a library. It requires the programmer to follow very specific ways to achieve concurrency. Again though it has a main loop under the hood called reactor like everything else.

Back to your initial question: You can in theory replace the reactor with any loop (including gevent). But that would defeat the purpose. Probably Twisted's team decided to use their own version of a main loop for optimisation reasons. All these libraries use different scheduling in their main loops to meet their needs.

Title: Gevent's libev, and Twisted's reactor


问:
Paho MQTT unexpectedly calls on_connect
My script reads data from MQTT server and writes it to postgres table.

I'm using loop_forever().
The program is supposed to run nonstop.

When the first connection is received everything works fine, but after some time (from minutes to days) on_connect() is called again. The program works (in the meaning that there is no error in connection) but no meassages are received any more.

In order to debug I tried following:

induce disconnect by switching off and on the network connection

shutting off and on the server

calling client.disconnect()

To my surprise first and second thing did nothing - there was no logs about new connection and the running program just kept running after the connection revived.

The third attempt was unsuccesfull, I couldn't make it work.

Other remarks:

I tried using loop_start() instead of loop_forever but was not succesfull with that at all

So basically the questions are:

how to counter-act ?

how to disconnect manually to replicate the problem of calling on_connect (and loosing incoming data)

My code:

```<code>import json
import sys
from paho.mqtt import client as mqtt_client
import psycopg2
import logging as log
from datetime import datetime
import certifi
from collections import defaultdict

def connect_mqtt(userdict) -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        log.info(f"{datetime.now()}: Trying connect")
        if rc == 0:
            log.info(f"{datetime.now()}: Connection returned result: " + mqtt_client.connack_string(rc))
        else:
            log.info("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id=conf['client_id'], protocol=mqtt_client.MQTTv31, userdata=userdict)
    client.tls_set(certifi.where())
    client.tls_insecure_set(True)

    client.username_pw_set(conf['username'], conf['password'])
    client.on_connect = on_connect
    client.connect(conf['broker'], conf['port'])
    return client

def on_message(client, userdata, msg):
    now_ts_in_s = round(datetime.timestamp(datetime.now()))
    now_dt_in_s = datetime.fromtimestamp(now_ts_in_s)

    try:
        value = float(msg.payload.decode())
        data = [now_dt_in_s,  value]
        insert_to_psql(userdata['conn'], data)
    except ValueError:
        pass

def insert_to_psql(conn, data):
    cursor = conn.cursor()
    insert_query = "INSERT INTO data (time, value) VALUES (%s, %s) ON CONFLICT " \
                   "DO " \
                   "NOTHING;"
    cursor.execute(insert_query, data)
    conn.commit()

def run():
    psql_conn = "postgres://postgres:blablabla"
    conn = psycopg2.connect(psql_conn)

    userdict = {'collected_data': defaultdict(list), 'conn': conn, 'first_conn': True}
    client = connect_mqtt(userdict)
    client.subscribe(conf['topic'])
    client.on_message = on_message
    try:
        client.loop_forever()
    finally:
        client.disconnect()
        conn.close()

if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        conf = json.load(f)
    run()
</code>```

答:
If connect is called, then disconnect is probably called before that. Could be some temporary network issue. You should configure the corresponding callback.

Note, that because of this, it's most important that you subscribe in the on_connect callback and not one time outside that. When paho disconnects and connects again, it won't resubscribe automatically. That's why subscriptions should be made in the on_connect callback.

To you question how to test this. You can run a local MQTT broker, and just shut it down after your app has connected the first time and then start it again.

Apart from that, messages won't be lost if you configure your broker accordingly. MQTT has various QOS settings for that specific purpose.

If you think your app is the problem, and its not some networking issue, you could gain a somewhat more solid setup by deploying your app multiple times and let the replicas subscribe via shared subscription. https://www.hivemq.com/blog/mqtt5-essentials-part7-shared-subscriptions/

Title: Paho MQTT unexpectedly calls on_connect

Body:
My script reads data from MQTT server and writes it to postgres table.

I'm using loop_forever().
The program is supposed to run nonstop.

When the first connection is received everything works fine, but after some time (from minutes to days) on_connect() is called again. The program works (in the meaning that there is no error in connection) but no meassages are received any more.

In order to debug I tried following:

induce disconnect by switching off and on the network connection

shutting off and on the server

calling client.disconnect()

To my surprise first and second thing did nothing - there was no logs about new connection and the running program just kept running after the connection revived.

The third attempt was unsuccesfull, I couldn't make it work.

Other remarks:

I tried using loop_start() instead of loop_forever but was not succesfull with that at all

So basically the questions are:

how to counter-act ?

how to disconnect manually to replicate the problem of calling on_connect (and loosing incoming data)

My code:

import json
import sys
from paho.mqtt import client as mqtt_client
import psycopg2
import logging as log
from datetime import datetime
import certifi
from collections import defaultdict

def connect_mqtt(userdict) -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        log.info(f"{datetime.now()}: Trying connect")
        if rc == 0:
            log.info(f"{datetime.now()}: Connection returned result: " + mqtt_client.connack_string(rc))
        else:
            log.info("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id=conf['client_id'], protocol=mqtt_client.MQTTv31, userdata=userdict)
    client.tls_set(certifi.where())
    client.tls_insecure_set(True)

    client.username_pw_set(conf['username'], conf['password'])
    client.on_connect = on_connect
    client.connect(conf['broker'], conf['port'])
    return client

def on_message(client, userdata, msg):
    now_ts_in_s = round(datetime.timestamp(datetime.now()))
    now_dt_in_s = datetime.fromtimestamp(now_ts_in_s)

    try:
        value = float(msg.payload.decode())
        data = [now_dt_in_s,  value]
        insert_to_psql(userdata['conn'], data)
    except ValueError:
        pass

def insert_to_psql(conn, data):
    cursor = conn.cursor()
    insert_query = "INSERT INTO data (time, value) VALUES (%s, %s) ON CONFLICT " \
                   "DO " \
                   "NOTHING;"
    cursor.execute(insert_query, data)
    conn.commit()

def run():
    psql_conn = "postgres://postgres:blablabla"
    conn = psycopg2.connect(psql_conn)

    userdict = {'collected_data': defaultdict(list), 'conn': conn, 'first_conn': True}
    client = connect_mqtt(userdict)
    client.subscribe(conf['topic'])
    client.on_message = on_message
    try:
        client.loop_forever()
    finally:
        client.disconnect()
        conn.close()

if __name__ == '__main__':
    with open(sys.argv[1]) as f:
        conf = json.load(f)
    run()


问:
tk eventspending?
How do you refresh the tk gui while doing some computation inside of a button call back routine?

The routine takes a long time, and the user wants to see some progress.

Need some way to repaint the screen / look for the cancel button.

in gtk its like this:

/* computation going on */
...
    while (gtk_events_pending ())
      gtk_main_iteration ();
...
/* computation continued */
```

答:
I might be missing the point, but why would't you use thread for that? You won't be able to join it in a callback, but you still should be able to generate an event.

```<code>TkButton.new :text => 'Hard routine',
             :command => proc { Thread.new { hard_routine } }.pack
Tk.mainloop
</code>```

doing the heavy things in your callback is considered a bad practice since it blocks the entire event loop so your gui freezes.

Title: tk eventspending?

Body:
I might be missing the point, but why would't you use thread for that? You won't be able to join it in a callback, but you still should be able to generate an event.

TkButton.new :text => 'Hard routine',
             :command => proc { Thread.new { hard_routine } }.pack
Tk.mainloop

doing the heavy things in your callback is considered a bad practice since it blocks the entire event loop so your gui freezes.


问:
Laravel whereHas on multiple relationships
Does anyone know if this new feature can be performed on multiple relationships?

For example, I have a query where I want to filter on not only the club name (related question) but also the territory name.

In this example, I'd like query results where the club (club relationship) name is Arsenal and the the region is Australia (territory relationship)

```<code>$ret->with('territory')->with('homeClub')->with('awayClub');
    $ret->whereHas('territory',function( $query ){
            $query->where('region','Australia');
        })->whereHas('homeClub', function ( $query ) {
            $query->where('name', 'Arsenal' );
        })->orWhereHas('awayClub', function ( $query ) {
            $query->where('name', 'Arsenal' );
        });
</code>```

When executing this query - the result isn't constraining the territory whereHas just the clubs one.

Can whereHas be chained to filter the results on previous relationship's whereHas? Any suggestions if not?

thanks

jon

答:
```<code> $homeAndLiving    =   Product::with('user')->whereHas('category',function($query){
                          $query->where('category_slug', 'home--living')
                            ->where('is_active','=','on');
                       })
                            ->whereHas('user',function($q){
                          $q->where('is_enabled',1);
                      })->inRandomOrder()->take(6)
                      ->get();
</code>```

This is what works great for me.

Body:
Does anyone know if this new feature can be performed on multiple relationships?

For example, I have a query where I want to filter on not only the club name (related question) but also the territory name.

In this example, I'd like query results where the club (club relationship) name is Arsenal and the the region is Australia (territory relationship)

$ret->with('territory')->with('homeClub')->with('awayClub');
    $ret->whereHas('territory',function( $query ){
            $query->where('region','Australia');
        })->whereHas('homeClub', function ( $query ) {
            $query->where('name', 'Arsenal' );
        })->orWhereHas('awayClub', function ( $query ) {
            $query->where('name', 'Arsenal' );
        });

When executing this query - the result isn't constraining the territory whereHas just the clubs one.

Can whereHas be chained to filter the results on previous relationship's whereHas? Any suggestions if not?

thanks

jon

Body:
 $homeAndLiving    =   Product::with('user')->whereHas('category',function($query){
                          $query->where('category_slug', 'home--living')
                            ->where('is_active','=','on');
                       })
                            ->whereHas('user',function($q){
                          $q->where('is_enabled',1);
                      })->inRandomOrder()->take(6)
                      ->get();

This is what works great for me.


问:
blank screen on website after configuring apex domain and www subdomain variant on github
I am using vite+svelte wanted to host my webpage using github pages

Deployed Vite app as showed in the video How to Deploy Your Vite App to Github Pages

Create a repo repo1 on github

all stuff

```<code>git init
git add .
git commit -m "comment"
git branch -M main
git remote add origin https:// ........git
</code>```

Changed the base url inside vite.config.js

```<code>import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

// https://vitejs.dev/config/
export default defineConfig({
    base: '/repo1/',
  plugins: [svelte()]
})
</code>```

npm run build

git add dist -f

git commit -m "add dist"

git subtree push --prefix dist origin gh-pages

Got website running with this extension https://name.github.io/repo1/

Wanted to add a custom domain to the repo1

Saw this page Configuring an apex domain and the www subdomain variant

First configure an apex domain with A record

```<code>On GitHub, navigate to your site's repository.

Under your repository name, click  Settings.

Repository settings button

click Pages

Under "Custom domain", type your example.com, then click Save

Check for CNAME created inside repo1 containing example.com

Changed A record in DNS provider

185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153
</code>```

Then configured a CNAME record with your DNS provider

type CNAME name www.example.com data username.github.io.

confirmed if DNS record configured correctly using

dig WWW.EXAMPLE.COM +nostats +nocomments +nocmd

I had to get this output

```<code>> ;WWW.EXAMPLE.COM.                     IN      A
    > WWW.EXAMPLE.COM.              3592    IN      CNAME   YOUR-USERNAME.github.io.
    > YOUR-USERNAME.github.io.      43192   IN      CNAME    GITHUB-PAGES-SERVER .
    >  GITHUB-PAGES-SERVER .         22      IN      A       192.0.2.1
</code>```

But what I got is

```<code>;WWW.EXAMPLE.COM.   IN  A
WWW.EXAMPLE.COM. 9999   IN  CNAME   YOUR-USERNAME.github.io.
YOUR-USERNAME.github.io. 9999 IN    A   185.199.111.153
YOUR-USERNAME.github.io. 9999 IN    A   185.199.109.153
YOUR-USERNAME.github.io. 9999 IN    A   185.199.110.153
YOUR-USERNAME.github.io. 9999 IN    A   185.199.108.153
</code>```

I never got these

username pointing to github-pages-server

    > YOUR-USERNAME.github.io.      43192   IN      CNAME    GITHUB-PAGES-SERVER .

github-pages-server pointing to IP

    >  GITHUB-PAGES-SERVER .         22      IN      A       192.0.2.1

When I tried checking www.example.com my custom domain I get a blank white screen no errors or  warning message on the website just a white screen

I came across this How to Configure GitHub Pages Custom Domain? (Google Domains | Subdomain & Apex Domain)

He too gets a blank white screen without any kind of error or warning messages on page load just as mine he inspects the page gets 404 error on console

When I checked my custom domain inspect -> console

Even i got similar warning

```<code>example.com/:8
GET https://example.com/repo1/assets/index.b0a7898d.js net::ERR_ABORTED 404
example.com/:9
GET https://example.com/repo1/assets/vendor.8c7ac98a.js net::ERR_ABORTED 404
example.com/:10
GET https://example.com/repo1/assets/index.897361a6.css net::ERR_ABORTED 404
</code>```

He adds homepage inside package.json

```<code>  "homepage": "https://example.com",
</code>```

Saves pushes the code on github and website starts working

How do I correct this?

Do I add '"homepage": "https://example.com",' inside package.json?

Or

Should I change the base URL inside vite.config.js from /repo1/ to example.com?

OR

have I missed anything in between?

I am confused please help

答:
Went through vite documentation

base is required to be specified inside vite.config.js

```<code>base
    Type: string
    Default: /
    Base public path when served in development or production. Valid values include:
        Absolute URL pathname, e.g. /repo-name/
        Full URL, e.g. https://example.com/
        Empty string or ./ (for embedded deployment)
</code>```

default vite.config.js file content below

```<code>import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
  plugins: [svelte()]
})
</code>```

When deploying with https://user-name.github.io/repo-name/
add base with repo-name

```<code>import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
    base: '/repo-name/',
  plugins: [svelte()]
})
</code>```

When deploying with https://example.com(your custom domain)
add base with https://example.com

```<code>import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
    base: 'https://example.com/',
  plugins: [svelte()]
})
</code>```

Then npm run build update to your github repo, same procedure

Got my site running

Body:
I am using vite+svelte wanted to host my webpage using github pages

Deployed Vite app as showed in the video How to Deploy Your Vite App to Github Pages

Create a repo repo1 on github

all stuff

git init
git add .
git commit -m "comment"
git branch -M main
git remote add origin https:// ........git

Changed the base url inside vite.config.js

import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

// https://vitejs.dev/config/
export default defineConfig({
    base: '/repo1/',
  plugins: [svelte()]
})

npm run build

git add dist -f

git commit -m "add dist"

git subtree push --prefix dist origin gh-pages

Got website running with this extension https://name.github.io/repo1/

Wanted to add a custom domain to the repo1

Saw this page Configuring an apex domain and the www subdomain variant

First configure an apex domain with A record

On GitHub, navigate to your site's repository.

Under your repository name, click  Settings.

Repository settings button

click Pages

Under "Custom domain", type your example.com, then click Save

Check for CNAME created inside repo1 containing example.com

Changed A record in DNS provider

185.199.108.153
185.199.109.153
185.199.110.153
185.199.111.153

Then configured a CNAME record with your DNS provider

type CNAME name www.example.com data username.github.io.

confirmed if DNS record configured correctly using

dig WWW.EXAMPLE.COM +nostats +nocomments +nocmd

I had to get this output

> ;WWW.EXAMPLE.COM.                     IN      A
    > WWW.EXAMPLE.COM.              3592    IN      CNAME   YOUR-USERNAME.github.io.
    > YOUR-USERNAME.github.io.      43192   IN      CNAME    GITHUB-PAGES-SERVER .
    >  GITHUB-PAGES-SERVER .         22      IN      A       192.0.2.1

But what I got is

;WWW.EXAMPLE.COM.   IN  A
WWW.EXAMPLE.COM. 9999   IN  CNAME   YOUR-USERNAME.github.io.
YOUR-USERNAME.github.io. 9999 IN    A   185.199.111.153
YOUR-USERNAME.github.io. 9999 IN    A   185.199.109.153
YOUR-USERNAME.github.io. 9999 IN    A   185.199.110.153
YOUR-USERNAME.github.io. 9999 IN    A   185.199.108.153

I never got these

username pointing to github-pages-server

    > YOUR-USERNAME.github.io.      43192   IN      CNAME    GITHUB-PAGES-SERVER .

github-pages-server pointing to IP

    >  GITHUB-PAGES-SERVER .         22      IN      A       192.0.2.1

When I tried checking www.example.com my custom domain I get a blank white screen no errors or  warning message on the website just a white screen

I came across this How to Configure GitHub Pages Custom Domain? (Google Domains | Subdomain & Apex Domain)

He too gets a blank white screen without any kind of error or warning messages on page load just as mine he inspects the page gets 404 error on console

When I checked my custom domain inspect -> console

Even i got similar warning

example.com/:8
GET https://example.com/repo1/assets/index.b0a7898d.js net::ERR_ABORTED 404
example.com/:9
GET https://example.com/repo1/assets/vendor.8c7ac98a.js net::ERR_ABORTED 404
example.com/:10
GET https://example.com/repo1/assets/index.897361a6.css net::ERR_ABORTED 404

He adds homepage inside package.json

  "homepage": "https://example.com",

Saves pushes the code on github and website starts working

How do I correct this?

Do I add '"homepage": "https://example.com",' inside package.json?

Or

Should I change the base URL inside vite.config.js from /repo1/ to example.com?

OR

have I missed anything in between?

I am confused please help

Body:
Went through vite documentation

base is required to be specified inside vite.config.js

base
    Type: string
    Default: /
    Base public path when served in development or production. Valid values include:
        Absolute URL pathname, e.g. /repo-name/
        Full URL, e.g. https://example.com/
        Empty string or ./ (for embedded deployment)

default vite.config.js file content below

import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
  plugins: [svelte()]
})

When deploying with https://user-name.github.io/repo-name/
add base with repo-name

import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
    base: '/repo-name/',
  plugins: [svelte()]
})

When deploying with https://example.com(your custom domain)
add base with https://example.com

import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
    base: 'https://example.com/',
  plugins: [svelte()]
})

Then npm run build update to your github repo, same procedure

Got my site running