问:
How to emit to a certain socket from a thread in flask socketio?
i want to isolate each socket connection and emit to that specific connection, when i try to run without threading, it works fine and each socket gets it's own messages, but when i use threading, it just starts broadcasting and all the clients receive all the messages.

Here's how my client side looks like :

var socket = io.connect('https://my_server_link');

 socket.on('connect', function() {
  console.log('Connection Success')
 });

 // Recieves the session id
 socket.on('connection_status',  (data)=>{
  console.log('Connection Status')
  console.log(data);
  session_id = data['session_id']
  socket.emit('verifyClient', {'session_id': session_id, 'api_id': api_id})
 })

 socket.on('verification_status', (data)=>{
  console.log('Verification Status')
  console.log(data)
  if (data['status']){
   console.log('Verified')
   socket.emit('setupUser', {'session_id': session_id, 'user_id': user_id})
  }
 })

 socket.on('user_setup_status', (data)=>{
  console.log('User Setup Status');
  console.log(data);
  if (data['status']){
   console.log('User Setup Successful, Starting monitoring...')
   running_ops = setInterval(()=>{
    op_interval(session_id)
   }, 5000)
  }
 })

 function op_interval(session_id){
  ctx2.drawImage(video, 0, 0, video.width, video.height);
  frame = canva.toDataURL('image/jpeg');
  frame = to_blob(frame);
  socket.emit('monitor', {
   'frame':frame,
   'session_id':session_id
   });
 }

 // when error messages are encountered, generate alert on client side
 socket.on('alert', (alert)=>{
  console.log(alert);
  // TODO : Handle Alerts Here
 })```
</div>
</div>
</p>

<p>And here's my server side.</p>

<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code>app = Flask(__name__)

CORS(app, resources={"*": {"origins": "*"}})

# eventlet.monkey_patch()

socketio = SocketIO(app, async_mode='threading', cors_allowed_origins="*")

# Set up socket connection to the client and register session id
@socketio.on('connect')
def handle_connection():
 print('Connection Successfull')
 # connection_id = request.sid
 session_id = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
 active_socket_sessions[session_id] = {'session_id': session_id}#, 'connection_id': connection_id}
 join_room(session_id)
 emit('connection_status', {'status':'success', 'session_id':session_id}, room=session_id)

@socketio.on('verifyClient')
def verification(data):
 session_id = data['session_id']
 client_id = data['api_id']
 verified = False
 message = "Session not found."

 if session_id in active_socket_sessions.keys():
  client, message = verify_client(database, client_id, active_sessions)

  if len(client.keys()) > 0:
   verified = True
   active_socket_sessions[session_id]['client_id'] = client['client_id']

  emit('verification_status', {'status':verified, 'message': message, 'session_id':session_id}, room=session_id)
 else:
  emit('verification_status', {'status':verified, 'message': message, 'session_id':session_id})

@socketio.on('setupUser')
def user_setup(data):
 session_id = data['session_id']
 user_id = data['user_id']
 found = False
 message = 'Session not found.'

 if session_id in active_socket_sessions.keys():
  client_id = active_socket_sessions[session_id]['client_id']
  user, message = get_user(database, {'client_id': client_id}, user_id)

  if len(user.keys()) > 0:
   found = True
   user['person_encoding'] = str(user['person_encoding'])
   active_socket_sessions[session_id]['user'] = user
   rediss.set_dict(session_id, active_socket_sessions[session_id])
   active_socket_sessions[session_id] = {}

  emit('user_setup_status', {'status': found, 'message': message, 'session_id': session_id}, room=session_id)
 else:
  emit('user_setup_status', {'status': found, 'message': message, 'session_id': session_id})

@socketio.on('disconnect')
def handle_disconnect():
 # Handle Clearing Of Socket From Redis And Also Closing The Socket Connection
 emit('connection_ended', {'data': 'Successfully Disconnected, Socket Is Closed.'})

@socketio.on('monitor')
def monitor(data):
 frame = data['frame']
 session_id = data['session_id']
 socketio.start_background_task(monitoring_process, frame, session_id)

def monitoring_process(frame, session_id):
 if session_id in active_socket_sessions.keys():
  session = rediss.get_dict(session_id)
  client_id = session['client_id']
  user = session['user']
  user_encoding = np.array(eval(user['person_encoding']))
  person_id = user['person_id']
  browser_info = {}

  frame = cv2.imdecode(np.frombuffer(frame, np.uint8), -1)
  preds = model.model.predict(frame, user_encoding)

  if not preds['recognized']:
   alert = vars.BRISO_ALERTS[preds['message']]
   alert['timestamp'] = str(time.time())
   alert['log_id'] = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
   alert['person_id'] = person_id
   headers = browser_info
   message, flag = log_alert(database, client_id, alert, headers)
   preds['session_id'] = session_id
   socketio.emit('alert', preds, room=session_id)

if __name__ == "__main__":
 socketio.run(app, host=vars.HOST_NAME, port=vars.SERVER_PORT, debug=False, use_reloader=False)</code>```

答:
Ok, so as suggested by Miguel Grinberg himself, when i asked him on github, the only replacement i had to make was to switch from setting my own session_id to request.sid and not calling the join_room method.

The updated (working) code looks like this :

For client side socket.io:

socket.on('connect', function() {
  console.log('Connection Success')
 });

 // Recieves the session id
 socket.on('connection_status', (data)=>{
  console.log('Connection Status')
  console.log(data);
  session_id = data['session_id']
  socket.emit('verify_client', {'session_id': session_id, 'api_id': api_id}, (status)=>{
   socket.emit('setup_user', {'session_id': session_id, 'user_id': user_id}, (status)=>{
    running_ops = setInterval(()=>{
     op_interval(session_id)
    }, 5000)
   })
  })
 })

  function op_interval(session_id){
  ctx2.drawImage(video, 0, 0, video.width, video.height);
  frame = canva.toDataURL('image/jpeg');
  frame = to_blob(frame);
  socket.emit('monitor', {
   'frame':frame,
   'session_id':session_id
   });
 }

  // when error messages are encountered, generate alert on client side
 socket.on('alert', (alert)=>{
  console.log(alert);
 })```
</div>
</div>
</p>

<p>for python flask socketio</p>

<p><div class="snippet" data-lang="js" data-hide="false" data-console="true" data-babel="false">
<div class="snippet-code">
<pre class="snippet-code-js lang-js prettyprint-override"><code># Set up socket connection to the client and register session id
@socketio.on('connect')
def handle_connection():
 print('Connection Successfull')
 session_id = request.sid
 active_socket_sessions[session_id] = {'session_id': session_id}#, 'connection_id': connection_id}
 emit('connection_status', {'status':'success', 'session_id':session_id}, room=session_id)

@socketio.on('verify_client')
def verification(data):
 session_id = request.sid
 client_id = data['api_id']
 verified = False
 message = "Session not found."

 if session_id in active_socket_sessions.keys():
  client, message = verify_client(database, client_id, active_sessions)

  if len(client.keys()) > 0:
   verified = True
   active_socket_sessions[session_id]['client_id'] = client['client_id']

  return json.dumps({'status': verified, 'message': message, 'session_id': session_id})
 else:
  return json.dumps({'status': verified, 'message': message, 'session_id': session_id})

@socketio.on('setup_user')
def user_setup(data):
 session_id = request.sid
 user_id = data['user_id']
 found = False
 message = 'Session not found.'

 if session_id in active_socket_sessions.keys():
  client_id = active_socket_sessions[session_id]['client_id']
  user, message = get_user(database, {'client_id': client_id}, user_id)

  if len(user.keys()) > 0:
   found = True
   user['person_encoding'] = str(user['person_encoding'])
   active_socket_sessions[session_id]['user'] = user
   rediss.set_dict(session_id, active_socket_sessions[session_id])
   active_socket_sessions[session_id] = {}

  return json.dumps({'status': found, 'message': message, 'session_id': session_id})
 else:
  return json.dumps({'status': found, 'message': message, 'session_id': session_id})

@socketio.on('disconnect')
def handle_disconnect():
 # Handle Clearing Of Socket From Redis And Also Closing The Socket Connection
 emit('connection_ended', {'data': 'Successfully Disconnected, Socket Is Closed.'})

@socketio.on('monitor')
def monitor(data):
 frame = data['frame']
 session_id = request.sid

 process = Thread(target=monitoring_process, args=(frame, session_id,))
 process.start()
 process.join()
 socketio.start_background_task(monitoring_process, frame, session_id)

def monitoring_process(frame, session_id):
 if session_id in active_socket_sessions.keys():
  session = rediss.get_dict(session_id)
  client_id = session['client_id']
  user = session['user']
  user_encoding = np.array(eval(user['person_encoding']))
  person_id = user['person_id']
  browser_info = {}

  frame = cv2.imdecode(np.frombuffer(frame, np.uint8), -1)
  preds = model.model.predict(frame, user_encoding)

  if not preds['recognized']:
   alert = vars.ALERTS[preds['message']]
   alert['timestamp'] = str(time.time())
   alert['log_id'] = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
   alert['person_id'] = person_id
   headers = browser_info
   message, flag = log_alert(database, client_id, alert, headers)
   preds['session_id'] = session_id
   # return preds
   socketio.emit('alert', preds, room=session_id)</code>```

Body:
i want to isolate each socket connection and emit to that specific connection, when i try to run without threading, it works fine and each socket gets it's own messages, but when i use threading, it just starts broadcasting and all the clients receive all the messages.

Here's how my client side looks like :

var socket = io.connect('https://my_server_link');

 socket.on('connect', function() {
  console.log('Connection Success')
 });

 // Recieves the session id
 socket.on('connection_status',  (data)=>{
  console.log('Connection Status')
  console.log(data);
  session_id = data['session_id']
  socket.emit('verifyClient', {'session_id': session_id, 'api_id': api_id})
 })

 socket.on('verification_status', (data)=>{
  console.log('Verification Status')
  console.log(data)
  if (data['status']){
   console.log('Verified')
   socket.emit('setupUser', {'session_id': session_id, 'user_id': user_id})
  }
 })

 socket.on('user_setup_status', (data)=>{
  console.log('User Setup Status');
  console.log(data);
  if (data['status']){
   console.log('User Setup Successful, Starting monitoring...')
   running_ops = setInterval(()=>{
    op_interval(session_id)
   }, 5000)
  }
 })

 function op_interval(session_id){
  ctx2.drawImage(video, 0, 0, video.width, video.height);
  frame = canva.toDataURL('image/jpeg');
  frame = to_blob(frame);
  socket.emit('monitor', {
   'frame':frame,
   'session_id':session_id
   });
 }

 // when error messages are encountered, generate alert on client side
 socket.on('alert', (alert)=>{
  console.log(alert);
  // TODO : Handle Alerts Here
 })

And here's my server side.

app = Flask(__name__)

CORS(app, resources={"*": {"origins": "*"}})

# eventlet.monkey_patch()

socketio = SocketIO(app, async_mode='threading', cors_allowed_origins="*")

# Set up socket connection to the client and register session id
@socketio.on('connect')
def handle_connection():
 print('Connection Successfull')
 # connection_id = request.sid
 session_id = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
 active_socket_sessions[session_id] = {'session_id': session_id}#, 'connection_id': connection_id}
 join_room(session_id)
 emit('connection_status', {'status':'success', 'session_id':session_id}, room=session_id)

@socketio.on('verifyClient')
def verification(data):
 session_id = data['session_id']
 client_id = data['api_id']
 verified = False
 message = "Session not found."

 if session_id in active_socket_sessions.keys():
  client, message = verify_client(database, client_id, active_sessions)

  if len(client.keys()) > 0:
   verified = True
   active_socket_sessions[session_id]['client_id'] = client['client_id']

  emit('verification_status', {'status':verified, 'message': message, 'session_id':session_id}, room=session_id)
 else:
  emit('verification_status', {'status':verified, 'message': message, 'session_id':session_id})

@socketio.on('setupUser')
def user_setup(data):
 session_id = data['session_id']
 user_id = data['user_id']
 found = False
 message = 'Session not found.'

 if session_id in active_socket_sessions.keys():
  client_id = active_socket_sessions[session_id]['client_id']
  user, message = get_user(database, {'client_id': client_id}, user_id)

  if len(user.keys()) > 0:
   found = True
   user['person_encoding'] = str(user['person_encoding'])
   active_socket_sessions[session_id]['user'] = user
   rediss.set_dict(session_id, active_socket_sessions[session_id])
   active_socket_sessions[session_id] = {}

  emit('user_setup_status', {'status': found, 'message': message, 'session_id': session_id}, room=session_id)
 else:
  emit('user_setup_status', {'status': found, 'message': message, 'session_id': session_id})

@socketio.on('disconnect')
def handle_disconnect():
 # Handle Clearing Of Socket From Redis And Also Closing The Socket Connection
 emit('connection_ended', {'data': 'Successfully Disconnected, Socket Is Closed.'})

@socketio.on('monitor')
def monitor(data):
 frame = data['frame']
 session_id = data['session_id']
 socketio.start_background_task(monitoring_process, frame, session_id)

def monitoring_process(frame, session_id):
 if session_id in active_socket_sessions.keys():
  session = rediss.get_dict(session_id)
  client_id = session['client_id']
  user = session['user']
  user_encoding = np.array(eval(user['person_encoding']))
  person_id = user['person_id']
  browser_info = {}

  frame = cv2.imdecode(np.frombuffer(frame, np.uint8), -1)
  preds = model.model.predict(frame, user_encoding)

  if not preds['recognized']:
   alert = vars.BRISO_ALERTS[preds['message']]
   alert['timestamp'] = str(time.time())
   alert['log_id'] = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
   alert['person_id'] = person_id
   headers = browser_info
   message, flag = log_alert(database, client_id, alert, headers)
   preds['session_id'] = session_id
   socketio.emit('alert', preds, room=session_id)

if __name__ == "__main__":
 socketio.run(app, host=vars.HOST_NAME, port=vars.SERVER_PORT, debug=False, use_reloader=False)

Body:
Ok, so as suggested by Miguel Grinberg himself, when i asked him on github, the only replacement i had to make was to switch from setting my own session_id to request.sid and not calling the join_room method.

The updated (working) code looks like this :

For client side socket.io:

socket.on('connect', function() {
  console.log('Connection Success')
 });

 // Recieves the session id
 socket.on('connection_status', (data)=>{
  console.log('Connection Status')
  console.log(data);
  session_id = data['session_id']
  socket.emit('verify_client', {'session_id': session_id, 'api_id': api_id}, (status)=>{
   socket.emit('setup_user', {'session_id': session_id, 'user_id': user_id}, (status)=>{
    running_ops = setInterval(()=>{
     op_interval(session_id)
    }, 5000)
   })
  })
 })

  function op_interval(session_id){
  ctx2.drawImage(video, 0, 0, video.width, video.height);
  frame = canva.toDataURL('image/jpeg');
  frame = to_blob(frame);
  socket.emit('monitor', {
   'frame':frame,
   'session_id':session_id
   });
 }

  // when error messages are encountered, generate alert on client side
 socket.on('alert', (alert)=>{
  console.log(alert);
 })

for python flask socketio

# Set up socket connection to the client and register session id
@socketio.on('connect')
def handle_connection():
 print('Connection Successfull')
 session_id = request.sid
 active_socket_sessions[session_id] = {'session_id': session_id}#, 'connection_id': connection_id}
 emit('connection_status', {'status':'success', 'session_id':session_id}, room=session_id)

@socketio.on('verify_client')
def verification(data):
 session_id = request.sid
 client_id = data['api_id']
 verified = False
 message = "Session not found."

 if session_id in active_socket_sessions.keys():
  client, message = verify_client(database, client_id, active_sessions)

  if len(client.keys()) > 0:
   verified = True
   active_socket_sessions[session_id]['client_id'] = client['client_id']

  return json.dumps({'status': verified, 'message': message, 'session_id': session_id})
 else:
  return json.dumps({'status': verified, 'message': message, 'session_id': session_id})

@socketio.on('setup_user')
def user_setup(data):
 session_id = request.sid
 user_id = data['user_id']
 found = False
 message = 'Session not found.'

 if session_id in active_socket_sessions.keys():
  client_id = active_socket_sessions[session_id]['client_id']
  user, message = get_user(database, {'client_id': client_id}, user_id)

  if len(user.keys()) > 0:
   found = True
   user['person_encoding'] = str(user['person_encoding'])
   active_socket_sessions[session_id]['user'] = user
   rediss.set_dict(session_id, active_socket_sessions[session_id])
   active_socket_sessions[session_id] = {}

  return json.dumps({'status': found, 'message': message, 'session_id': session_id})
 else:
  return json.dumps({'status': found, 'message': message, 'session_id': session_id})

@socketio.on('disconnect')
def handle_disconnect():
 # Handle Clearing Of Socket From Redis And Also Closing The Socket Connection
 emit('connection_ended', {'data': 'Successfully Disconnected, Socket Is Closed.'})

@socketio.on('monitor')
def monitor(data):
 frame = data['frame']
 session_id = request.sid

 process = Thread(target=monitoring_process, args=(frame, session_id,))
 process.start()
 process.join()
 socketio.start_background_task(monitoring_process, frame, session_id)

def monitoring_process(frame, session_id):
 if session_id in active_socket_sessions.keys():
  session = rediss.get_dict(session_id)
  client_id = session['client_id']
  user = session['user']
  user_encoding = np.array(eval(user['person_encoding']))
  person_id = user['person_id']
  browser_info = {}

  frame = cv2.imdecode(np.frombuffer(frame, np.uint8), -1)
  preds = model.model.predict(frame, user_encoding)

  if not preds['recognized']:
   alert = vars.ALERTS[preds['message']]
   alert['timestamp'] = str(time.time())
   alert['log_id'] = ''.join(random.choice(string.ascii_lowercase) for i in range(10))
   alert['person_id'] = person_id
   headers = browser_info
   message, flag = log_alert(database, client_id, alert, headers)
   preds['session_id'] = session_id
   # return preds
   socketio.emit('alert', preds, room=session_id)


来源: stackexchange

问:
How to replace arrow operator(->) with dot(.) operator in a string
I have a string like this

```<code>s = '''int t; //variable t
t->a=0;  //t->a does;; something
printf("\nEnter the Employee ID : ");
scanf("%d", ptrx->eid);  //employee id ptrx->eid
printf("\nEnter the Employee Name : ");
scanf("%s", ptr->name);
return 0;'''
</code>```

I want to replace -> this with . in above string. But this replacement shouldn't be done inside commments. A comment is a string that starts with // and terminates at the end of the line.

I have tried  with below code. Is there any way this can solved using single regular expression.

Code

```<code>import re

for line in s.split('\n'):
    code = re.findall('^(?:(?!\/\/.+$).)*', line)
    comment = re.findall('\/\/.+$', line)
    print(''.join(code).replace('->', '.') + ''.join(comment))
</code>```

Expected Output:

```<code>int t; //variable t
t.a=0;  //t->a does;; something
printf("
Enter the Employee ID : ");
scanf("%d", ptrx.eid);  //employee id ptrx->eid
printf("
Enter the Employee Name : ");
scanf("%s", ptr.name);
return 0;
</code>```

答:
Using the regex library which allows variable length lookbehind allows the following.</p>

```<code>>>> s = '''int t; //variable t
t->a=0;  //t->a does;; something
printf("\nEnter the Employee ID : ");
scanf("%d", ptrx->eid);  //employee id ptrx->eid
printf("\nEnter the Employee Name : ");
scanf("%s", ptr->name);
return 0;'''.splitlines()

>>> import regex
>>> for line in s:
    n = regex.sub(r'(?<!//.+)->', '.', line)
    print(n)

int t; //variable t
t.a=0;  //t->a does;; something
printf("
Enter the Employee ID : ");
scanf("%d", ptrx.eid);  //employee id ptrx->eid
printf("
Enter the Employee Name : ");
scanf("%s", ptr.name);
return 0;
>>>
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I have a string like this

s = '''int t; //variable t
t->a=0;  //t->a does;; something
printf("\nEnter the Employee ID : ");
scanf("%d", ptrx->eid);  //employee id ptrx->eid
printf("\nEnter the Employee Name : ");
scanf("%s", ptr->name);
return 0;'''

I want to replace -> this with . in above string. But this replacement shouldn't be done inside commments. A comment is a string that starts with // and terminates at the end of the line.

I have tried  with below code. Is there any way this can solved using single regular expression.

Code

import re

for line in s.split('\n'):
    code = re.findall('^(?:(?!\/\/.+$).)*', line)
    comment = re.findall('\/\/.+$', line)
    print(''.join(code).replace('->', '.') + ''.join(comment))

Expected Output:

int t; //variable t
t.a=0;  //t->a does;; something
printf("
Enter the Employee ID : ");
scanf("%d", ptrx.eid);  //employee id ptrx->eid
printf("
Enter the Employee Name : ");
scanf("%s", ptr.name);
return 0;

Body:
Using the regex library which allows variable length lookbehind allows the following.

>>> s = '''int t; //variable t
t->a=0;  //t->a does;; something
printf("\nEnter the Employee ID : ");
scanf("%d", ptrx->eid);  //employee id ptrx->eid
printf("\nEnter the Employee Name : ");
scanf("%s", ptr->name);
return 0;'''.splitlines()

>>> import regex
>>> for line in s:
    n = regex.sub(r'(?<!//.+)->', '.', line)
    print(n)

int t; //variable t
t.a=0;  //t->a does;; something
printf("
Enter the Employee ID : ");
scanf("%d", ptrx.eid);  //employee id ptrx->eid
printf("
Enter the Employee Name : ");
scanf("%s", ptr.name);
return 0;
>>>


问:
How to combine two tables in SQL Server
I have these two tables:

Table 1

```<code>Date          Name         StudentID          TotalDuration
------------------------------------------------------------
2019-09-30    aA           11111              100
2019-09-30    bB           22222              40
2019-09-30    cC           33333              60
2019-10-07    aA           11111              50
2019-10-07    bB           22222              10
2019-10-07    cC           33333              12
2019-10-07    dD           44444              90

</code>```

It contains data of students who ATTENDED a lecture (hence, does not include those who did not attend.

Table 2

```<code>StudentID          Surname         FirstName          Group
------------------------------------------------------------
11111              A               a                  1
22222              B               b                  1
33333              C               c                  1
44444              D               d                  2
55555              E               e                  2
66666              F               f                  2
77777              G               g                  3
</code>```

Table2 contains data of ALL students in the class.

Name attribute in Table 1 is combination of surname + first name and TotalDuration is duration of student participation in minutes.

I want to combine these two tables so that it list all the students in the class and their TotalDuration.

I tried OUTER JOIN and UNION ALL, but can't figure out how I can list all the student, yet shows NULL value for those students who did not attend to the lecture on particular date.

How can I achieve this?

答:
You could left join and group by. But since you just need one aggregate computation, a correlated subquery is probably a simpler and more efficient approach (if you have the right index in place - see below):

```<code>select
    t2.*,
    (
        select sum(totalduration)
        from table1 t1
        where t1.studentid = t2.studentid
    ) totalduration
from table2 t2
</code>```

For performance, consider an index on table1(studentid, totalduration).

Side note: from a database design perspective, column Name in table1 is just not needed; this is redondant information, that complicates maintenance task (what if someone changes the first name of a studend in the other table?). You should remove that column, and rely on the foreign key on studentid only.

Title: How to combine two tables in SQL Server

Body:
I have these two tables:

Table 1

Date          Name         StudentID          TotalDuration
------------------------------------------------------------
2019-09-30    aA           11111              100
2019-09-30    bB           22222              40
2019-09-30    cC           33333              60
2019-10-07    aA           11111              50
2019-10-07    bB           22222              10
2019-10-07    cC           33333              12
2019-10-07    dD           44444              90

It contains data of students who ATTENDED a lecture (hence, does not include those who did not attend.

Table 2

StudentID          Surname         FirstName          Group
------------------------------------------------------------
11111              A               a                  1
22222              B               b                  1
33333              C               c                  1
44444              D               d                  2
55555              E               e                  2
66666              F               f                  2
77777              G               g                  3

Table2 contains data of ALL students in the class.

Name attribute in Table 1 is combination of surname + first name and TotalDuration is duration of student participation in minutes.

I want to combine these two tables so that it list all the students in the class and their TotalDuration.

I tried OUTER JOIN and UNION ALL, but can't figure out how I can list all the student, yet shows NULL value for those students who did not attend to the lecture on particular date.

How can I achieve this?

Body:
You could left join and group by. But since you just need one aggregate computation, a correlated subquery is probably a simpler and more efficient approach (if you have the right index in place - see below):

select
    t2.*,
    (
        select sum(totalduration)
        from table1 t1
        where t1.studentid = t2.studentid
    ) totalduration
from table2 t2

For performance, consider an index on table1(studentid, totalduration).

Side note: from a database design perspective, column Name in table1 is just not needed; this is redondant information, that complicates maintenance task (what if someone changes the first name of a studend in the other table?). You should remove that column, and rely on the foreign key on studentid only.


问:
Puppeteer: wait for Ajax call after page loading

SOLUTION:

As per @pguardiario 's suggestion, the following intercepts the Ajax call and waits for its completion:

```<code>  await page.waitForResponse('http://localhost:58080/', {timeout: 2000})
    .catch(() => {console.log('[puppeteer] Error')});
</code>```

I have a page which performs an Ajax call after the page has loaded and I need for puppeteer to wait for the completion of that call. In puppeteer : wait for ajax call after navigation the accepted answer uses await page.waitForSelector(cssSelector); which doesn't work in my current case since the success of the Ajax call doesn't add any new elements to the page. Here's a minimal working example with some comments as to what the actual page does:

index.html:

```<code><!DOCTYPE html>
<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js" charset="utf-8"></script>
  </head>
  <body>
  </body>
  <script charset="utf-8">
    $(document).ready(function() {
      // render data previously stored in localStorage
      console.log('Fetching page');
      // in reality it is fetching a JSON API endpoint, but for the purposes of this example, use /
      $.get("/")
      .fail(function () {
        // add an error element to the page
        console.log('Error');
      })
      .done(function () {
        // empty the table containing the data and rerender
        console.log('Success');
      })
      .always(function () {
        // puppeteer can now continue and check for error
        console.log('Done fetching page');
      });
    });
  </script>
</html>
</code>```

test.js:

```<code>const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', consoleObj => console.log(consoleObj.text()));
  await page.goto('http://localhost:58080');
  // What to do to wait for the completion of the ajax call done after
  // document is ready?
  console.log('[puppeteer] Sleeping');
  await new Promise(resolve => setTimeout(resolve, 1000));
  console.log('[puppeteer] Closing');
  await browser.close();
});
</code>```

serve.js:

```<code>const http = require('http');
const fs = require('fs');

http.createServer(function (request, response) {
    fs.readFile('index.html', function(error, content) {
        response.writeHead(200, { 'Content-Type': 'text/html' });
        response.end(content, 'utf-8');
    });
}).listen(58080, 'localhost');
</code>```

In one terminal:

```<code>node serve.js
</code>```

In another:

```<code>node test.js
</code>```

Output:

```<code>[puppeteer] Sleeping
Fetching page
Success
Done fetching page
[puppeteer] Closing
</code>```

I want puppeteer to wait for the point where "Done fetching page" is printed without a preset timeout. I control the source code to the page itself, so any ideas accepted, even those that require changes to the target server. For example, if I add a hidden DOM element after the end of the Ajax call, I can use await page.waitForSelector(cssSelector);. I'm wondering if there's a better way.

答:
I believe puppeteer has a load event you can hook into.

So something like this:

```<code>const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', consoleObj => console.log(consoleObj.text()));
  page.on('load', await () => { //set listener before you go to the page.
     // Now do something...
  });
  await page.goto('http://localhost:58080');
  // What to do to wait for the completion of the ajax call done after
  // document is ready?
  console.log('[puppeteer] Sleeping');
  await new Promise(resolve => setTimeout(resolve, 1000));
  console.log('[puppeteer] Closing');
  await browser.close();
});
</code>```

Body:
SOLUTION:

As per @pguardiario 's suggestion, the following intercepts the Ajax call and waits for its completion:

  await page.waitForResponse('http://localhost:58080/', {timeout: 2000})
    .catch(() => {console.log('[puppeteer] Error')});

I have a page which performs an Ajax call after the page has loaded and I need for puppeteer to wait for the completion of that call. In puppeteer : wait for ajax call after navigation the accepted answer uses await page.waitForSelector(cssSelector); which doesn't work in my current case since the success of the Ajax call doesn't add any new elements to the page. Here's a minimal working example with some comments as to what the actual page does:

index.html:

<!DOCTYPE html>

test.js:

const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', consoleObj => console.log(consoleObj.text()));
  await page.goto('http://localhost:58080');
  // What to do to wait for the completion of the ajax call done after
  // document is ready?
  console.log('[puppeteer] Sleeping');
  await new Promise(resolve => setTimeout(resolve, 1000));
  console.log('[puppeteer] Closing');
  await browser.close();
});

serve.js:

const http = require('http');
const fs = require('fs');

http.createServer(function (request, response) {
    fs.readFile('index.html', function(error, content) {
        response.writeHead(200, { 'Content-Type': 'text/html' });
        response.end(content, 'utf-8');
    });
}).listen(58080, 'localhost');

In one terminal:

node serve.js

In another:

node test.js

Output:

[puppeteer] Sleeping
Fetching page
Success
Done fetching page
[puppeteer] Closing

I want puppeteer to wait for the point where "Done fetching page" is printed without a preset timeout. I control the source code to the page itself, so any ideas accepted, even those that require changes to the target server. For example, if I add a hidden DOM element after the end of the Ajax call, I can use await page.waitForSelector(cssSelector);. I'm wondering if there's a better way.

Body:
I believe puppeteer has a load event you can hook into.

So something like this:

const puppeteer = require('puppeteer');

puppeteer.launch().then(async browser => {
  const page = await browser.newPage();
  page.on('console', consoleObj => console.log(consoleObj.text()));
  page.on('load', await () => { //set listener before you go to the page.
     // Now do something...
  });
  await page.goto('http://localhost:58080');
  // What to do to wait for the completion of the ajax call done after
  // document is ready?
  console.log('[puppeteer] Sleeping');
  await new Promise(resolve => setTimeout(resolve, 1000));
  console.log('[puppeteer] Closing');
  await browser.close();
});


问:
UIColor does not match standard RGB color wheel?
Hue in UIColor is not the same as a standard RGB color wheel. What I mean by that is, two opposing colors on a color wheel will match (i.e., yellow and purple), but if you take two opposing colors in UIColor, for example:

Color 1: Hue 0.45

Color 2: Hue 0.95

they don't match. Is there any way to find the opposite color in the spectrum through UIColor?

答:
Colors opposite each other on a wheel not usually called "matching", they are called "complementary", as in, if you mix them together, you get white (or black if you're dealing with subtractive colors, i.e., pigments).

RGB isn't really a color "wheel" -- it's more of a cube shape. The Hue in HSB, however, is often expressed as an angle, from 0˚ to 360˚, with red at 0˚, and turquoise at 180˚. If you take a value 180˚ from whatever you start with, you get the complement: Red 0˚/turquoise 180˚, green 120˚/purple 300˚, etc. When programming, the range of hue is usually written as a fraction between 0 and 1 inclusive. In that scheme, you can do

```<code>fmod(val - 0.5, 1.0)
</code>```

to get the complement.

You haven't said what result you're expecting and what result you're getting, so it's hard to be specifically helpful, but 0.95 and 0.45 are indeed complementary, and when I create UIColors with those values, I see the expected reddish and turquoise-ish hues.

The colors on a computer screen behave differently than the colors of paint, because in the first case, you are adding wavelengths of light to get a result, and in the second, you are selectively absorbing wavelengths. This may be the source of your confusion. Red plus yellow equals orange with pigments, but red plus green equals yellow with light.

ContentLicense: CC BY-SA 3.0

Body:
Colors opposite each other on a wheel not usually called "matching", they are called "complementary", as in, if you mix them together, you get white (or black if you're dealing with subtractive colors, i.e., pigments).

RGB isn't really a color "wheel" -- it's more of a cube shape. The Hue in HSB, however, is often expressed as an angle, from 0˚ to 360˚, with red at 0˚, and turquoise at 180˚. If you take a value 180˚ from whatever you start with, you get the complement: Red 0˚/turquoise 180˚, green 120˚/purple 300˚, etc. When programming, the range of hue is usually written as a fraction between 0 and 1 inclusive. In that scheme, you can do

fmod(val - 0.5, 1.0)

to get the complement.

You haven't said what result you're expecting and what result you're getting, so it's hard to be specifically helpful, but 0.95 and 0.45 are indeed complementary, and when I create UIColors with those values, I see the expected reddish and turquoise-ish hues.

The colors on a computer screen behave differently than the colors of paint, because in the first case, you are adding wavelengths of light to get a result, and in the second, you are selectively absorbing wavelengths. This may be the source of your confusion. Red plus yellow equals orange with pigments, but red plus green equals yellow with light.


问:
How to find ActiveDialog (waterfall-step) in context after replacedialog in waterfall dialog

Contextual help in prompts

I need to implement contextual help for a chatbot. My strategy is to use the active prompt as an index for a table with help-textlines. I am struggling with finding the active prompt after a stepContext.replaceDialog() in a waterfall dialog.

I will use the Compex Dialog sample as example.

In reviewSelectionDialog below is a prompt called CHOICE_PROMPT. This is the prompt in which I would like to add contextual help. If the user enters help, the helptext should be shown that is about that prompt.

In the same dialog is a loopstep. Based on a user decision, the dialog is repeated (looped) by the replaceDialog() method.

ReviewSelectionDialog is extended with CancelAndHelpDialog. As a result I am able to check for and act on any user interrupts like 'help'.

In CancelAndHelpDialog I need the active prompt when help was entered by the user so I am able to show relevant help. (CHOICE_PROMPT in this example).

My question

In the first pass of ReviewSelectionDialog, after sending 'help', I am able to get the active prompt in the CancelAndHelpDialog via innerDc.activeDialog.id. But after the stepContext.replaceDialog() in loopStep and sending 'help' again in the CHOICE_PROMPT, innerDc.activeDialog.id shows REVIEW_SELECTION_DIALOG. Where do I find the active prompt after a replace_dialog()?

ReviewSelectionDialog

```<code>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { ChoicePrompt, WaterfallDialog } = require('botbuilder-dialogs');

const REVIEW_SELECTION_DIALOG = 'REVIEW_SELECTION_DIALOG';
const { CancelAndHelpDialog } = require('./cancelAndHelpDialog');

const CHOICE_PROMPT = 'CHOICE_PROMPT';
const WATERFALL_DIALOG = 'WATERFALL_DIALOG';

class ReviewSelectionDialog extends CancelAndHelpDialog {
    constructor() {
        super(REVIEW_SELECTION_DIALOG);

        // Define a "done" response for the company selection prompt.
        this.doneOption = 'done';

        // Define value names for values tracked inside the dialogs.
        this.companiesSelected = 'value-companiesSelected';

        // Define the company choices for the company selection prompt.
        this.companyOptions = ['Adatum Corporation', 'Contoso Suites', 'Graphic Design Institute', 'Wide World Importers'];

        this.addDialog(new ChoicePrompt(CHOICE_PROMPT));
        this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
            this.selectionStep.bind(this),
            this.loopStep.bind(this)
        ]));

        this.initialDialogId = WATERFALL_DIALOG;
    }

    async selectionStep(stepContext) {
        // Continue using the same selection list, if any, from the previous iteration of this dialog.
        const list = Array.isArray(stepContext.options) ? stepContext.options : [];
        stepContext.values[this.companiesSelected] = list;

        // Create a prompt message.
        let message = '';
        if (list.length === 0) {
            message = `Please choose a company to review, or \`${ this.doneOption }\` to finish.`;
        } else {
            message = `You have selected **${ list[0] }**. You can review an additional company, or choose \`${ this.doneOption }\` to finish.`;
        }

        // Create the list of options to choose from.
        const options = list.length > 0
            ? this.companyOptions.filter(function(item) { return item !== list[0]; })
            : this.companyOptions.slice();
        options.push(this.doneOption);

        // Prompt the user for a choice.
        return await stepContext.prompt(CHOICE_PROMPT, {
            prompt: message,
            retryPrompt: 'Please choose an option from the list.',
            choices: options
        });
    }

    async loopStep(stepContext) {
        // Retrieve their selection list, the choice they made, and whether they chose to finish.
        const list = stepContext.values[this.companiesSelected];
        const choice = stepContext.result;
        const done = choice.value === this.doneOption;

        if (!done) {
            // If they chose a company, add it to the list.
            list.push(choice.value);
        }

        if (done || list.length > 1) {
            // If they're done, exit and return their list.
            return await stepContext.endDialog(list);
        } else {
            // Otherwise, repeat this dialog, passing in the list from this iteration.
            return await stepContext.replaceDialog(REVIEW_SELECTION_DIALOG, list);
        }
    }
}

module.exports.ReviewSelectionDialog = ReviewSelectionDialog;
module.exports.REVIEW_SELECTION_DIALOG = REVIEW_SELECTION_DIALOG;

</code>```

CancelAndHelpDialog

```<code>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { InputHints } = require('botbuilder');
const { ComponentDialog, DialogTurnStatus } = require('botbuilder-dialogs');

/**
 * This base class watches for common phrases like "help" and "cancel" and takes action on them
 * BEFORE they reach the normal bot logic.
 */
class CancelAndHelpDialog extends ComponentDialog {
    async onContinueDialog(innerDc) {
        const result = await this.interrupt(innerDc);
        if (result) {
            return result;
        }
        return await super.onContinueDialog(innerDc);
    }

    async interrupt(innerDc) {
        if (innerDc.context.activity.text) {
            const text = innerDc.context.activity.text.toLowerCase();

            switch (text) {
            case 'help':
            case '?': {
                const helpMessageText = 'Show help about prompt: ' + innerDc.activeDialog.id;
                await innerDc.context.sendActivity(helpMessageText, helpMessageText, InputHints.ExpectingInput);
                return { status: DialogTurnStatus.waiting };
            }
            case 'cancel':
            case 'quit': {
                const cancelMessageText = 'Cancelling...';
                await innerDc.context.sendActivity(cancelMessageText, cancelMessageText, InputHints.IgnoringInput);
                return await innerDc.cancelAllDialogs();
            }
            }
        }
    }
}

module.exports.CancelAndHelpDialog = CancelAndHelpDialog;

</code>```

答:
I want to thank you for using the sample code because you've actually revealed a bug that I've reported here: https://github.com/microsoft/BotBuilder-Samples/issues/2457

The underlying problem here is that the dialogs library has two ways of stacking dialogs. Ordinarily, one dialog gets stacked on top of another dialog like this:

```<code>[  CHOICE_PROMPT   ]
[ WATERFALL_DIALOG ]
</code>```

However, component dialogs form a nested dialog stack that stacks inward rather than further upward:

```<code>        [ REVIEW_SELECTION_DIALOG  ]
    [        TOP_LEVEL_DIALOG          ]
[               MAIN_DIALOG                ]
</code>```

Since not all dialogs are component dialogs, the two ways combine to look like this:

```<code>            [  CHOICE_PROMPT   ]
            [ WATERFALL_DIALOG ]
        [ REVIEW_SELECTION_DIALOG  ]
    [        TOP_LEVEL_DIALOG          ]
[               MAIN_DIALOG                ]
</code>```

I want to note that the order of this stack is not necessarily what you'd expect if you're used to writing hierarchical lists that look like this (with the most recently added item on the bottom):

MAIN_DIALOG

TOP_LEVEL_DIALOG

REVIEW_SELECTION_DIALOG

WATERFALL_DIALOG

CHOICE_PROMPT

Some people might not consider the second way of stacking actual stacking, since it's a parent-child relationship and not a stack. The reason I'm calling it a second way of stacking here is because of the conceptual similarity to a dialog stack. When you design your bot's dialogs, you have a choice about whether you want each new dialog to be added on top of the existing dialog stack or be nested as a child in an inner dialog stack. The two ways behave similarly because a component dialog ends when its last child dialog ends, so when you pop a dialog off of a stack the stack unravels outwards in much the same way as it unravels downwards. (Remember that new dialogs get added to the top of the stack so "downwards" here means from newer dialogs back to older dialogs, like the stack diagrams I started with.)

The "active dialog" is the dialog at the top of the stack. Since each component dialog has its own dialog set and dialog state and dialog stack and dialog context, each component dialog has a different idea of what the active dialog is. Because the active dialog is defined in terms of a specific dialog stack, when there are multiple dialog stacks the active dialog depends on who you ask.

This didn't cause a problem for you when you were looking for the active dialog in the innermost component dialog. But then you replaced that component dialog's child with the component dialog itself. After that, your (full) stack looked like this:

```<code>                [  CHOICE_PROMPT   ]
                [ WATERFALL_DIALOG ]
            [ REVIEW_SELECTION_DIALOG  ]
        [     REVIEW_SELECTION_DIALOG      ]
    [            TOP_LEVEL_DIALOG              ]
[                   MAIN_DIALOG                    ]
</code>```

When your CancelAndHelpDialog tried to access the active dialog of its inner dialog context, it correctly returned a ReviewSelectionDialog because that was the only dialog on its stack. You wanted to return the choice prompt but that choice prompt was in the dialog stack of the child ReviewSelectionDialog and not the parent ReviewSelectionDialog.

The bug is that you should be replacing the waterfall dialog with itself rather than with the parent component dialog. So it could look like this:

```<code>return await stepContext.replaceDialog(WATERFALL_DIALOG, list);
</code>```

Or like this:

```<code>return await stepContext.replaceDialog(this.initialDialogId, list);
</code>```

Ultimately, this still hasn't answered a question that you may have meant to ask. Since you've seen that problems can arise when you get the active dialog in an intermediate dialog context, you may want a way to get the "real" innermost active dialog. This can be accomplished with some simple recursion:

```<code>function getInnermostActiveDialog(dc) {
    const child = dc.child;
    return child ? getInnermostActiveDialog(child) : dc.activeDialog;
}
</code>```

Body:
Contextual help in prompts

I need to implement contextual help for a chatbot. My strategy is to use the active prompt as an index for a table with help-textlines. I am struggling with finding the active prompt after a stepContext.replaceDialog() in a waterfall dialog.

I will use the Compex Dialog sample as example.

In reviewSelectionDialog below is a prompt called CHOICE_PROMPT. This is the prompt in which I would like to add contextual help. If the user enters help, the helptext should be shown that is about that prompt.

In the same dialog is a loopstep. Based on a user decision, the dialog is repeated (looped) by the replaceDialog() method.

ReviewSelectionDialog is extended with CancelAndHelpDialog. As a result I am able to check for and act on any user interrupts like 'help'.

In CancelAndHelpDialog I need the active prompt when help was entered by the user so I am able to show relevant help. (CHOICE_PROMPT in this example).

My question

In the first pass of ReviewSelectionDialog, after sending 'help', I am able to get the active prompt in the CancelAndHelpDialog via innerDc.activeDialog.id. But after the stepContext.replaceDialog() in loopStep and sending 'help' again in the CHOICE_PROMPT, innerDc.activeDialog.id shows REVIEW_SELECTION_DIALOG. Where do I find the active prompt after a replace_dialog()?

ReviewSelectionDialog

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { ChoicePrompt, WaterfallDialog } = require('botbuilder-dialogs');

const REVIEW_SELECTION_DIALOG = 'REVIEW_SELECTION_DIALOG';
const { CancelAndHelpDialog } = require('./cancelAndHelpDialog');

const CHOICE_PROMPT = 'CHOICE_PROMPT';
const WATERFALL_DIALOG = 'WATERFALL_DIALOG';

class ReviewSelectionDialog extends CancelAndHelpDialog {
    constructor() {
        super(REVIEW_SELECTION_DIALOG);

        // Define a "done" response for the company selection prompt.
        this.doneOption = 'done';

        // Define value names for values tracked inside the dialogs.
        this.companiesSelected = 'value-companiesSelected';

        // Define the company choices for the company selection prompt.
        this.companyOptions = ['Adatum Corporation', 'Contoso Suites', 'Graphic Design Institute', 'Wide World Importers'];

        this.addDialog(new ChoicePrompt(CHOICE_PROMPT));
        this.addDialog(new WaterfallDialog(WATERFALL_DIALOG, [
            this.selectionStep.bind(this),
            this.loopStep.bind(this)
        ]));

        this.initialDialogId = WATERFALL_DIALOG;
    }

    async selectionStep(stepContext) {
        // Continue using the same selection list, if any, from the previous iteration of this dialog.
        const list = Array.isArray(stepContext.options) ? stepContext.options : [];
        stepContext.values[this.companiesSelected] = list;

        // Create a prompt message.
        let message = '';
        if (list.length === 0) {
            message = `Please choose a company to review, or \`${ this.doneOption }\` to finish.`;
        } else {
            message = `You have selected **${ list[0] }**. You can review an additional company, or choose \`${ this.doneOption }\` to finish.`;
        }

        // Create the list of options to choose from.
        const options = list.length > 0
            ? this.companyOptions.filter(function(item) { return item !== list[0]; })
            : this.companyOptions.slice();
        options.push(this.doneOption);

        // Prompt the user for a choice.
        return await stepContext.prompt(CHOICE_PROMPT, {
            prompt: message,
            retryPrompt: 'Please choose an option from the list.',
            choices: options
        });
    }

    async loopStep(stepContext) {
        // Retrieve their selection list, the choice they made, and whether they chose to finish.
        const list = stepContext.values[this.companiesSelected];
        const choice = stepContext.result;
        const done = choice.value === this.doneOption;

        if (!done) {
            // If they chose a company, add it to the list.
            list.push(choice.value);
        }

        if (done || list.length > 1) {
            // If they're done, exit and return their list.
            return await stepContext.endDialog(list);
        } else {
            // Otherwise, repeat this dialog, passing in the list from this iteration.
            return await stepContext.replaceDialog(REVIEW_SELECTION_DIALOG, list);
        }
    }
}

module.exports.ReviewSelectionDialog = ReviewSelectionDialog;
module.exports.REVIEW_SELECTION_DIALOG = REVIEW_SELECTION_DIALOG;

CancelAndHelpDialog

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

const { InputHints } = require('botbuilder');
const { ComponentDialog, DialogTurnStatus } = require('botbuilder-dialogs');

/**
 * This base class watches for common phrases like "help" and "cancel" and takes action on them
 * BEFORE they reach the normal bot logic.
 */
class CancelAndHelpDialog extends ComponentDialog {
    async onContinueDialog(innerDc) {
        const result = await this.interrupt(innerDc);
        if (result) {
            return result;
        }
        return await super.onContinueDialog(innerDc);
    }

    async interrupt(innerDc) {
        if (innerDc.context.activity.text) {
            const text = innerDc.context.activity.text.toLowerCase();

            switch (text) {
            case 'help':
            case '?': {
                const helpMessageText = 'Show help about prompt: ' + innerDc.activeDialog.id;
                await innerDc.context.sendActivity(helpMessageText, helpMessageText, InputHints.ExpectingInput);
                return { status: DialogTurnStatus.waiting };
            }
            case 'cancel':
            case 'quit': {
                const cancelMessageText = 'Cancelling...';
                await innerDc.context.sendActivity(cancelMessageText, cancelMessageText, InputHints.IgnoringInput);
                return await innerDc.cancelAllDialogs();
            }
            }
        }
    }
}

module.exports.CancelAndHelpDialog = CancelAndHelpDialog;

Body:
I want to thank you for using the sample code because you've actually revealed a bug that I've reported here: https://github.com/microsoft/BotBuilder-Samples/issues/2457

The underlying problem here is that the dialogs library has two ways of stacking dialogs. Ordinarily, one dialog gets stacked on top of another dialog like this:

[  CHOICE_PROMPT   ]
[ WATERFALL_DIALOG ]

However, component dialogs form a nested dialog stack that stacks inward rather than further upward:

        [ REVIEW_SELECTION_DIALOG  ]
    [        TOP_LEVEL_DIALOG          ]
[               MAIN_DIALOG                ]

Since not all dialogs are component dialogs, the two ways combine to look like this:

            [  CHOICE_PROMPT   ]
            [ WATERFALL_DIALOG ]
        [ REVIEW_SELECTION_DIALOG  ]
    [        TOP_LEVEL_DIALOG          ]
[               MAIN_DIALOG                ]

I want to note that the order of this stack is not necessarily what you'd expect if you're used to writing hierarchical lists that look like this (with the most recently added item on the bottom):

MAIN_DIALOG

TOP_LEVEL_DIALOG

REVIEW_SELECTION_DIALOG

WATERFALL_DIALOG

CHOICE_PROMPT

Some people might not consider the second way of stacking actual stacking, since it's a parent-child relationship and not a stack. The reason I'm calling it a second way of stacking here is because of the conceptual similarity to a dialog stack. When you design your bot's dialogs, you have a choice about whether you want each new dialog to be added on top of the existing dialog stack or be nested as a child in an inner dialog stack. The two ways behave similarly because a component dialog ends when its last child dialog ends, so when you pop a dialog off of a stack the stack unravels outwards in much the same way as it unravels downwards. (Remember that new dialogs get added to the top of the stack so "downwards" here means from newer dialogs back to older dialogs, like the stack diagrams I started with.)

The "active dialog" is the dialog at the top of the stack. Since each component dialog has its own dialog set and dialog state and dialog stack and dialog context, each component dialog has a different idea of what the active dialog is. Because the active dialog is defined in terms of a specific dialog stack, when there are multiple dialog stacks the active dialog depends on who you ask.

This didn't cause a problem for you when you were looking for the active dialog in the innermost component dialog. But then you replaced that component dialog's child with the component dialog itself. After that, your (full) stack looked like this:

                [  CHOICE_PROMPT   ]
                [ WATERFALL_DIALOG ]
            [ REVIEW_SELECTION_DIALOG  ]
        [     REVIEW_SELECTION_DIALOG      ]
    [            TOP_LEVEL_DIALOG              ]
[                   MAIN_DIALOG                    ]

When your CancelAndHelpDialog tried to access the active dialog of its inner dialog context, it correctly returned a ReviewSelectionDialog because that was the only dialog on its stack. You wanted to return the choice prompt but that choice prompt was in the dialog stack of the child ReviewSelectionDialog and not the parent ReviewSelectionDialog.

The bug is that you should be replacing the waterfall dialog with itself rather than with the parent component dialog. So it could look like this:

return await stepContext.replaceDialog(WATERFALL_DIALOG, list);

Or like this:

return await stepContext.replaceDialog(this.initialDialogId, list);

Ultimately, this still hasn't answered a question that you may have meant to ask. Since you've seen that problems can arise when you get the active dialog in an intermediate dialog context, you may want a way to get the "real" innermost active dialog. This can be accomplished with some simple recursion:

function getInnermostActiveDialog(dc) {
    const child = dc.child;
    return child ? getInnermostActiveDialog(child) : dc.activeDialog;
}


问:
How to crop a region selected with mouse click, using Python Image Library?
Is there a way to select a region in a image with mouse click and crop these region using python PIL ? How can i do it?

Thanks

答: I tried to make a little tool like this to run in the Jupyter ecosystem, so that you could crop the images and then use the cropped results later on in the same notebook. It's designed to work for many images, to let you crop each of them sequentially. Check it out and see if it works for you. Can install via pip install interactivecrop, but you'll want to check out the blog post for usage instructions.


问:
Right aligning using printf_P in C
I am attempting to get an output of:

```<code>Score:
    0
</code>```

but my output keeps coming out like

```<code>Score:        0
</code>```

this is what I have implemented:

```<code>move_cursor(30,4);
printf_P(PSTR("Score : %8d\n"), get_score());
move_cursor(37, 8);
</code>```

we are writing the score in Putty, from AVR to serial.
What am I doing wrong?

答:
Q: If you want "0" on a separate line ... then shouldn't you put a matching `\n' in your format statement?

Q: If  You want it right-aligned at column 6, then shouldn't your format statement be %6?

EXAMPLE: printf_P(PSTR("Score :\n%6d\n"), get_score());

PS:

As you're probably aware, "printf_P()" isn't standard C; it's AVR-specific.

Title: Right aligning using printf_P in C

Body:
I am attempting to get an output of:

Score:
    0

but my output keeps coming out like

Score:        0

this is what I have implemented:

move_cursor(30,4);
printf_P(PSTR("Score : %8d\n"), get_score());
move_cursor(37, 8);

we are writing the score in Putty, from AVR to serial.
What am I doing wrong?


答:
You probably want to aggregate the result by StudentID and use a LEFT JOIN, as in:

```<code>select
  a.StudentId,
  a.FirstName,
  a.Surname,
  a.Group,
  sum(b.TotalDuration) as total_duration
from table2 a
left join table1 b on b.StudentId = a.StudentId
group by a.StudentId
</code>```

Note that grouping by a.FirstName and a.Surname (assuming StudentId is the primary key) is optional according to the SQL Standard. I'm not sure SQL server will require it, though.

Title: How to combine two tables in SQL Server

Body:
You probably want to aggregate the result by StudentID and use a LEFT JOIN, as in:

select
  a.StudentId,
  a.FirstName,
  a.Surname,
  a.Group,
  sum(b.TotalDuration) as total_duration
from table2 a
left join table1 b on b.StudentId = a.StudentId
group by a.StudentId

Note that grouping by a.FirstName and a.Surname (assuming StudentId is the primary key) is optional according to the SQL Standard. I'm not sure SQL server will require it, though.


问:
How to avoid getting trapped in local minimum in 8-queens using min-conflicts heuristic
I have written the following code to solve the n-queens problem:

```<code>(defun solve (board max-steps)

    (enforce-one-queen-per-column board)

    (dotimes (step max-steps) ; repeat for a max amount of times,
        (if (eql (get-threatened-queens board) 0) ; if we have solved the board, return it
            (progn
                (format t "Solved!")
                (return board)
            )
        )

        (let ((threatened-queens (get-threatened-queens board)) ; get all threatened queens
              (queen nil))

             (setf queen (nth (random (length threatened-queens)) threatened-queens)) ; choose random threatened queen

             ; find which row in its column where it would be least threatened
             (let ((row-with-min-threats nil) ; (row_index, num_threats set to a high number)
                   (col (car queen))
                   (row (cdr queen)))

                  (format t "Dealing with threatened queen at (~A, ~A)...~%" col row)

                  (dotimes (i (array-dimension board 0)) ; for each row, find num of threats
                      (let ((num-threats (get-num-threats board col i)))
                           (print (car row-with-min-threats))
                           (format t "Checking (~A, ~A)~%" col i)
                           (format t "Threatened by ~A queens...~%" num-threats)

                            ; if row-with-min-threats has not yet been initialized
                           ; or if the row's threat is smaller than the tracked row with min threats

                            ; take first row as min threat so far
                            (if (eql row-with-min-threats nil) ;
                                (setf row-with-min-threats (cons i num-threats))
                                (if (< num-threats (cdr row-with-min-threats)) ; if not first row and current min threats is smaller than tracked min
                                    (setf row-with-min-threats (cons i num-threats))
                                    (if (and (eql num-threats (cdr row-with-min-threats))
                                             (eql (random 2) 1))                            ; if current cell's & min cell's threats are equal, we randomly decide which cell to assign
                                        (progn
                                            (format t "Randomly chose (~A, ~A)...~%" col i)
                                            (setf row-with-min-threats (cons i num-threats)))
                                        )

                                    )
                                )
                        )
                 )

                  (format t "Least threatened cell is (~A, ~A)...~%" col (car row-with-min-threats))

                  (if (not (eql row (car row-with-min-threats))) ; if its least threatened position isn't where it currently is
                      (progn
                          (setf (aref board (car row-with-min-threats) col) 1) ; move queen
                          (setf (aref board row col) 0)
                          (format t "Moved queen to (~A, ~A)...~%" col (car row-with-min-threats))
                      )
                  )

             )
        )
    )

    nil
)
</code>```

I'm trying to solve the 8-queens problem. The problem is in the solve function, but I'm not sure what I'm doing wrong. Since I am using the min-conflicts heuristic, I have a feeling that I am getting stuck in a local minima. I tried to overcome this by restarting the problem with the original board, but it doesn't seem to be working regardless of the amount of times I restart, since the queens are all stuck in the minimum conflicted spots, even though they still conflict. How can I improve solve to successfully place the 8 queens in cells where they do not threaten each other?

To run the program:

```<code>(setf board (make-board 8))
(solve board 10)
</code>```

where the 10 represents the amount of times solve gets recalled on the original board.

I did not include my functions as they are self-explanatory but if they will help, I will be happy to include them.

答:
I tried to overcome this by restarting the problem with the original board, but it doesn't seem to be working regardless of the amount of times I restart, since the queens are all stuck in the minimum conflicted spots, even though they still conflict

I believe that simply means the initial position given by you can't be 'repaired' at all by the heuristic. In that case, you need to a new 'seed', which you can get by randomly choosing a row in all 8 columns, and doing that (if it turns out it's a bad seed) until you get a good one.
Since the solution space increases asymptotically, in a n*n board there are increasingly more 'good' initial positions/seeds the higher 'n' is.

Here is a Java class with these considerations (mostly at the main and shuffle methods): https://github.com/danielbmancini/JHTP8_JCP8_Sol._Comentadas/blob/master/7/src/EightQueensHeuristic.java

I hope this can be helpful to you. If i am wrong in any way, criticism is welcome.

Body:
I have written the following code to solve the n-queens problem:

(defun solve (board max-steps)

    (enforce-one-queen-per-column board)

    (dotimes (step max-steps) ; repeat for a max amount of times,
        (if (eql (get-threatened-queens board) 0) ; if we have solved the board, return it
            (progn
                (format t "Solved!")
                (return board)
            )
        )

        (let ((threatened-queens (get-threatened-queens board)) ; get all threatened queens
              (queen nil))

             (setf queen (nth (random (length threatened-queens)) threatened-queens)) ; choose random threatened queen

             ; find which row in its column where it would be least threatened
             (let ((row-with-min-threats nil) ; (row_index, num_threats set to a high number)
                   (col (car queen))
                   (row (cdr queen)))

                  (format t "Dealing with threatened queen at (~A, ~A)...~%" col row)

                  (dotimes (i (array-dimension board 0)) ; for each row, find num of threats
                      (let ((num-threats (get-num-threats board col i)))
                           (print (car row-with-min-threats))
                           (format t "Checking (~A, ~A)~%" col i)
                           (format t "Threatened by ~A queens...~%" num-threats)

                            ; if row-with-min-threats has not yet been initialized
                           ; or if the row's threat is smaller than the tracked row with min threats

                            ; take first row as min threat so far
                            (if (eql row-with-min-threats nil) ;
                                (setf row-with-min-threats (cons i num-threats))
                                (if (< num-threats (cdr row-with-min-threats)) ; if not first row and current min threats is smaller than tracked min
                                    (setf row-with-min-threats (cons i num-threats))
                                    (if (and (eql num-threats (cdr row-with-min-threats))
                                             (eql (random 2) 1))                            ; if current cell's & min cell's threats are equal, we randomly decide which cell to assign
                                        (progn
                                            (format t "Randomly chose (~A, ~A)...~%" col i)
                                            (setf row-with-min-threats (cons i num-threats)))
                                        )

                                    )
                                )
                        )
                 )

                  (format t "Least threatened cell is (~A, ~A)...~%" col (car row-with-min-threats))

                  (if (not (eql row (car row-with-min-threats))) ; if its least threatened position isn't where it currently is
                      (progn
                          (setf (aref board (car row-with-min-threats) col) 1) ; move queen
                          (setf (aref board row col) 0)
                          (format t "Moved queen to (~A, ~A)...~%" col (car row-with-min-threats))
                      )
                  )

             )
        )
    )

    nil
)

I'm trying to solve the 8-queens problem. The problem is in the solve function, but I'm not sure what I'm doing wrong. Since I am using the min-conflicts heuristic, I have a feeling that I am getting stuck in a local minima. I tried to overcome this by restarting the problem with the original board, but it doesn't seem to be working regardless of the amount of times I restart, since the queens are all stuck in the minimum conflicted spots, even though they still conflict. How can I improve solve to successfully place the 8 queens in cells where they do not threaten each other?

To run the program:

(setf board (make-board 8))
(solve board 10)

where the 10 represents the amount of times solve gets recalled on the original board.

I did not include my functions as they are self-explanatory but if they will help, I will be happy to include them.


问:
I tried to send a python request to a proxy but it failed
I tried to send a python request to a proxy but it failed. What did I do wrong?

Here's the code:

```<code>import requests
url = 'https://httpbin.org/ip'

proxies = {
    "http": 'http://103.250.153.242',
    "https": 'http://103.250.153.242'
}

response = requests.get(url,proxies=proxies)
print(response.json())
</code>```

The result should have returned {'origin': '103.250.153.242'} but instead I got this:

```<code>Traceback (most recent call last):
  File "C:\Python37\lib\site-packages\urllib3\connection.py", line 160, in _new_conn
    (self._dns_host, self.port), self.timeout, **extra_kw)
  File "C:\Python37\lib\site-packages\urllib3\util\connection.py", line 80, in create_connection
    raise err
  File "C:\Python37\lib\site-packages\urllib3\util\connection.py", line 70, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
</code>```

How do I fix this?

答:
```<code>import urllib
import requests

r = requests.get('http://google.com', proxies=urllib.request.getproxies())
</code>```

But if you have proxies list:

```<code>from urllib3 import ProxyManager, make_headers

default_headers = make_headers(proxy_basic_auth='myusername:mypassword')
http = ProxyManager("https://myproxy.com:8080/", headers=default_headers)

# Now you can use `http` as you would a normal PoolManager
r = http.request('GET', 'https://stackoverflow.com/')
</code>```

Or:

```<code>import requests
proxies = {
    'http': 'http://proxy.server:port',
    'https': 'http://proxyserver:port',
}
s = requests.Session()
s.proxies = proxies
r = s.get('https://api.ipify.org?format=json').json()
</code>```

Body:
I tried to send a python request to a proxy but it failed. What did I do wrong?

Here's the code:

import requests
url = 'https://httpbin.org/ip'

proxies = {
    "http": 'http://103.250.153.242',
    "https": 'http://103.250.153.242'
}

response = requests.get(url,proxies=proxies)
print(response.json())

The result should have returned {'origin': '103.250.153.242'} but instead I got this:

Traceback (most recent call last):
  File "C:\Python37\lib\site-packages\urllib3\connection.py", line 160, in _new_conn
    (self._dns_host, self.port), self.timeout, **extra_kw)
  File "C:\Python37\lib\site-packages\urllib3\util\connection.py", line 80, in create_connection
    raise err
  File "C:\Python37\lib\site-packages\urllib3\util\connection.py", line 70, in create_connection
    sock.connect(sa)
TimeoutError: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

How do I fix this?

Body:
import urllib
import requests

r = requests.get('http://google.com', proxies=urllib.request.getproxies())

But if you have proxies list:

from urllib3 import ProxyManager, make_headers

default_headers = make_headers(proxy_basic_auth='myusername:mypassword')
http = ProxyManager("https://myproxy.com:8080/", headers=default_headers)

# Now you can use `http` as you would a normal PoolManager
r = http.request('GET', 'https://stackoverflow.com/')

Or:

import requests
proxies = {
    'http': 'http://proxy.server:port',
    'https': 'http://proxyserver:port',
}
s = requests.Session()
s.proxies = proxies
r = s.get('https://api.ipify.org?format=json').json()


问:
Is there a way to Enter large number of data into Firebase Firestore DataBase
I am trying to enter large number of data (13 Million rows) into Firebase Firestore, but it is taking forever to finish.

Currently,I am Inserting the data row by row using python, I tried to use multi-treading, but it is still very slow and it is not efficient (I have to stay connected into the Internet)

so, is there another way to insert a file into Firebase (a more efficient way to (batch) insert the data)?

This is the data format

```<code>[
{
    '010045006031': {
                        'FName':'Ahmed',
                        'LName':'Aline'
                    }
},
{
    '010045006031': {
                        'FName':'Ali',
                        'LName':'Adel'
                    }
},
{
    '010045006031': {
                        'FName':'Osama',
                        'LName':'Luay'
                    }
}
</code>```

]

This is the code that I am using

```<code>import firebase_admin
from firebase_admin import credentials, firestore

def Insert2DB(I):
     doc_ref = db.collection('DBCoolect').document(I['M'])
     doc_ref.set({"FirstName": I['FName'], "LastName": I['LName']}

cred = credentials.Certificate("ServiceAccountKey.json")

firebase_admin.initialize_app(cred)

db = firestore.client()

List = []
#List are read from File
List.append({'M': random(),'FName':'Ahmed','LName':'Aline'})
List.append({'M': random(),'FName':'Ali','LName':'Adel'})
List.append({'M': random(),'FName':'Osama','LName':'Luay'})

for item in List:
    Insert2DB(item)
</code>```

Thanks a lot ...

答:
Firestore does not offer any way to "bulk update" documents.  They have to be added individually.  There is a facility to batch write, but that's limited to 500 documents per batch, and that's not likely to speed up your process by a large amount.

If you want to optimize the rate at which documents can be added, I suggest reading the documentation on best practices for read and write operations and designing for scale.  All things considered, however, there is really no "fast" way to get 13 million documents into Firestore.  You're going to be writing code to add each one individually.  Firestore is not optimized for fast writes.  It's optimized for fast reads.

Body:
I am trying to enter large number of data (13 Million rows) into Firebase Firestore, but it is taking forever to finish.

Currently,I am Inserting the data row by row using python, I tried to use multi-treading, but it is still very slow and it is not efficient (I have to stay connected into the Internet)

so, is there another way to insert a file into Firebase (a more efficient way to (batch) insert the data)?

This is the data format

[
{
    '010045006031': {
                        'FName':'Ahmed',
                        'LName':'Aline'
                    }
},
{
    '010045006031': {
                        'FName':'Ali',
                        'LName':'Adel'
                    }
},
{
    '010045006031': {
                        'FName':'Osama',
                        'LName':'Luay'
                    }
}

]

This is the code that I am using

import firebase_admin
from firebase_admin import credentials, firestore

def Insert2DB(I):
     doc_ref = db.collection('DBCoolect').document(I['M'])
     doc_ref.set({"FirstName": I['FName'], "LastName": I['LName']}

cred = credentials.Certificate("ServiceAccountKey.json")

firebase_admin.initialize_app(cred)

db = firestore.client()

List = []
#List are read from File
List.append({'M': random(),'FName':'Ahmed','LName':'Aline'})
List.append({'M': random(),'FName':'Ali','LName':'Adel'})
List.append({'M': random(),'FName':'Osama','LName':'Luay'})

for item in List:
    Insert2DB(item)

Thanks a lot ...


问:
How do I split text file without delimiter into a list of dictionaries in python3?
I have a text file that has data in the following shape:

```<code>{"id": 1, {"device_data": 123}, "created_at": "2020-04-03"}{"id": 2, {"device_data": 123}, "created_at": '2020-04-03'}{"id": 2, {"device_data": 123}, "created_at": "2020-04-03"}{"id": 2, {"device_data": 123}, "created_at": '2020-04-03'}
</code>```

There aren't any \n delimiters or , delimiters that I can use here. I'd like to parse this into a list of dictionaries in order to load the data into a dataframe.

I've tried parsing this using .split() and list comprehension doing something like this:

```<code>lst = [x + '}' for x in data.split('}') if x != '']

</code>```

But this obviously breaks for records that have nested objects.

I also tried doing this with regex but I'm struggling to figure out the appropriate way.  This is what I have so far:

```<code>re.split('(\{(.*)\})', data)
</code>```

Per the suggestions below, I also attempted making use of the json library.

```<code>with open('path/to/file', 'r') as f:
    res = json.load(f)
</code>```

However, this resulted in an error with the following message: JSONDecodeError: Extra data. I believe this is due to the fact that there are multiple valid jsons in this file.

I wanted to use the json.load() command with a for loop, but then I ran into trouble figuring out how to properly split the file contents.

Does anyone have a suggestion for how to approach this kind of problem?

答:
Regex does not handle nested formats like this effectively.

This looks a bit like JSON, and Python has the builtin json package, which could help. To use it on this data, you'll need to first convert single quotes to double quotes: data_string.replace("'", '"'). But the format is probably still different enough from JSON to be a problem.

If you know what generated the data, that may help you figure out what will parse the data. Otherwise, this answer explains how to parse nested expressions manually.

Body:
I have a text file that has data in the following shape:

{"id": 1, {"device_data": 123}, "created_at": "2020-04-03"}{"id": 2, {"device_data": 123}, "created_at": '2020-04-03'}{"id": 2, {"device_data": 123}, "created_at": "2020-04-03"}{"id": 2, {"device_data": 123}, "created_at": '2020-04-03'}

There aren't any \n delimiters or , delimiters that I can use here. I'd like to parse this into a list of dictionaries in order to load the data into a dataframe.

I've tried parsing this using .split() and list comprehension doing something like this:

lst = [x + '}' for x in data.split('}') if x != '']

But this obviously breaks for records that have nested objects.

I also tried doing this with regex but I'm struggling to figure out the appropriate way.  This is what I have so far:

re.split('(\{(.*)\})', data)

Per the suggestions below, I also attempted making use of the json library.

with open('path/to/file', 'r') as f:
    res = json.load(f)

However, this resulted in an error with the following message: JSONDecodeError: Extra data. I believe this is due to the fact that there are multiple valid jsons in this file.

I wanted to use the json.load() command with a for loop, but then I ran into trouble figuring out how to properly split the file contents.

Does anyone have a suggestion for how to approach this kind of problem?


问:
How to pass external configuration file to pyspark(Spark 2.x) program?
When I am running pyspark program interactive shell able to fetch the configuration file(config.ini) inside pyspark script,
But when I am trying to run same script using Spark submit command with master yarn and cluster deployment mode is cluster it giving me error as config file not exists, I have checked yarn log and able to see same, below is command for running the pyspark job.</p>

```<code>spark2-submit --master yarn --deploy-mode cluster test.py /home/sys_user/ask/conf/config.ini
</code>```

答:
Pass the ini file in spark.files parameter

```<code>.config('spark.files', 'config/local/config.ini') \
</code>```

Read in pyspark:

```<code>with open(SparkFiles.get('config.ini')) as config_file:
    print(config_file.read())
</code>```

It works for me.

Body:
When I am running pyspark program interactive shell able to fetch the configuration file(config.ini) inside pyspark script,
But when I am trying to run same script using Spark submit command with master yarn and cluster deployment mode is cluster it giving me error as config file not exists, I have checked yarn log and able to see same, below is command for running the pyspark job.

spark2-submit --master yarn --deploy-mode cluster test.py /home/sys_user/ask/conf/config.ini

Body:
Pass the ini file in spark.files parameter

.config('spark.files', 'config/local/config.ini') \

Read in pyspark:

with open(SparkFiles.get('config.ini')) as config_file:
    print(config_file.read())

It works for me.


问:
How to verify that proper promises were created in Rust smart contract tests?
Working with the linkdrop contract here: https://github.com/nearprotocol/near-linkdrop/blob/master/src/lib.rs

I'm writing a new method to deploy a contract with a limited access key. I would like to check my promise was created successfully and found this comment in other tests:

```<code>// TODO: verify that promise was created with funds for given username.
</code>```

How would I verify that my promise is being created correctly. The test passes with no errors/panic, but is that all that can be done prior to testing with near-shell?

Working out of this branch on my own fork here: https://github.com/mattlockyer/near-linkdrop/tree/deploy-contract

Here is my new method:

```<code>/// Create and fund new account with limited access key to contract methods.
pub fn create_limited_contract_account(
    &mut self,
    new_account_id: AccountId,
    new_public_key: Base58PublicKey,
    allowance: u128,
    contract_bytes: Vec<u8>,
    method_names: Vec<u8>,
) -> Promise {
    assert_eq!(
        env::predecessor_account_id(),
        env::current_account_id(),
        "Create account and claim only can come from this account"
    );
    assert!(
        env::is_valid_account_id(new_account_id.as_bytes()),
        "Invalid account id"
    );
    let amount = self
        .accounts
        .remove(&env::signer_account_pk())
        .expect("Unexpected public key");

    Promise::new(new_account_id.clone())
        .create_account()
        .transfer(amount)
        .deploy_contract(contract_bytes)
        .add_access_key(
            new_public_key.into(),
            allowance,
            new_account_id,
            method_names
        ).then(
            ext_self::on_account_created_and_claimed(
            amount.into(),
            &env::current_account_id(),
            NO_DEPOSIT,
            ON_CREATE_ACCOUNT_CALLBACK_GAS,
        ))
}
</code>```

And here is my test:

```<code>#[test]
fn test_create_limited_contract_account() {
    let mut contract = LinkDrop::default();
    let pk: Base58PublicKey = "qSq3LoufLvTCTNGC3LJePMDGrok8dHMQ5A1YD9psbiz"
        .try_into()
        .unwrap();
    // Deposit money to linkdrop contract.
    let deposit = ACCESS_KEY_ALLOWANCE * 100;
    testing_env!(VMContextBuilder::new()
        .current_account_id(linkdrop())
        .attached_deposit(deposit)
        .finish());
    contract.send(pk.clone());
    // Now, send new transaction to link drop contract.
    let context = VMContextBuilder::new()
        .current_account_id(linkdrop())
        .predecessor_account_id(linkdrop())
        .signer_account_pk(pk.into())
        .account_balance(deposit)
        .finish();
    testing_env!(context);
    let pk2 = "2S87aQ1PM9o6eBcEXnTR5yBAVRTiNmvj8J8ngZ6FzSca"
        .try_into()
        .unwrap();
    let contract_bytes = include_bytes!("../res/multisig.wasm").to_vec();
    let method_names = "multisig_method_a,multisig_method_b".as_bytes().to_vec();

    contract.create_limited_contract_account(
        bob(),
        pk2,
        LIMITED_ACCESS_KEY_ALLOWANCE,
        contract_bytes,
        method_names
    );
}
</code>```

答:
This is a hard problem currently.  However, the best way to test this currently (and it's a work in progress) is the standalone runtime, which allows you to create a mock runtime that can process transactions.  For example you can create a transaction that calls a function that makes a promise call and then can process just that transaction or all of the subsequent receipts that it generates.

Here is an example of its usage: Here, but also look at the utils for how to set it up.

Body:
Working with the linkdrop contract here: https://github.com/nearprotocol/near-linkdrop/blob/master/src/lib.rs

I'm writing a new method to deploy a contract with a limited access key. I would like to check my promise was created successfully and found this comment in other tests:

// TODO: verify that promise was created with funds for given username.

How would I verify that my promise is being created correctly. The test passes with no errors/panic, but is that all that can be done prior to testing with near-shell?

Working out of this branch on my own fork here: https://github.com/mattlockyer/near-linkdrop/tree/deploy-contract

Here is my new method:

/// Create and fund new account with limited access key to contract methods.
pub fn create_limited_contract_account(
    &mut self,
    new_account_id: AccountId,
    new_public_key: Base58PublicKey,
    allowance: u128,
    contract_bytes: Vec<u8>,
    method_names: Vec<u8>,
) -> Promise {
    assert_eq!(
        env::predecessor_account_id(),
        env::current_account_id(),
        "Create account and claim only can come from this account"
    );
    assert!(
        env::is_valid_account_id(new_account_id.as_bytes()),
        "Invalid account id"
    );
    let amount = self
        .accounts
        .remove(&env::signer_account_pk())
        .expect("Unexpected public key");

    Promise::new(new_account_id.clone())
        .create_account()
        .transfer(amount)
        .deploy_contract(contract_bytes)
        .add_access_key(
            new_public_key.into(),
            allowance,
            new_account_id,
            method_names
        ).then(
            ext_self::on_account_created_and_claimed(
            amount.into(),
            &env::current_account_id(),
            NO_DEPOSIT,
            ON_CREATE_ACCOUNT_CALLBACK_GAS,
        ))
}

And here is my test:

#[test]
fn test_create_limited_contract_account() {
    let mut contract = LinkDrop::default();
    let pk: Base58PublicKey = "qSq3LoufLvTCTNGC3LJePMDGrok8dHMQ5A1YD9psbiz"
        .try_into()
        .unwrap();
    // Deposit money to linkdrop contract.
    let deposit = ACCESS_KEY_ALLOWANCE * 100;
    testing_env!(VMContextBuilder::new()
        .current_account_id(linkdrop())
        .attached_deposit(deposit)
        .finish());
    contract.send(pk.clone());
    // Now, send new transaction to link drop contract.
    let context = VMContextBuilder::new()
        .current_account_id(linkdrop())
        .predecessor_account_id(linkdrop())
        .signer_account_pk(pk.into())
        .account_balance(deposit)
        .finish();
    testing_env!(context);
    let pk2 = "2S87aQ1PM9o6eBcEXnTR5yBAVRTiNmvj8J8ngZ6FzSca"
        .try_into()
        .unwrap();
    let contract_bytes = include_bytes!("../res/multisig.wasm").to_vec();
    let method_names = "multisig_method_a,multisig_method_b".as_bytes().to_vec();

    contract.create_limited_contract_account(
        bob(),
        pk2,
        LIMITED_ACCESS_KEY_ALLOWANCE,
        contract_bytes,
        method_names
    );
}


问:
How do I make my git history more coherent?
I have to use an 3rd party API for development. I write code upload to git, download the code onto the 3rd party interface and then execute the code from the API. This means a very large number of git commits. I have been trying to make my commit history more coherent so that when the module is ready I show all the changes made in the code along the way. Should I be amending each one of my debugging commits? I'm using visual studio if that helps.</p>

答:
In general, if you have a large number of debugging commits, those don't make for a good history.  What can be useful is to either amend your commits with git commit --amend, as you suggested, or to squash them together using an interactive rebase.

The way you perform such a squash is to run git rebase -i BASE, where BASE is the commit before the ones you want to squash together.  You'll then get a list of commits like this:

```<code>pick 92a28ece5a commit 1
pick 5878fe6a98 commit 2
pick 402864eaa3 commit 3
pick d124692e2f commit 4
</code>```

You change the pick lines to fixup on all the commits but the first one, save and quit your editor, and they'll all be combined into one.  If you use squash instead of fixup, Git will prompt you to merge the commit messages of the commits instead of discarding them.

There's an even easier way to do this, and that's to use git commit --fixup COMMIT or git commit --squash COMMIT, which create fixup or squash commits against the given commit (which in this case, would probably be commit 1).  You can then run git rebase -i --autosquash BASE and Git will automatically mark those commits as squash or fixup commits and move them into the right place.

Ideally each commit is a independent logical change where all the tests pass.  You can use fixup or squash commits to make changes to older commits in your branch and then squash them together at the end.  The final product will look like you never made a mistake in your series at all and wrote perfect code to begin with.

You'll also probably want to have decent commit messages, for which the Git documentation is helpful.  Describing your changes well is helpful for other developers as well as future you.  I've often found myself questioning why I made a certain change six months after the fact, and at that point the work I've done by writing a good commit message pays off immensely.

If you're looking for examples, Git and Linux have these kinds of practices and are generally great examples of this kind of approach.

Body:
In general, if you have a large number of debugging commits, those don't make for a good history.  What can be useful is to either amend your commits with git commit --amend, as you suggested, or to squash them together using an interactive rebase.

The way you perform such a squash is to run git rebase -i BASE, where BASE is the commit before the ones you want to squash together.  You'll then get a list of commits like this:

pick 92a28ece5a commit 1
pick 5878fe6a98 commit 2
pick 402864eaa3 commit 3
pick d124692e2f commit 4

You change the pick lines to fixup on all the commits but the first one, save and quit your editor, and they'll all be combined into one.  If you use squash instead of fixup, Git will prompt you to merge the commit messages of the commits instead of discarding them.

There's an even easier way to do this, and that's to use git commit --fixup COMMIT or git commit --squash COMMIT, which create fixup or squash commits against the given commit (which in this case, would probably be commit 1).  You can then run git rebase -i --autosquash BASE and Git will automatically mark those commits as squash or fixup commits and move them into the right place.

Ideally each commit is a independent logical change where all the tests pass.  You can use fixup or squash commits to make changes to older commits in your branch and then squash them together at the end.  The final product will look like you never made a mistake in your series at all and wrote perfect code to begin with.

You'll also probably want to have decent commit messages, for which the Git documentation is helpful.  Describing your changes well is helpful for other developers as well as future you.  I've often found myself questioning why I made a certain change six months after the fact, and at that point the work I've done by writing a good commit message pays off immensely.

If you're looking for examples, Git and Linux have these kinds of practices and are generally great examples of this kind of approach.


问:
Putting several plots side by side
I have 9 histograms made with matplotlib.pyplot.

Is there an easy way to "stick" them to each other, so that every new histogram would not start with a new row?

Data: data

Providing code:

```<code>for column in data:
   plt.figure(figsize=(5,5))

   a1 = data[(data['Outcome'] == 0)][column]
   a2 = data[(data['Outcome'] == 1)][column]

   ax = np.linspace(0, data[column].max(), 50)

   plt.hist(a1, ax, color='blue', alpha=0.6, label='Have Diabetes = NO')
   plt.hist(a2, ax, color='yellow', alpha=0.6, label='Have Diabetes = YES')

   plt.title(f'Histogram for {column}')
   plt.xlabel(f'{column}')
   plt.ylabel('number of people')

   plt.grid(True)
   leg = plt.legend(loc='upper right', frameon=True)
</code>```

What I want is something like this:

I actually don't need it to be 3x3, just not go in a column. Is it possible? Thanks for any possible help.

答:
You need to assign the plots to ax , and also it will be set_title etc:

```<code>import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
data = pd.read_csv("datasets_228_482_diabetes.csv")

fig,ax = plt.subplots(3,3,figsize=(9,9))
ax = ax.flatten()

for i,column in enumerate(data.columns):
    a1 = data[(data['Outcome'] == 0)][column]
    a2 = data[(data['Outcome'] == 1)][column]

    ax[i].hist(a1, color='blue', alpha=0.6, label='Have Diabetes = NO')
    ax[i].hist(a2, color='yellow', alpha=0.6, label='Have Diabetes = YES')

    ax[i].set_title('Histogram for '+column)
    ax[i].set_xlabel(f'{column}')
    ax[i].set_ylabel('number of people')

    ax[i].legend(loc='upper right',frameon=True,markerscale=7,fontsize=7)

fig.tight_layout()
</code>```

As you can see, the last column outcome is pretty useless, so if you don't plot that, you can also consider using seaborn:

```<code>g = sns.FacetGrid(data=data.melt(id_vars="Outcome"),
                  col="variable",hue="Outcome",sharex=False,sharey=False,
                  col_wrap=4,palette=['blue','yellow'])
g = g.map(plt.hist,"value",alpha=0.7)
</code>```

Title: Putting several plots side by side

Body:
I have 9 histograms made with matplotlib.pyplot.

Is there an easy way to "stick" them to each other, so that every new histogram would not start with a new row?

Data: data

Providing code:

for column in data:
   plt.figure(figsize=(5,5))

   a1 = data[(data['Outcome'] == 0)][column]
   a2 = data[(data['Outcome'] == 1)][column]

   ax = np.linspace(0, data[column].max(), 50)

   plt.hist(a1, ax, color='blue', alpha=0.6, label='Have Diabetes = NO')
   plt.hist(a2, ax, color='yellow', alpha=0.6, label='Have Diabetes = YES')

   plt.title(f'Histogram for {column}')
   plt.xlabel(f'{column}')
   plt.ylabel('number of people')

   plt.grid(True)
   leg = plt.legend(loc='upper right', frameon=True)

What I want is something like this:

I actually don't need it to be 3x3, just not go in a column. Is it possible? Thanks for any possible help.

Body:
You need to assign the plots to ax , and also it will be set_title etc:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
data = pd.read_csv("datasets_228_482_diabetes.csv")

fig,ax = plt.subplots(3,3,figsize=(9,9))
ax = ax.flatten()

for i,column in enumerate(data.columns):
    a1 = data[(data['Outcome'] == 0)][column]
    a2 = data[(data['Outcome'] == 1)][column]

    ax[i].hist(a1, color='blue', alpha=0.6, label='Have Diabetes = NO')
    ax[i].hist(a2, color='yellow', alpha=0.6, label='Have Diabetes = YES')

    ax[i].set_title('Histogram for '+column)
    ax[i].set_xlabel(f'{column}')
    ax[i].set_ylabel('number of people')

    ax[i].legend(loc='upper right',frameon=True,markerscale=7,fontsize=7)

fig.tight_layout()

As you can see, the last column outcome is pretty useless, so if you don't plot that, you can also consider using seaborn:

g = sns.FacetGrid(data=data.melt(id_vars="Outcome"),
                  col="variable",hue="Outcome",sharex=False,sharey=False,
                  col_wrap=4,palette=['blue','yellow'])
g = g.map(plt.hist,"value",alpha=0.7)