问:
Can this Entity Framework Query be improved for performance?
* UPDATE *

I am unable to delete this question even though it was actually not a problem in the long run... I still had some code from when I was working on it that did separate queries and populated some of these fields... when I stripped out that code... the following query runs very fast (2 seconds):

```<code>public IQueryable<ApplicationUser> QueriableUsersList()
{
    return _context.Users.OrderBy(u => u.UserName)
        .Include(u => u.Accounts.Select(a => a.Broker))
        .Include(u => u.Roles);
}
</code>```

* ORIGINAL QUESTION *

I am trying to load a list of users (about 600 of them) using Entity Framework… I want to preload with the query account records for each user and a broker record for each account (along with roles for each user)… this SQL gets me results very quickly ( < 1 second):

```<code>select ISNULL(ur.RoleId, 0) as IsAdmin, u.*, a.*, b.*
  from AspNetUsers u
 inner join Accounts a on u.Id = a.ClientId
 inner join Brokers b on a.Brokerid = b.BrokerId
 left outer join AspNetUserRoles ur on u.id = ur.UserId and ur.RoleId = 1
order by u.UserName
</code>```

But this Entity Framework query takes a long time (something like 20 - 25 seconds)... especially in production where the database is on a different server:

```<code>public IQueryable<ApplicationUser> QueriableUsersList()
{
    return _context.Users.OrderBy(u => u.UserName)
        .Include(u => u.Accounts.Select(a => a.Broker))
        .Include(u => u.Roles);
}
</code>```

Any thoughts on how the Entity Framework query could be improved and/or what it would take to get it to be faster like the native SQL query is?. (Note: I do need all the data from all the above object for my list so lazy loading isn’t going to help.) I was hoping it would generate a single query along the lines of what I show above… but it is generating several queries (below) for each user it seems.

I eventually want to use this IQueryable to get paginated data as well.

My objects are defined like this:

```<code>public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>/
{
    public List<Account> Accounts { get; set; }
…
    public bool isAdmin { get {  return this.Roles != null && this.Roles.Any(r => r.RoleId == 1); } }
…
}

public class Account
{
    public int AccountId { get; set; }
…
    public int BrokerId { get; set; }
    public virtual Broker Broker { get; set; }
…
}

public class Broker
{
    public int BrokerId { get; set; }
    public string Name { get; set; }
…
}
</code>```

With the entity framework query using SQL Server profiler I see one of these:

```<code>SELECT
[Project1].[Id] AS [Id],
[Project1].[UserName] AS [UserName],
[Project1].[FirstName] AS [FirstName],
[Project1].[LastName] AS [LastName],
[Project1].[PhoneNumber] AS [PhoneNumber],
[Project1].[Email] AS [Email],
[Project1].[Address] AS [Address],
[Project1].[City] AS [City],
[Project1].[State] AS [State],
[Project1].[Zip] AS [Zip],
[Project1].[DateAdded] AS [DateAdded],
[Project1].[IsActive] AS [IsActive],
[Project1].[C1] AS [C1],
[Project1].[AccountId] AS [AccountId],
[Project1].[ClientId] AS [ClientId],
[Project1].[BrokerId] AS [BrokerId],
[Project1].[AccountNumber] AS [AccountNumber],
[Project1].[BrokerUserName] AS [BrokerUserName],
[Project1].[BrokerPasswordHash] AS [BrokerPasswordHash],
[Project1].[EquityCurve] AS [EquityCurve],
[Project1].[CapitalInvested] AS [CapitalInvested],
[Project1].[IsSimulated] AS [IsSimulated],
[Project1].[ClosedProfit] AS [ClosedProfit],
[Project1].[MarketValueTimeStamp] AS [MarketValueTimeStamp],
[Project1].[IsAuthorizedForLiveTrading] AS [IsAuthorizedForLiveTrading],
[Project1].[ActivatedOn] AS [ActivatedOn]
FROM ( SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[FirstName] AS [FirstName],
    [Extent1].[LastName] AS [LastName],
    [Extent1].[Address] AS [Address],
    [Extent1].[Zip] AS [Zip],
    [Extent1].[City] AS [City],
    [Extent1].[State] AS [State],
    [Extent1].[DateAdded] AS [DateAdded],
    [Extent1].[IsActive] AS [IsActive],
    [Extent1].[Email] AS [Email],
    [Extent1].[PhoneNumber] AS [PhoneNumber],
    [Extent1].[UserName] AS [UserName],
    [Extent2].[AccountId] AS [AccountId],
    [Extent2].[ClientId] AS [ClientId],
    [Extent2].[BrokerId] AS [BrokerId],
    [Extent2].[AccountNumber] AS [AccountNumber],
    [Extent2].[BrokerUserName] AS [BrokerUserName],
    [Extent2].[BrokerPasswordHash] AS [BrokerPasswordHash],
    [Extent2].[EquityCurve] AS [EquityCurve],
    [Extent2].[CapitalInvested] AS [CapitalInvested],
    [Extent2].[IsSimulated] AS [IsSimulated],
    [Extent2].[ClosedProfit] AS [ClosedProfit],
    [Extent2].[MarketValueTimeStamp] AS [MarketValueTimeStamp],
    [Extent2].[IsAuthorizedForLiveTrading] AS [IsAuthorizedForLiveTrading],
    [Extent2].[ActivatedOn] AS [ActivatedOn],
    CASE WHEN ([Extent2].[AccountId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM  [dbo].[AspNetUsers] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Accounts] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ClientId]
)  AS [Project1]
ORDER BY [Project1].[UserName] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC
</code>```

Then seemingly one of these for each user:

```<code>SELECT TOP (1)
[Extent1].[BrokerId] AS [BrokerId],
[Extent1].[Name] AS [Name],
[Extent1].[Code] AS [Code],
[Extent1].[IsExternal] AS [IsExternal]
FROM [dbo].[Brokers] AS [Extent1]
WHERE [Extent1].[BrokerId] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=2
</code>```

And also one of these for each user:

```<code>SELECT
[Project2].[Id] AS [Id],
[Project2].[ReferralId] AS [ReferralId],
[Project2].[FirstName] AS [FirstName],
[Project2].[LastName] AS [LastName],
[Project2].[Address] AS [Address],
[Project2].[Address2] AS [Address2],
[Project2].[Zip] AS [Zip],
[Project2].[City] AS [City],
[Project2].[StateProvince] AS [StateProvince],
[Project2].[Country] AS [Country],
[Project2].[State] AS [State],
[Project2].[startPopupChecked] AS [startPopupChecked],
[Project2].[DateAdded] AS [DateAdded],
[Project2].[CurrentPortfolioId] AS [CurrentPortfolioId],
[Project2].[NotificationsEmailAddress] AS [NotificationsEmailAddress],
[Project2].[NotificationMobileNumber] AS [NotificationMobileNumber],
[Project2].[ReceivesEmailNotifications] AS [ReceivesEmailNotifications],
[Project2].[ReceivesTextNotifications] AS [ReceivesTextNotifications],
[Project2].[IsActive] AS [IsActive],
[Project2].[HasSeen] AS [HasSeen],
[Project2].[Email] AS [Email],
[Project2].[EmailConfirmed] AS [EmailConfirmed],
[Project2].[PasswordHash] AS [PasswordHash],
[Project2].[SecurityStamp] AS [SecurityStamp],
[Project2].[PhoneNumber] AS [PhoneNumber],
[Project2].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed],
[Project2].[TwoFactorEnabled] AS [TwoFactorEnabled],
[Project2].[LockoutEndDateUtc] AS [LockoutEndDateUtc],
[Project2].[LockoutEnabled] AS [LockoutEnabled],
[Project2].[AccessFailedCount] AS [AccessFailedCount],
[Project2].[UserName] AS [UserName],
[Project2].[BlockOrder_BlockOrderId] AS [BlockOrder_BlockOrderId],
[Project2].[C1] AS [C1],
[Project2].[UserId] AS [UserId],
[Project2].[RoleId] AS [RoleId]
FROM ( SELECT
    [Limit1].[Id] AS [Id],
    [Limit1].[ReferralId] AS [ReferralId],
    [Limit1].[FirstName] AS [FirstName],
    [Limit1].[LastName] AS [LastName],
    [Limit1].[Address] AS [Address],
    [Limit1].[Address2] AS [Address2],
    [Limit1].[Zip] AS [Zip],
    [Limit1].[City] AS [City],
    [Limit1].[StateProvince] AS [StateProvince],
    [Limit1].[Country] AS [Country],
    [Limit1].[State] AS [State],
    [Limit1].[startPopupChecked] AS [startPopupChecked],
    [Limit1].[DateAdded] AS [DateAdded],
    [Limit1].[CurrentPortfolioId] AS [CurrentPortfolioId],
    [Limit1].[NotificationsEmailAddress] AS [NotificationsEmailAddress],
    [Limit1].[NotificationMobileNumber] AS [NotificationMobileNumber],
    [Limit1].[ReceivesEmailNotifications] AS [ReceivesEmailNotifications],
    [Limit1].[ReceivesTextNotifications] AS [ReceivesTextNotifications],
    [Limit1].[IsActive] AS [IsActive],
    [Limit1].[HasSeen] AS [HasSeen],
    [Limit1].[Email] AS [Email],
    [Limit1].[EmailConfirmed] AS [EmailConfirmed],
    [Limit1].[PasswordHash] AS [PasswordHash],
    [Limit1].[SecurityStamp] AS [SecurityStamp],
    [Limit1].[PhoneNumber] AS [PhoneNumber],
    [Limit1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed],
    [Limit1].[TwoFactorEnabled] AS [TwoFactorEnabled],
    [Limit1].[LockoutEndDateUtc] AS [LockoutEndDateUtc],
    [Limit1].[LockoutEnabled] AS [LockoutEnabled],
    [Limit1].[AccessFailedCount] AS [AccessFailedCount],
    [Limit1].[UserName] AS [UserName],
    [Limit1].[BlockOrder_BlockOrderId] AS [BlockOrder_BlockOrderId],
    [Extent2].[UserId] AS [UserId],
    [Extent2].[RoleId] AS [RoleId],
    CASE WHEN ([Extent2].[UserId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   (SELECT TOP (1)
        [Extent1].[Id] AS [Id],
        [Extent1].[ReferralId] AS [ReferralId],
        [Extent1].[FirstName] AS [FirstName],
        [Extent1].[LastName] AS [LastName],
        [Extent1].[Address] AS [Address],
        [Extent1].[Address2] AS [Address2],
        [Extent1].[Zip] AS [Zip],
        [Extent1].[City] AS [City],
        [Extent1].[StateProvince] AS [StateProvince],
        [Extent1].[Country] AS [Country],
        [Extent1].[State] AS [State],
        [Extent1].[startPopupChecked] AS [startPopupChecked],
        [Extent1].[DateAdded] AS [DateAdded],
        [Extent1].[CurrentPortfolioId] AS [CurrentPortfolioId],
        [Extent1].[NotificationsEmailAddress] AS [NotificationsEmailAddress],
        [Extent1].[NotificationMobileNumber] AS [NotificationMobileNumber],
        [Extent1].[ReceivesEmailNotifications] AS [ReceivesEmailNotifications],
        [Extent1].[ReceivesTextNotifications] AS [ReceivesTextNotifications],
        [Extent1].[IsActive] AS [IsActive],
        [Extent1].[HasSeen] AS [HasSeen],
        [Extent1].[Email] AS [Email],
        [Extent1].[EmailConfirmed] AS [EmailConfirmed],
        [Extent1].[PasswordHash] AS [PasswordHash],
        [Extent1].[SecurityStamp] AS [SecurityStamp],
        [Extent1].[PhoneNumber] AS [PhoneNumber],
        [Extent1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed],
        [Extent1].[TwoFactorEnabled] AS [TwoFactorEnabled],
        [Extent1].[LockoutEndDateUtc] AS [LockoutEndDateUtc],
        [Extent1].[LockoutEnabled] AS [LockoutEnabled],
        [Extent1].[AccessFailedCount] AS [AccessFailedCount],
        [Extent1].[UserName] AS [UserName],
        [Extent1].[BlockOrder_BlockOrderId] AS [BlockOrder_BlockOrderId]
        FROM [dbo].[AspNetUsers] AS [Extent1]
        WHERE [Extent1].[Id] = @p__linq__0 ) AS [Limit1]
    LEFT OUTER JOIN [dbo].[AspNetUserRoles] AS [Extent2] ON [Limit1].[Id] = [Extent2].[UserId]
)  AS [Project2]
ORDER BY [Project2].[Id] ASC, [Project2].[C1] ASC',N'@p__linq__0 int',@p__linq__0=346
</code>```

答:
I am unable to delete this question even though it was actually not a problem in the long run... I still had some code from when I was working on it that did separate queries and populated some of these fields... when I stripped out that code... the following query runs very fast (2 seconds):</p>

```<code>public IQueryable<ApplicationUser> QueriableUsersList()
{
    return _context.Users.OrderBy(u => u.UserName)
        .Include(u => u.Accounts.Select(a => a.Broker))
        .Include(u => u.Roles);
}
</code>```

Body:
* UPDATE *

I am unable to delete this question even though it was actually not a problem in the long run... I still had some code from when I was working on it that did separate queries and populated some of these fields... when I stripped out that code... the following query runs very fast (2 seconds):

public IQueryable<ApplicationUser> QueriableUsersList()
{
    return _context.Users.OrderBy(u => u.UserName)
        .Include(u => u.Accounts.Select(a => a.Broker))
        .Include(u => u.Roles);
}

* ORIGINAL QUESTION *

I am trying to load a list of users (about 600 of them) using Entity Framework… I want to preload with the query account records for each user and a broker record for each account (along with roles for each user)… this SQL gets me results very quickly ( < 1 second):

select ISNULL(ur.RoleId, 0) as IsAdmin, u.*, a.*, b.*
  from AspNetUsers u
 inner join Accounts a on u.Id = a.ClientId
 inner join Brokers b on a.Brokerid = b.BrokerId
 left outer join AspNetUserRoles ur on u.id = ur.UserId and ur.RoleId = 1
order by u.UserName

But this Entity Framework query takes a long time (something like 20 - 25 seconds)... especially in production where the database is on a different server:

public IQueryable<ApplicationUser> QueriableUsersList()
{
    return _context.Users.OrderBy(u => u.UserName)
        .Include(u => u.Accounts.Select(a => a.Broker))
        .Include(u => u.Roles);
}

Any thoughts on how the Entity Framework query could be improved and/or what it would take to get it to be faster like the native SQL query is?. (Note: I do need all the data from all the above object for my list so lazy loading isn’t going to help.) I was hoping it would generate a single query along the lines of what I show above… but it is generating several queries (below) for each user it seems.

I eventually want to use this IQueryable to get paginated data as well.

My objects are defined like this:

public class ApplicationUser : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>/
{
    public List<Account> Accounts { get; set; }
…
    public bool isAdmin { get {  return this.Roles != null && this.Roles.Any(r => r.RoleId == 1); } }
…
}

public class Account
{
    public int AccountId { get; set; }
…
    public int BrokerId { get; set; }
    public virtual Broker Broker { get; set; }
…
}

public class Broker
{
    public int BrokerId { get; set; }
    public string Name { get; set; }
…
}

With the entity framework query using SQL Server profiler I see one of these:

SELECT
[Project1].[Id] AS [Id],
[Project1].[UserName] AS [UserName],
[Project1].[FirstName] AS [FirstName],
[Project1].[LastName] AS [LastName],
[Project1].[PhoneNumber] AS [PhoneNumber],
[Project1].[Email] AS [Email],
[Project1].[Address] AS [Address],
[Project1].[City] AS [City],
[Project1].[State] AS [State],
[Project1].[Zip] AS [Zip],
[Project1].[DateAdded] AS [DateAdded],
[Project1].[IsActive] AS [IsActive],
[Project1].[C1] AS [C1],
[Project1].[AccountId] AS [AccountId],
[Project1].[ClientId] AS [ClientId],
[Project1].[BrokerId] AS [BrokerId],
[Project1].[AccountNumber] AS [AccountNumber],
[Project1].[BrokerUserName] AS [BrokerUserName],
[Project1].[BrokerPasswordHash] AS [BrokerPasswordHash],
[Project1].[EquityCurve] AS [EquityCurve],
[Project1].[CapitalInvested] AS [CapitalInvested],
[Project1].[IsSimulated] AS [IsSimulated],
[Project1].[ClosedProfit] AS [ClosedProfit],
[Project1].[MarketValueTimeStamp] AS [MarketValueTimeStamp],
[Project1].[IsAuthorizedForLiveTrading] AS [IsAuthorizedForLiveTrading],
[Project1].[ActivatedOn] AS [ActivatedOn]
FROM ( SELECT
    [Extent1].[Id] AS [Id],
    [Extent1].[FirstName] AS [FirstName],
    [Extent1].[LastName] AS [LastName],
    [Extent1].[Address] AS [Address],
    [Extent1].[Zip] AS [Zip],
    [Extent1].[City] AS [City],
    [Extent1].[State] AS [State],
    [Extent1].[DateAdded] AS [DateAdded],
    [Extent1].[IsActive] AS [IsActive],
    [Extent1].[Email] AS [Email],
    [Extent1].[PhoneNumber] AS [PhoneNumber],
    [Extent1].[UserName] AS [UserName],
    [Extent2].[AccountId] AS [AccountId],
    [Extent2].[ClientId] AS [ClientId],
    [Extent2].[BrokerId] AS [BrokerId],
    [Extent2].[AccountNumber] AS [AccountNumber],
    [Extent2].[BrokerUserName] AS [BrokerUserName],
    [Extent2].[BrokerPasswordHash] AS [BrokerPasswordHash],
    [Extent2].[EquityCurve] AS [EquityCurve],
    [Extent2].[CapitalInvested] AS [CapitalInvested],
    [Extent2].[IsSimulated] AS [IsSimulated],
    [Extent2].[ClosedProfit] AS [ClosedProfit],
    [Extent2].[MarketValueTimeStamp] AS [MarketValueTimeStamp],
    [Extent2].[IsAuthorizedForLiveTrading] AS [IsAuthorizedForLiveTrading],
    [Extent2].[ActivatedOn] AS [ActivatedOn],
    CASE WHEN ([Extent2].[AccountId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM  [dbo].[AspNetUsers] AS [Extent1]
    LEFT OUTER JOIN [dbo].[Accounts] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ClientId]
)  AS [Project1]
ORDER BY [Project1].[UserName] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC

Then seemingly one of these for each user:

SELECT TOP (1)
[Extent1].[BrokerId] AS [BrokerId],
[Extent1].[Name] AS [Name],
[Extent1].[Code] AS [Code],
[Extent1].[IsExternal] AS [IsExternal]
FROM [dbo].[Brokers] AS [Extent1]
WHERE [Extent1].[BrokerId] = @p__linq__0',N'@p__linq__0 int',@p__linq__0=2

And also one of these for each user:

SELECT
[Project2].[Id] AS [Id],
[Project2].[ReferralId] AS [ReferralId],
[Project2].[FirstName] AS [FirstName],
[Project2].[LastName] AS [LastName],
[Project2].[Address] AS [Address],
[Project2].[Address2] AS [Address2],
[Project2].[Zip] AS [Zip],
[Project2].[City] AS [City],
[Project2].[StateProvince] AS [StateProvince],
[Project2].[Country] AS [Country],
[Project2].[State] AS [State],
[Project2].[startPopupChecked] AS [startPopupChecked],
[Project2].[DateAdded] AS [DateAdded],
[Project2].[CurrentPortfolioId] AS [CurrentPortfolioId],
[Project2].[NotificationsEmailAddress] AS [NotificationsEmailAddress],
[Project2].[NotificationMobileNumber] AS [NotificationMobileNumber],
[Project2].[ReceivesEmailNotifications] AS [ReceivesEmailNotifications],
[Project2].[ReceivesTextNotifications] AS [ReceivesTextNotifications],
[Project2].[IsActive] AS [IsActive],
[Project2].[HasSeen] AS [HasSeen],
[Project2].[Email] AS [Email],
[Project2].[EmailConfirmed] AS [EmailConfirmed],
[Project2].[PasswordHash] AS [PasswordHash],
[Project2].[SecurityStamp] AS [SecurityStamp],
[Project2].[PhoneNumber] AS [PhoneNumber],
[Project2].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed],
[Project2].[TwoFactorEnabled] AS [TwoFactorEnabled],
[Project2].[LockoutEndDateUtc] AS [LockoutEndDateUtc],
[Project2].[LockoutEnabled] AS [LockoutEnabled],
[Project2].[AccessFailedCount] AS [AccessFailedCount],
[Project2].[UserName] AS [UserName],
[Project2].[BlockOrder_BlockOrderId] AS [BlockOrder_BlockOrderId],
[Project2].[C1] AS [C1],
[Project2].[UserId] AS [UserId],
[Project2].[RoleId] AS [RoleId]
FROM ( SELECT
    [Limit1].[Id] AS [Id],
    [Limit1].[ReferralId] AS [ReferralId],
    [Limit1].[FirstName] AS [FirstName],
    [Limit1].[LastName] AS [LastName],
    [Limit1].[Address] AS [Address],
    [Limit1].[Address2] AS [Address2],
    [Limit1].[Zip] AS [Zip],
    [Limit1].[City] AS [City],
    [Limit1].[StateProvince] AS [StateProvince],
    [Limit1].[Country] AS [Country],
    [Limit1].[State] AS [State],
    [Limit1].[startPopupChecked] AS [startPopupChecked],
    [Limit1].[DateAdded] AS [DateAdded],
    [Limit1].[CurrentPortfolioId] AS [CurrentPortfolioId],
    [Limit1].[NotificationsEmailAddress] AS [NotificationsEmailAddress],
    [Limit1].[NotificationMobileNumber] AS [NotificationMobileNumber],
    [Limit1].[ReceivesEmailNotifications] AS [ReceivesEmailNotifications],
    [Limit1].[ReceivesTextNotifications] AS [ReceivesTextNotifications],
    [Limit1].[IsActive] AS [IsActive],
    [Limit1].[HasSeen] AS [HasSeen],
    [Limit1].[Email] AS [Email],
    [Limit1].[EmailConfirmed] AS [EmailConfirmed],
    [Limit1].[PasswordHash] AS [PasswordHash],
    [Limit1].[SecurityStamp] AS [SecurityStamp],
    [Limit1].[PhoneNumber] AS [PhoneNumber],
    [Limit1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed],
    [Limit1].[TwoFactorEnabled] AS [TwoFactorEnabled],
    [Limit1].[LockoutEndDateUtc] AS [LockoutEndDateUtc],
    [Limit1].[LockoutEnabled] AS [LockoutEnabled],
    [Limit1].[AccessFailedCount] AS [AccessFailedCount],
    [Limit1].[UserName] AS [UserName],
    [Limit1].[BlockOrder_BlockOrderId] AS [BlockOrder_BlockOrderId],
    [Extent2].[UserId] AS [UserId],
    [Extent2].[RoleId] AS [RoleId],
    CASE WHEN ([Extent2].[UserId] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1]
    FROM   (SELECT TOP (1)
        [Extent1].[Id] AS [Id],
        [Extent1].[ReferralId] AS [ReferralId],
        [Extent1].[FirstName] AS [FirstName],
        [Extent1].[LastName] AS [LastName],
        [Extent1].[Address] AS [Address],
        [Extent1].[Address2] AS [Address2],
        [Extent1].[Zip] AS [Zip],
        [Extent1].[City] AS [City],
        [Extent1].[StateProvince] AS [StateProvince],
        [Extent1].[Country] AS [Country],
        [Extent1].[State] AS [State],
        [Extent1].[startPopupChecked] AS [startPopupChecked],
        [Extent1].[DateAdded] AS [DateAdded],
        [Extent1].[CurrentPortfolioId] AS [CurrentPortfolioId],
        [Extent1].[NotificationsEmailAddress] AS [NotificationsEmailAddress],
        [Extent1].[NotificationMobileNumber] AS [NotificationMobileNumber],
        [Extent1].[ReceivesEmailNotifications] AS [ReceivesEmailNotifications],
        [Extent1].[ReceivesTextNotifications] AS [ReceivesTextNotifications],
        [Extent1].[IsActive] AS [IsActive],
        [Extent1].[HasSeen] AS [HasSeen],
        [Extent1].[Email] AS [Email],
        [Extent1].[EmailConfirmed] AS [EmailConfirmed],
        [Extent1].[PasswordHash] AS [PasswordHash],
        [Extent1].[SecurityStamp] AS [SecurityStamp],
        [Extent1].[PhoneNumber] AS [PhoneNumber],
        [Extent1].[PhoneNumberConfirmed] AS [PhoneNumberConfirmed],
        [Extent1].[TwoFactorEnabled] AS [TwoFactorEnabled],
        [Extent1].[LockoutEndDateUtc] AS [LockoutEndDateUtc],
        [Extent1].[LockoutEnabled] AS [LockoutEnabled],
        [Extent1].[AccessFailedCount] AS [AccessFailedCount],
        [Extent1].[UserName] AS [UserName],
        [Extent1].[BlockOrder_BlockOrderId] AS [BlockOrder_BlockOrderId]
        FROM [dbo].[AspNetUsers] AS [Extent1]
        WHERE [Extent1].[Id] = @p__linq__0 ) AS [Limit1]
    LEFT OUTER JOIN [dbo].[AspNetUserRoles] AS [Extent2] ON [Limit1].[Id] = [Extent2].[UserId]
)  AS [Project2]
ORDER BY [Project2].[Id] ASC, [Project2].[C1] ASC',N'@p__linq__0 int',@p__linq__0=346


来源: stackexchange

问:
how to clear gridview
I want to clear my gridview. I have 2 GridViews and Has Select Button On It. on Selecting this button that item goes into the second gridview. now the question is how should i clear the second grid view. I am trying the clear method but clear method is not found in my visual studio..</p>

答: dataGridView1.Columns.Clear(); //this clears the entire Gridview </p>

ContentLicense: CC BY-SA 2.5

Title: how to clear gridview

ContentLicense: CC BY-SA 3.0


问:
Generate SQL statement using Linq to SQL without placeholders
I'm using EF 6 to model an Oracle database and in turn wrote a simple LINQ to SQL statement to pull data.  If I take the query object and do something like:

```<code>linqQuery.ToString()
</code>```

I'll get the SQL but it has placeholders rather than the conditions passed in by my variables.  I've searched around but I can't see any solution.  The purpose of this use case is to use EF to model my entities, LINQ to SQL to craft the SQL which I then plan to hand off to another process.

Is there anyway of getting my SQL generated to include the variables?

答:
You should be able to use the logging facilities to get the exact complete SQL that is sent to the underlying RDBMS. Yes, it will contain parameters, but the definitions and values of the parameters should be part of that.
See https://msdn.microsoft.com/en-us/library/dn469464%28v=vs.113%29.aspx?f=255&MSPPError=-2147217396</p>

Body:
I'm using EF 6 to model an Oracle database and in turn wrote a simple LINQ to SQL statement to pull data.  If I take the query object and do something like:

linqQuery.ToString()

I'll get the SQL but it has placeholders rather than the conditions passed in by my variables.  I've searched around but I can't see any solution.  The purpose of this use case is to use EF to model my entities, LINQ to SQL to craft the SQL which I then plan to hand off to another process.

Is there anyway of getting my SQL generated to include the variables?


问:
JS Calculator variable prevKey doesn't register values properly
Still working on the JS Calculator for FreeCodeCamp. I've been working on this problem for the past few days. The problem is repeating operators. For example, if I press "5" then "+", but changed my mind and pressed "-". The history area should display "5-" instead of "5+".

After carefully studying what is wrong, I figured out how it's happening. If you check out my code at this Codepen, you can see how the variable prevKey isn't gathering the numbers and operators in right order...

If I press in this order "5", "+", "-". The prevKey should be a number at first then an operator, and then an operator, or something like that. However, since I listed the variable prevKey = null;, it's been messing up the order. The prevkey actually goes like that: "5", "+", "null", "-".

How do I fix it?

Here's my code in question. All the actions are happening in function addOperator(keyitem).

```<code>    subMatharray.push(mainMath);
    prevKey = mainMath;
    console.log("addOpKeyItem: " + keyitem);
    console.log("addOpPrevKey: " + prevKey);

    if(["/", "*", "+", "-"].indexOf(prevKey) == -1) {
      subMatharray.push(keyitem);
      prevKey = keyitem;
      console.log("addOpArraySubArrayElse: " + subMatharray);
      console.log("addOpArrayPrevKeyElse: " + prevKey);
      console.log("addOpArrayoppArrayElse: " + oppArray);
      console.log("addOpArrayKeyItemElse: " + keyitem);
    } else if (["/", "*", "+", "-"].indexOf(keyitem) > -1 && ["/", "*", "+", "-"].indexOf(prevKey) > -1 || prevKey == null) {
      subMatharray.push("test");

      console.log("addOpArraySubArray: " + subMatharray);
      console.log("addOpArrayPrevKey: " + prevKey);
      console.log("addOpArrayPrevKeyItem: " + keyitem);
      console.log("addOpArrayoppArray: " + oppArray);
    }
</code>```

And here's my full code here:

$(document).ready(function() {

  var mainMath = null;
  var subMath = "0";
  var finalset = "";
  var subMatharray = [];
  var oppArray = [];
  var equalPressed = false;
  var prevKey = null;
  var regexChecked = /[0-9]/g;
  var originalKey = "";
  update();

  $("button").click(function(){
    calculate($(this).attr("value"));
  });

  function calculate(keyitem) {
    originalKey = keyitem;
    console.log("buttonpress: " + keyitem);
    switch(keyitem) {
      case "clear":
        clearScreen();
        break;
      case "%":
        percentageScreen();
        break;
      case "/":
      case "*":
      case "+":
      case "-":
        addOperator(keyitem);
        break;
      case "plusminus":
        plusminusScreen();
        break;
      case "0":
      case "1":
      case "2":
      case "3":
      case "4":
      case "5":
      case "6":
      case "7":
      case "8":
      case "9":
        addNumber(keyitem);
        break;
      case ".":
        addDecimal(keyitem);
        break;
      case "=":
        solveEqual(keyitem);
        break;
    }
    update();
    };

  function clearScreen() {
     mainMath = null;
     subMath = "0";
     prevKey = null;
     subMatharray = [];
     oppArray = [];
    if(mainMath == null){
      $(".entry").css("font-size", "4em");
    }
    console.log("clearMain: " + mainMath);
    console.log("clearSub: " + subMath);
  };

  function plusminusScreen() {
     mainMath = -1 * mainMath;
    finalset = mainMath;
    console.log("plusminusMain: " + mainMath);
    console.log("plusminusFinal: " + finalset);
  };

  function addNumber(keyitem) {
    if (mainMath === null){
      mainMath = "0";
    }
    if (mainMath == "0"){
      mainMath = keyitem/*mainMath.replace("0", keyitem);*/
      finalset = mainMath;
      return;
      console.log("addedMainZero: " + mainMath);
      console.log("addedFinalZero: " + finalset);
    }
    if (equalPressed == true){
      mainMath = keyitem;
      subMath = "0";
      subMatharray = [];
      equalPressed = false;
      console.log("addNumberEqualmain: " + mainMath);
    }
    mainMath+=keyitem;
    finalset = mainMath;

    console.log("addedMain: " + mainMath);
    console.log("addedFinalset: " + finalset);
    console.log("addedarray: " + subMatharray);

    if(mainMath.length > 8){
      $(".entry").css("font-size", "1.5em");
    }

  };

  function addOperator(keyitem){
    if(mainMath === null && subMatharray.length === 0) {
      return;
    }

    if (equalPressed == true){
      subMatharray = [];
      oppArray = [];
      equalPressed = false;
      console.log("addOpEqualarray: " + subMatharray);
    }

    oppArray.push(keyitem);
    console.log("addOpArray: " + oppArray);
    var opkeyitem = "";

    subMatharray.push(mainMath);
    prevKey = mainMath;
    console.log("addOpKeyItem: " + keyitem);
    console.log("addOpPrevKey: " + prevKey);

    /*prevKey won't get numbers, only operators!!!!*/

    if(["/", "*", "+", "-"].indexOf(prevKey) == -1) {
      subMatharray.push(keyitem);
      prevKey = keyitem;
      console.log("addOpArraySubArrayElse: " + subMatharray);
      console.log("addOpArrayPrevKeyElse: " + prevKey);
      console.log("addOpArrayoppArrayElse: " + oppArray);
      console.log("addOpArrayKeyItemElse: " + keyitem);
    } else if (["/", "*", "+", "-"].indexOf(keyitem) > -1 && ["/", "*", "+", "-"].indexOf(prevKey) > -1 || prevKey == null) {
      oppArray.shift();
      opkeyitem = oppArray.toString();
      /*subMatharray.splice(-2, 2);
      /*subMatharray.pop();*/
      /*subMatharray.push(opkeyitem);*/
      subMatharray.push("test");
      /*oppArray = [];*/
      /*prevKey = null;*/
      console.log("addOpArraySubArray: " + subMatharray);
      console.log("addOpArrayPrevKey: " + prevKey);
      console.log("addOpArrayPrevKeyItem: " + keyitem);
      console.log("addOpArrayoppArray: " + oppArray);
    } /*else if(prevKey == null) {
      subMatharray.push(keyitem);
      prevKey = keyitem;
      console.log("addOpArraySubArrayElse: " + subMatharray);
      console.log("addOpArrayPrevKeyElse: " + prevKey);
      console.log("addOpArrayoppArrayElse: " + oppArray);
      console.log("addOpArrayKeyItemElse: " + keyitem);
    }*/

    subMath = subMatharray.join("");
    mainMath = null;
    /*prevKey = null;*/
    console.log("addOpSub: " + subMath);
    console.log("addOpMain: " + mainMath);
    console.log("addOpMainarray: " + subMatharray);
    console.log("equaltrueTest: " + equalPressed);
  };

  function addDecimal(keyitem){
    if (mainMath === null){
      mainMath = "0";
    }
    if (mainMath.indexOf(keyitem) === -1){
      if(mainMath == "0") {
        mainMath = "0" + keyitem;
        return;
      }
    } else {
        return;
      }
    addNumber(keyitem);
  };

  function solveEqual(keyitem) {
    subMatharray.push(finalset);
    subMath = subMatharray.join("");
    mainMath = eval(subMath);
    console.log("solveEqualresult: " + mainMath);
    console.log("solveEqualhistory: " + subMath);
    console.log("solveEqualarray: " + subMatharray);
    var finalresult = mainMath.toString();
    if(finalresult.length > 8){
      $(".entry").css("font-size", "1.5em");
    }
    equalPressed = true;
  };

  function update(){
  $("#answer").html(mainMath === null ? "0" : mainMath);
  $("#history").html(subMath);
};

});

   ```
<pre class="snippet-code-css lang-css prettyprint-override"><code>@import url('https://fonts.googleapis.com/css?family=Roboto:300,400');
h1, h2, h3, p {
  font-family: 'Roboto', sans-serif;
}
html, body{
  height:100%;
  margin: 0;
  background-color: #ffffff;
}
.wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  display:flex;
  flex-direction:column;
  justify-content:center;
  align-items:center;
  background-repeat: no-repeat;
    background-size: cover;
  background-position: center center;
  padding: 160px 0;
}
.calculatorbox {
  width: 300px;
  margin: 0 auto;
  border: 1px solid #000000;
}
.calheader {
  text-align: center;
}
.calwindow {
  background: #000000;
  position: relative;
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
   -webkit-flex-direction: column; /* Safari */
  flex-direction:         column;
  -webkit-justify-content: flex-end;
  justify-content: flex-end;
  -webkit-align-items: flex-end;
  align-items: flex-end;
  padding: 10px 0;
  box-sizing: border-box;
}
.entry {
  font-size: 4em;
  display: block;
  line-height: 1em;
}
.entryhistory {
  font-size: 1em;
  letter-spacing: 2px;
  padding-right: 5px;
}
.entry p, .entryhistory p {
  margin: 0;
  color: #ffffff;
}
sup {
  top: -0.5em;
}

sub {
  bottom: -0em;
}
.row {
  clear: both;
  width: 100%;
  display: flex;
}
button {
  display: inline-block;
  border: none;
  padding: 0;
  outline: none;
  cursor: pointer;
}
.key {
  width: 75px;
  height: 70px;
  font-size: 22px;
  border-top: 1px solid rgba(0, 0, 0, 0.3);
  border-right: 1px solid rgba(0, 0, 0, 0.3);
  box-sizing: border-box;
}
.key.btnspan {
  width: 150px;
}
.key.topcolor {
  background: #d9d9d9;
}
.key.orange {
  background: #ff8c00;
  color: #ffffff;
}</code>```

Simple Calculator

        <button class="key topcolor" value="clear">C</button>
        <button class="key topcolor" value="plusminus">+/−</button>
        <button class="key topcolor" value="%">%</button>
        <button class="key orange" value="/">÷</button>

        <button class="key" value="7">7</button>
        <button class="key" value="8">8</button>
        <button class="key" value="9">9</button>
        <button class="key orange" value="*">×</button>

        <button class="key" value="4">4</button>
        <button class="key" value="5">5</button>
        <button class="key" value="6">6</button>
        <button class="key orange" value="-">−</button>

        <button class="key" value="1">1</button>
        <button class="key" value="2">2</button>
        <button class="key" value="3">3</button>
        <button class="key orange" value="+">+</button>

        <button class="key btnspan" value="0">0</button>
        <button class="key" value=".">.</button>
        <button class="key orange" value="=">=</button>

```

答:
Your code is pretty hard to follow. Eric Lippert has a great article to help you get started on debugging small programs. I think the answer will likely be in addOperand: before pushing the latest operand on your subMathArray, check if there already is an operand, and remove it.

```<code>function lastElement(array){
    return array[array.length - 1];
}

function isOperator(char){
    return '/*+-'.indexOf(char) >= 0;
}

function addOperator(keyitem){
  if(mainMath === null && subMatharray.length === 0) {
    return;
  }

  if (equalPressed == true){
    subMatharray = [];
    oppArray = [];
    equalPressed = false;
    console.log("addOpEqualarray: " + subMatharray);
  }

  oppArray.push(keyitem);
  console.log("addOpArray: " + oppArray);
  var opkeyitem = "";

  const lastSubMath = lastElement(subMatharray);
  if(isOperator(lastSubMath)){
      subMatharray.pop();
  }

  subMatharray.push(mainMath);
  prevKey = mainMath;
  console.log("addOpKeyItem: " + keyitem);
  console.log("addOpPrevKey: " + prevKey);
  //etc
</code>```

Since I was having a hard time following your code, I decided to refactor it. I used eslint to automatically detect all the warnings that could easily be deleted. There was a lot. I then renamed your variables so they matched the UI elements to make it clearer. After I did this, it became clear that you don't need any array, and you don't need to remember previous key presses. All you need is 2 strings.

```<code>$(document).ready(function() {
  let entry = '0'; // mainMath
  let history = null; // subMath
  update();

  $('button').click(function() {
    calculate($(this).attr('value'));
  });

  function calculate(keyitem) {
    switch (keyitem) {
      case 'clear':
        clearScreen();
        break;
      case '/':
      case '*':
      case '+':
      case '-':
        addOperator(keyitem);
        break;
      case 'plusminus':
        plusminusScreen();
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        addNumber(keyitem);
        break;
      case '.':
        addDecimal();
        break;
      case '=':
        solveEqual();
        break;
    }
    update();
  };

  function clearScreen() {
    entry = '0';
    history = null;
  };

  function plusminusScreen() {
    entry = -1 * entry;
  };

  function addNumber(keyitem) {
    if (entry == '0') {
      entry = keyitem;
      history = keyitem;
      return;
    }

    if (isOperator(entry)) {
      entry = keyitem;
      history += keyitem;
      return;
    }

    entry += keyitem;
    history += keyitem;
  };

  function isOperator(char) {
    return '/*+-'.indexOf(char) >= 0;
  }

  function addOperator(keyitem) {
    if (history === null) {
      return;
    }

    if (isOperator(entry)) {
      // This part solves your repeating operator problem
      // If the current entry is an operator, replace the last
      // character in history with the new operator.
      history = history.substring(0, history.length - 1) + keyitem;
      entry = keyitem;
      return;
    }

    history += keyitem;
    entry = keyitem;
  };

  function addDecimal() {
    if (entry.indexOf('.') >= 0) {
      return;
    }

    entry += '.';
    if (history === null) {
      history = '0';
    }
    history += '.';
  };

  function solveEqual() {
    entry = eval(history);
    history = entry;
  };

  function update() {
    $('#answer').html(entry);
    $('#history').html(history);
  };
});
</code>```

Body:
Still working on the JS Calculator for FreeCodeCamp. I've been working on this problem for the past few days. The problem is repeating operators. For example, if I press "5" then "+", but changed my mind and pressed "-". The history area should display "5-" instead of "5+".

After carefully studying what is wrong, I figured out how it's happening. If you check out my code at this Codepen, you can see how the variable prevKey isn't gathering the numbers and operators in right order...

If I press in this order "5", "+", "-". The prevKey should be a number at first then an operator, and then an operator, or something like that. However, since I listed the variable prevKey = null;, it's been messing up the order. The prevkey actually goes like that: "5", "+", "null", "-".

How do I fix it?

Here's my code in question. All the actions are happening in function addOperator(keyitem).

    subMatharray.push(mainMath);
    prevKey = mainMath;
    console.log("addOpKeyItem: " + keyitem);
    console.log("addOpPrevKey: " + prevKey);

    if(["/", "*", "+", "-"].indexOf(prevKey) == -1) {
      subMatharray.push(keyitem);
      prevKey = keyitem;
      console.log("addOpArraySubArrayElse: " + subMatharray);
      console.log("addOpArrayPrevKeyElse: " + prevKey);
      console.log("addOpArrayoppArrayElse: " + oppArray);
      console.log("addOpArrayKeyItemElse: " + keyitem);
    } else if (["/", "*", "+", "-"].indexOf(keyitem) > -1 && ["/", "*", "+", "-"].indexOf(prevKey) > -1 || prevKey == null) {
      subMatharray.push("test");

      console.log("addOpArraySubArray: " + subMatharray);
      console.log("addOpArrayPrevKey: " + prevKey);
      console.log("addOpArrayPrevKeyItem: " + keyitem);
      console.log("addOpArrayoppArray: " + oppArray);
    }

And here's my full code here:

$(document).ready(function() {

  var mainMath = null;
  var subMath = "0";
  var finalset = "";
  var subMatharray = [];
  var oppArray = [];
  var equalPressed = false;
  var prevKey = null;
  var regexChecked = /[0-9]/g;
  var originalKey = "";
  update();

  $("button").click(function(){
    calculate($(this).attr("value"));
  });

  function calculate(keyitem) {
    originalKey = keyitem;
    console.log("buttonpress: " + keyitem);
    switch(keyitem) {
      case "clear":
        clearScreen();
        break;
      case "%":
        percentageScreen();
        break;
      case "/":
      case "*":
      case "+":
      case "-":
        addOperator(keyitem);
        break;
      case "plusminus":
        plusminusScreen();
        break;
      case "0":
      case "1":
      case "2":
      case "3":
      case "4":
      case "5":
      case "6":
      case "7":
      case "8":
      case "9":
        addNumber(keyitem);
        break;
      case ".":
        addDecimal(keyitem);
        break;
      case "=":
        solveEqual(keyitem);
        break;
    }
    update();
    };

  function clearScreen() {
     mainMath = null;
     subMath = "0";
     prevKey = null;
     subMatharray = [];
     oppArray = [];
    if(mainMath == null){
      $(".entry").css("font-size", "4em");
    }
    console.log("clearMain: " + mainMath);
    console.log("clearSub: " + subMath);
  };

  function plusminusScreen() {
     mainMath = -1 * mainMath;
    finalset = mainMath;
    console.log("plusminusMain: " + mainMath);
    console.log("plusminusFinal: " + finalset);
  };

  function addNumber(keyitem) {
    if (mainMath === null){
      mainMath = "0";
    }
    if (mainMath == "0"){
      mainMath = keyitem/*mainMath.replace("0", keyitem);*/
      finalset = mainMath;
      return;
      console.log("addedMainZero: " + mainMath);
      console.log("addedFinalZero: " + finalset);
    }
    if (equalPressed == true){
      mainMath = keyitem;
      subMath = "0";
      subMatharray = [];
      equalPressed = false;
      console.log("addNumberEqualmain: " + mainMath);
    }
    mainMath+=keyitem;
    finalset = mainMath;

    console.log("addedMain: " + mainMath);
    console.log("addedFinalset: " + finalset);
    console.log("addedarray: " + subMatharray);

    if(mainMath.length > 8){
      $(".entry").css("font-size", "1.5em");
    }

  };

  function addOperator(keyitem){
    if(mainMath === null && subMatharray.length === 0) {
      return;
    }

    if (equalPressed == true){
      subMatharray = [];
      oppArray = [];
      equalPressed = false;
      console.log("addOpEqualarray: " + subMatharray);
    }

    oppArray.push(keyitem);
    console.log("addOpArray: " + oppArray);
    var opkeyitem = "";

    subMatharray.push(mainMath);
    prevKey = mainMath;
    console.log("addOpKeyItem: " + keyitem);
    console.log("addOpPrevKey: " + prevKey);

    /*prevKey won't get numbers, only operators!!!!*/

    if(["/", "*", "+", "-"].indexOf(prevKey) == -1) {
      subMatharray.push(keyitem);
      prevKey = keyitem;
      console.log("addOpArraySubArrayElse: " + subMatharray);
      console.log("addOpArrayPrevKeyElse: " + prevKey);
      console.log("addOpArrayoppArrayElse: " + oppArray);
      console.log("addOpArrayKeyItemElse: " + keyitem);
    } else if (["/", "*", "+", "-"].indexOf(keyitem) > -1 && ["/", "*", "+", "-"].indexOf(prevKey) > -1 || prevKey == null) {
      oppArray.shift();
      opkeyitem = oppArray.toString();
      /*subMatharray.splice(-2, 2);
      /*subMatharray.pop();*/
      /*subMatharray.push(opkeyitem);*/
      subMatharray.push("test");
      /*oppArray = [];*/
      /*prevKey = null;*/
      console.log("addOpArraySubArray: " + subMatharray);
      console.log("addOpArrayPrevKey: " + prevKey);
      console.log("addOpArrayPrevKeyItem: " + keyitem);
      console.log("addOpArrayoppArray: " + oppArray);
    } /*else if(prevKey == null) {
      subMatharray.push(keyitem);
      prevKey = keyitem;
      console.log("addOpArraySubArrayElse: " + subMatharray);
      console.log("addOpArrayPrevKeyElse: " + prevKey);
      console.log("addOpArrayoppArrayElse: " + oppArray);
      console.log("addOpArrayKeyItemElse: " + keyitem);
    }*/

    subMath = subMatharray.join("");
    mainMath = null;
    /*prevKey = null;*/
    console.log("addOpSub: " + subMath);
    console.log("addOpMain: " + mainMath);
    console.log("addOpMainarray: " + subMatharray);
    console.log("equaltrueTest: " + equalPressed);
  };

  function addDecimal(keyitem){
    if (mainMath === null){
      mainMath = "0";
    }
    if (mainMath.indexOf(keyitem) === -1){
      if(mainMath == "0") {
        mainMath = "0" + keyitem;
        return;
      }
    } else {
        return;
      }
    addNumber(keyitem);
  };

  function solveEqual(keyitem) {
    subMatharray.push(finalset);
    subMath = subMatharray.join("");
    mainMath = eval(subMath);
    console.log("solveEqualresult: " + mainMath);
    console.log("solveEqualhistory: " + subMath);
    console.log("solveEqualarray: " + subMatharray);
    var finalresult = mainMath.toString();
    if(finalresult.length > 8){
      $(".entry").css("font-size", "1.5em");
    }
    equalPressed = true;
  };

  function update(){
  $("#answer").html(mainMath === null ? "0" : mainMath);
  $("#history").html(subMath);
};

});

@import url('https://fonts.googleapis.com/css?family=Roboto:300,400');
h1, h2, h3, p {
  font-family: 'Roboto', sans-serif;
}
html, body{
  height:100%;
  margin: 0;
  background-color: #ffffff;
}
.wrapper {
  width: 100%;
  height: 100%;
  position: relative;
  display:flex;
  flex-direction:column;
  justify-content:center;
  align-items:center;
  background-repeat: no-repeat;
    background-size: cover;
  background-position: center center;
  padding: 160px 0;
}
.calculatorbox {
  width: 300px;
  margin: 0 auto;
  border: 1px solid #000000;
}
.calheader {
  text-align: center;
}
.calwindow {
  background: #000000;
  position: relative;
  display: -webkit-box;
  display: -moz-box;
  display: -ms-flexbox;
  display: -webkit-flex;
  display: flex;
   -webkit-flex-direction: column; /* Safari */
  flex-direction:         column;
  -webkit-justify-content: flex-end;
  justify-content: flex-end;
  -webkit-align-items: flex-end;
  align-items: flex-end;
  padding: 10px 0;
  box-sizing: border-box;
}
.entry {
  font-size: 4em;
  display: block;
  line-height: 1em;
}
.entryhistory {
  font-size: 1em;
  letter-spacing: 2px;
  padding-right: 5px;
}
.entry p, .entryhistory p {
  margin: 0;
  color: #ffffff;
}
sup {
  top: -0.5em;
}

sub {
  bottom: -0em;
}
.row {
  clear: both;
  width: 100%;
  display: flex;
}
button {
  display: inline-block;
  border: none;
  padding: 0;
  outline: none;
  cursor: pointer;
}
.key {
  width: 75px;
  height: 70px;
  font-size: 22px;
  border-top: 1px solid rgba(0, 0, 0, 0.3);
  border-right: 1px solid rgba(0, 0, 0, 0.3);
  box-sizing: border-box;
}
.key.btnspan {
  width: 150px;
}
.key.topcolor {
  background: #d9d9d9;
}
.key.orange {
  background: #ff8c00;
  color: #ffffff;
}

Simple Calculator

        <button class="key topcolor" value="clear">C</button>
        <button class="key topcolor" value="plusminus">+/−</button>
        <button class="key topcolor" value="%">%</button>
        <button class="key orange" value="/">÷</button>

        <button class="key" value="7">7</button>
        <button class="key" value="8">8</button>
        <button class="key" value="9">9</button>
        <button class="key orange" value="*">×</button>

        <button class="key" value="4">4</button>
        <button class="key" value="5">5</button>
        <button class="key" value="6">6</button>
        <button class="key orange" value="-">−</button>

        <button class="key" value="1">1</button>
        <button class="key" value="2">2</button>
        <button class="key" value="3">3</button>
        <button class="key orange" value="+">+</button>

        <button class="key btnspan" value="0">0</button>
        <button class="key" value=".">.</button>
        <button class="key orange" value="=">=</button>

Body:
Your code is pretty hard to follow. Eric Lippert has a great article to help you get started on debugging small programs. I think the answer will likely be in addOperand: before pushing the latest operand on your subMathArray, check if there already is an operand, and remove it.

function lastElement(array){
    return array[array.length - 1];
}

function isOperator(char){
    return '/*+-'.indexOf(char) >= 0;
}

function addOperator(keyitem){
  if(mainMath === null && subMatharray.length === 0) {
    return;
  }

  if (equalPressed == true){
    subMatharray = [];
    oppArray = [];
    equalPressed = false;
    console.log("addOpEqualarray: " + subMatharray);
  }

  oppArray.push(keyitem);
  console.log("addOpArray: " + oppArray);
  var opkeyitem = "";

  const lastSubMath = lastElement(subMatharray);
  if(isOperator(lastSubMath)){
      subMatharray.pop();
  }

  subMatharray.push(mainMath);
  prevKey = mainMath;
  console.log("addOpKeyItem: " + keyitem);
  console.log("addOpPrevKey: " + prevKey);
  //etc

Since I was having a hard time following your code, I decided to refactor it. I used eslint to automatically detect all the warnings that could easily be deleted. There was a lot. I then renamed your variables so they matched the UI elements to make it clearer. After I did this, it became clear that you don't need any array, and you don't need to remember previous key presses. All you need is 2 strings.

$(document).ready(function() {
  let entry = '0'; // mainMath
  let history = null; // subMath
  update();

  $('button').click(function() {
    calculate($(this).attr('value'));
  });

  function calculate(keyitem) {
    switch (keyitem) {
      case 'clear':
        clearScreen();
        break;
      case '/':
      case '*':
      case '+':
      case '-':
        addOperator(keyitem);
        break;
      case 'plusminus':
        plusminusScreen();
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        addNumber(keyitem);
        break;
      case '.':
        addDecimal();
        break;
      case '=':
        solveEqual();
        break;
    }
    update();
  };

  function clearScreen() {
    entry = '0';
    history = null;
  };

  function plusminusScreen() {
    entry = -1 * entry;
  };

  function addNumber(keyitem) {
    if (entry == '0') {
      entry = keyitem;
      history = keyitem;
      return;
    }

    if (isOperator(entry)) {
      entry = keyitem;
      history += keyitem;
      return;
    }

    entry += keyitem;
    history += keyitem;
  };

  function isOperator(char) {
    return '/*+-'.indexOf(char) >= 0;
  }

  function addOperator(keyitem) {
    if (history === null) {
      return;
    }

    if (isOperator(entry)) {
      // This part solves your repeating operator problem
      // If the current entry is an operator, replace the last
      // character in history with the new operator.
      history = history.substring(0, history.length - 1) + keyitem;
      entry = keyitem;
      return;
    }

    history += keyitem;
    entry = keyitem;
  };

  function addDecimal() {
    if (entry.indexOf('.') >= 0) {
      return;
    }

    entry += '.';
    if (history === null) {
      history = '0';
    }
    history += '.';
  };

  function solveEqual() {
    entry = eval(history);
    history = entry;
  };

  function update() {
    $('#answer').html(entry);
    $('#history').html(history);
  };
});


问:
How to send HTML Emails in Outlook.com
I need help creating an HTML Email in Outlook.com. I looked in the settings and didn't see any information for this. I also searched online and in other Stackoverflow questions but couldn't really find the answer. My email is pretty simple, but each time to send it, all I see is the HTML code.

Hello NAME,

Content

Click here

Content

Sincerely

NAME

```

答: Neither Outlook.com (public site) nor Outlook 365 compose windows allow you to insert custom HTML content. You may only type your message and do basic formatting with the tools offered by compose view.</p>

Title: How to send HTML Emails in Outlook.com


问:
JSON print nested list from API request
I'm querying an API that interfaces to MariaDB and this is how I get the data back.

```<code>{'TestTable': {'columns': ['Name', 'Id'], 'records': [['Jack', 1], ['Jill', 2]]}}
</code>```

What I'm trying to achieve is to print the columns before the records like so:

Name: Jack
Id: 1
Name: Jill
Id: 2
```

<p>I tried to take the data and put the columns and records into different lists and then my idea was to use an if to match the indexes and if match to print the to the format above, but it was the wrong index.  Unfortuantely after trying to get it to work after about 5 different ways and 3 hours, I realized I had absolutely no idea what I was doing:</p>

```jsonData = json.loads(reqGet.text)
columns = jsonData['TestTable']['columns']
records = jsonData['TestTable']['records']

for idx, val in enumerate(records):
    print(idx, val)
```

<p>Output:</p>

<pre class="lang-none prettyprint-override"><code>0 ['Jack', 1]
1 ['Jill', 2]
</code>```

Any thoughts besides "Have you considered digging ditches?", would be great.

答:
You could read it to a pandas dataframe:

```<code>import pandas as pd

d = {'TestTable': {'columns': ['Name', 'Id'], 'records': [['Jack', 1], ['Jill', 2]]}}

df = pd.DataFrame(data=d['TestTable']['records'],columns=d['TestTable']['columns'])
</code>```

df looks like this:

```<code>  Name  Id
0  Jack   1
1  Jill   2
</code>```

Print it looping through the rows and joining index with value:

```<code>for idx,row in df.iterrows():
    for item in zip(row.index,row.values):
        print(': '.join([str(i) for i in item]))
</code>```

Result:

```<code>Name: Jack
Id: 1
Name: Jill
Id: 2
</code>```

Title: JSON print nested list from API request

Body:
I'm querying an API that interfaces to MariaDB and this is how I get the data back.

{'TestTable': {'columns': ['Name', 'Id'], 'records': [['Jack', 1], ['Jill', 2]]}}

What I'm trying to achieve is to print the columns before the records like so:

Name: Jack
Id: 1
Name: Jill
Id: 2

I tried to take the data and put the columns and records into different lists and then my idea was to use an if to match the indexes and if match to print the to the format above, but it was the wrong index.  Unfortuantely after trying to get it to work after about 5 different ways and 3 hours, I realized I had absolutely no idea what I was doing:

jsonData = json.loads(reqGet.text)
columns = jsonData['TestTable']['columns']
records = jsonData['TestTable']['records']

for idx, val in enumerate(records):
    print(idx, val)

Output:

0 ['Jack', 1]
1 ['Jill', 2]

Any thoughts besides "Have you considered digging ditches?", would be great.

Body:
You could read it to a pandas dataframe:

import pandas as pd

d = {'TestTable': {'columns': ['Name', 'Id'], 'records': [['Jack', 1], ['Jill', 2]]}}

df = pd.DataFrame(data=d['TestTable']['records'],columns=d['TestTable']['columns'])

df looks like this:

  Name  Id
0  Jack   1
1  Jill   2

Print it looping through the rows and joining index with value:

for idx,row in df.iterrows():
    for item in zip(row.index,row.values):
        print(': '.join([str(i) for i in item]))

Result:

Name: Jack
Id: 1
Name: Jill
Id: 2


问:
How to CancelSynchronousIo() on WaitForSingleObject() waiting on stdin?
On Windows 10, I'm waiting for input from the console using

WaitForSingleObject( GetStdHandle(STD_INPUT_HANDLE), ... )

and to cancel this waiting using CancelSynchronousIo().

But the cancellation does nothing (returns 0 and GetLastError() is ERROR_NOT_FOUND).

Any idea what I could be doing wrong?

Should I be able to cancel this waiting for new input on stdin?

(I actually want to do this with any HANDLE whose GetFileType() is FILE_TYPE_CHAR, not only stdin, but stdin is certainly the most important use case and the simplest to test with).

Related discussions I've found:

Synchronous ReadFile() on stdin cannot be unblocked by CancelSynchronousIo()

win32: how stop ReadFile (stdin|pipe)

But unfortunately they only discuss ReadFile(), not WaitForSingleObject(). I've also tried WaitForMultipleObjects() (with just a single object in the array), same problem.

(Background: I'm trying to improve input handling in the GHC Haskell compiler runtime.)

答:
Console I/O is difficult to use asynchronously, it is simply not designed for it. See IO Completion Ports (IOCP) and Asynchronous I/O through STDIN, STDOUT and STDERR for some possible workarounds.

If that is not an option for you, then you will have to either:

use WaitForSingleObject() in a loop with a short timeout.  Create a flag variable that your loop can look at on each iteration to break the loop if the flag is set.

use WaitForMutipleObjects(), giving it 2 HANDLEs to wait on - one for the console (or whatever), and one for an event object from CreateEvent().  Then you can signal the event with SetEvent() when you want to break the wait.  The return value of WaitForMutipleObjects() will tell you which HANDLE was signaled.


问:
substring in sh returns "Bad substitution"
In this code:

```<code>#!/bin/sh
a='sdsdsd'
c=${a:0:1}
</code>```

I use second line to read bytes of string one by one (in a loop), but it returns error in sh ("sh: 3: Bad substitution").
any way to do it in sh mode?
for some reasons i should use sh (not bash, and i know bash will be OK)

答:
With posix shell without expr

#!/bin/sh
var='abcd'
count="${#var}"
until [ "$count" -eq 0 ];do
  vartemp="${var#[a-z]}"
  lavar="${var%$vartemp}"
  var="$vartemp"
  count="$((count-1))"
  echo "$var $count $lavar"
done
```

Body:
In this code:

#!/bin/sh
a='sdsdsd'
c=${a:0:1}

I use second line to read bytes of string one by one (in a loop), but it returns error in sh ("sh: 3: Bad substitution").
any way to do it in sh mode?
for some reasons i should use sh (not bash, and i know bash will be OK)

ContentLicense: CC BY-SA 4.0


问:
What is the difference between controller in MVC pattern and presenter in MVP pattern?
What is the difference between controller in MVC pattern and presenter in MVP pattern? Can you provide links for understanding the Merits and usage scenario for both of them? </p>

答:
In MVP the Presenter assumes the functionality of the "middle-man" (played by the Application Controller in MVC). Additionally, the View is responsible for handling the UI events (like mouseDown, keyDown, etc), which used to be the Controller's job. Eventually, the Model becomes strictly a Domain Model.

Says Wikipedia.

Here is a more detailed explanation on the differences between the two.

See also Martin Fowler's Retirement note for Model View Presenter.


问:
adding a class to a calendar day in jQuery UI (MultipleDates)
I'm using Multiple Dates picker for jQuery UI date picker. Everything was going fine until now. Turns out the developer who made it hasn't touched it in years and pre-highlighting dates no longer works. So here's my plan. I'll place my dates that i need highlighted into an array, then using jQuery to add the necessary class to the calendars. That's where I'm stuck. How do I target this particular anchor when the it looks like this:

```<code><td class=" ui-datepicker-week-end  ui-datepicker-current-day" data-handler="selectDay" data-event="click" data-month="10" data-year="2017">
<a class="ui-state-default" href="#">18</a> <!-- needs class: ui-state-active-->
</td>
</code>```

So how do I target based on data-month, data-year and then the number that's in the anchor? All help is greatly appreciated!!

答:
Trigger the function with beforeShowDay event.

UPDATED: JavaScript: jQuery Datepicker - simple highlighting of specific days, who can help? (source inside)

Body:
I'm using Multiple Dates picker for jQuery UI date picker. Everything was going fine until now. Turns out the developer who made it hasn't touched it in years and pre-highlighting dates no longer works. So here's my plan. I'll place my dates that i need highlighted into an array, then using jQuery to add the necessary class to the calendars. That's where I'm stuck. How do I target this particular anchor when the it looks like this:

18

So how do I target based on data-month, data-year and then the number that's in the anchor? All help is greatly appreciated!!


问:
Call panda DataFrame (INSERT NEW COLUMN) into Python Script
I am attempting to add a 'Game Id' Column into a table that i am scraping (see script below).  I am not sure where to ad the pd.Dataframe and what to call on (within my web scrape) so that i can insert a new column called 'Game ID' BEFORE i write the script into a csv file (so that it writes with the new game id column with the scrape).

(Just some background info: the 'Game id' is the i in the loop that the scrape is iterating over from the url)

i tried entering

df.insert(0, 'GameID', range(1, 1 + len(df))) or

df['GameID']= (df.index / 18 + 1).astype(int)

but i do not know what to call my dataframe on (i tried pd.Dataframe[table, columns = 'cols] but it would not read it).

```<code>#ALL HOME GOALIES GAME STATS

import requests
from bs4 import BeautifulSoup
import pandas as pd
import csv

f = open('HOME_GOALIES_ALL.csv', 'a', newline = '')
writer = csv.writer(f)

GameID = i
for i in range (400961844,400961845):
    url = requests.get("http://www.espn.com/nhl/boxscore?gameId={}".format(i))
    if not url.ok:
        continue
    data = url.text
    soup = BeautifulSoup(data, 'lxml')
    table = soup.find_all('table', {'class' : 'mod-data'})[8].find_all('tr')[2:]
    for row in table:
        cols = row.findChildren(recursive=False)
        cols = [ele.text.strip() for ele in cols]
        writer.writerow(cols)
</code>```

答:
There is no DataFrame in your code, however, this can be done as follows:

```<code>import requests
from bs4 import BeautifulSoup
import pandas as pd
import csv
table = []
df = pd.DataFrame()
for i in range (400961844,400961848):
    url = requests.get("http://www.espn.com/nhl/boxscore?gameId={}".format(i))
    if not url.ok:
        continue
    data = url.text
    soup = BeautifulSoup(data, 'lxml')
    #Add the game ID to the list of soups to keep track of multiple players with same game ID
    table.append((i,soup.find_all('table', {'class' : 'mod-data'})[8].find_all('tr')[2:]))

data = []
soups = []
game_id = []
for i,t in table:
#Use .contents method to turn the soup into list of items
    soups = [j.contents for j in t]
    for s in soups:
#Use .string method to parse the values of different columns
        data.append([a.string for a in s])
#Append the Game ID
        game_id.append(i)

In [58]:
data
Out[58]:
[['H. Lundqvist', '25', '3', '22', '.880', '58:19', '0'],
 ['C. Anderson', '28', '4', '24', '.857', '65:00', '0'],
 ['J. Howard', '39', '2', '37', '.949', '60:00', '0'],
 ['C. Crawford', '29', '1', '28', '.966', '59:56', '0'],
 ['J. Gibson', '30', '4', '26', '.867', '59:53', '10'],
 ['J. Quick', '35', '0', '35', '1.000', '59:59', '0'],
 ['S. Bobrovsky', '29', '0', '29', '1.000', '59:53', '0'],
 ['A. Vasilevskiy', '36', '3', '33', '.917', '60:00', '0'],
 ['K. Lehtonen', '11', '2', '9', '.818', '15:00', '0'],
 ['B. Bishop', '19', '0', '19', '1.000', '43:58', '0'],
 ['F. Andersen', '35', '5', '30', '.857', '60:00', '0']]

#Create a DataFrame from the data extracted
df = pd.DataFrame(data)

In [59]:
df

Out[59]:
        0             1     2   3    4       5      6
0   H. Lundqvist      25    3   22  .880    58:19   0
1   C. Anderson       28    4   24  .857    65:00   0
2   J. Howard         39    2   37  .949    60:00   0
3   C. Crawford       29    1   28  .966    59:56   0
4   J. Gibson         30    4   26  .867    59:53   10
5   J. Quick          35    0   35  1.000   59:59   0
6   S. Bobrovsky      29    0   29  1.000   59:53   0
7   A. Vasilevskiy    36    3   33  .917    60:00   0
8   K. Lehtonen       11    2   9   .818    15:00   0
9   B. Bishop         19    0   19  1.000   43:58   0
10  F. Andersen       35    5   30  .857    60:00   0
</code>```

The columns names can be set using: df.columns = [list_of_columns_names]

Now for the important part, to add the 'Game ID' column, you can use the game_id list that we have created before: df['Game ID'] = game_id

Finally to write the DataFrame as CSV file: df.to_csv('path_of_file')

Body:
I am attempting to add a 'Game Id' Column into a table that i am scraping (see script below).  I am not sure where to ad the pd.Dataframe and what to call on (within my web scrape) so that i can insert a new column called 'Game ID' BEFORE i write the script into a csv file (so that it writes with the new game id column with the scrape).

(Just some background info: the 'Game id' is the i in the loop that the scrape is iterating over from the url)

i tried entering

df.insert(0, 'GameID', range(1, 1 + len(df))) or

df['GameID']= (df.index / 18 + 1).astype(int)

but i do not know what to call my dataframe on (i tried pd.Dataframe[table, columns = 'cols] but it would not read it).

#ALL HOME GOALIES GAME STATS

import requests
from bs4 import BeautifulSoup
import pandas as pd
import csv

f = open('HOME_GOALIES_ALL.csv', 'a', newline = '')
writer = csv.writer(f)

GameID = i
for i in range (400961844,400961845):
    url = requests.get("http://www.espn.com/nhl/boxscore?gameId={}".format(i))
    if not url.ok:
        continue
    data = url.text
    soup = BeautifulSoup(data, 'lxml')
    table = soup.find_all('table', {'class' : 'mod-data'})[8].find_all('tr')[2:]
    for row in table:
        cols = row.findChildren(recursive=False)
        cols = [ele.text.strip() for ele in cols]
        writer.writerow(cols)

Body:
There is no DataFrame in your code, however, this can be done as follows:

import requests
from bs4 import BeautifulSoup
import pandas as pd
import csv
table = []
df = pd.DataFrame()
for i in range (400961844,400961848):
    url = requests.get("http://www.espn.com/nhl/boxscore?gameId={}".format(i))
    if not url.ok:
        continue
    data = url.text
    soup = BeautifulSoup(data, 'lxml')
    #Add the game ID to the list of soups to keep track of multiple players with same game ID
    table.append((i,soup.find_all('table', {'class' : 'mod-data'})[8].find_all('tr')[2:]))

data = []
soups = []
game_id = []
for i,t in table:
#Use .contents method to turn the soup into list of items
    soups = [j.contents for j in t]
    for s in soups:
#Use .string method to parse the values of different columns
        data.append([a.string for a in s])
#Append the Game ID
        game_id.append(i)

In [58]:
data
Out[58]:
[['H. Lundqvist', '25', '3', '22', '.880', '58:19', '0'],
 ['C. Anderson', '28', '4', '24', '.857', '65:00', '0'],
 ['J. Howard', '39', '2', '37', '.949', '60:00', '0'],
 ['C. Crawford', '29', '1', '28', '.966', '59:56', '0'],
 ['J. Gibson', '30', '4', '26', '.867', '59:53', '10'],
 ['J. Quick', '35', '0', '35', '1.000', '59:59', '0'],
 ['S. Bobrovsky', '29', '0', '29', '1.000', '59:53', '0'],
 ['A. Vasilevskiy', '36', '3', '33', '.917', '60:00', '0'],
 ['K. Lehtonen', '11', '2', '9', '.818', '15:00', '0'],
 ['B. Bishop', '19', '0', '19', '1.000', '43:58', '0'],
 ['F. Andersen', '35', '5', '30', '.857', '60:00', '0']]

#Create a DataFrame from the data extracted
df = pd.DataFrame(data)

In [59]:
df

Out[59]:
        0             1     2   3    4       5      6
0   H. Lundqvist      25    3   22  .880    58:19   0
1   C. Anderson       28    4   24  .857    65:00   0
2   J. Howard         39    2   37  .949    60:00   0
3   C. Crawford       29    1   28  .966    59:56   0
4   J. Gibson         30    4   26  .867    59:53   10
5   J. Quick          35    0   35  1.000   59:59   0
6   S. Bobrovsky      29    0   29  1.000   59:53   0
7   A. Vasilevskiy    36    3   33  .917    60:00   0
8   K. Lehtonen       11    2   9   .818    15:00   0
9   B. Bishop         19    0   19  1.000   43:58   0
10  F. Andersen       35    5   30  .857    60:00   0

The columns names can be set using: df.columns = [list_of_columns_names]

Now for the important part, to add the 'Game ID' column, you can use the game_id list that we have created before: df['Game ID'] = game_id

Finally to write the DataFrame as CSV file: df.to_csv('path_of_file')


问:
Loading only parent image in a loop
I'm working on a blade template in laravel and it's loading very slowly. I think the main issue is the images.

So, my page is built by using a foreach loop around a group container div and this creates multiple divs on the page (anywhere between 5 and 20 depending on the order form chosen). Anyway, within this foreach loop, there is another foreach loop just for images, here:

```<code>  <div class="uk-grid">
    <div class="uk-width-2-10">
        <ul style="margin: 0; padding: 0; list-style-type: none; float: left; width: 100%;">
            @foreach ($pgroup->image_names as $image_name)
            <li style="max-width: 220px;"><a href="http://sales.jacksonfurnind.com/imagelib/Mediums/{{ substr($image_name, 0, strpos($image_name, ',')) }}" data-uk-lightbox="{group:'my-group'}" target=_blank><img src="http://sales.jacksonfurnind.com/imagelib/Bigthumbs/{{ substr($image_name, 0, strpos($image_name, ',')) }}" style="width: 100%; height: auto;" /></a><span class="uk-text-center" style="padding: 0 0 5px;">{{ substr($image_name, strpos( $image_name, ',') + 1)  }}</span></li>

            @endforeach
        </ul>
    </div>
  </div>
</code>```

I tried lazy loading them and it didn't help with loading speed/performance. However, I've thought of another solution if I can do it.

Right now, the images load as an ul vertically and there are anywhere from 1 to 6 images. what I'd like to do, using JS and/or CSS is keep the div/loop intact but only load the first li or the parent. Then when clicked, the lightbox on the image group will still contain the other images.

I'm just not sure how I would go about doing this. I want it to keep doing what it's doing but only load the parent image of the loop on the front end.

UPDATE:

I've tried this:

```<code><script type="text/javascript">

$(document).ready(function()
 {
     $('#imageLoop li').not(":first-child").hide();
 });
</script>

And it "works" but upon page load it shows all images, and then after a few seconds it hides the child images.
</code>```

答:
There is probably a lot of ways to do this. My solution would be to:
1. add a key to the foreach loop.
2. If the key is equal to 0, the first li, then print that li with the image. 3. If the key is not the first one, then print a hidden li tag and only add the link to the lightbox image.

            @foreach ($pgroup->image_names as $key => $image_name)
@if ( $key == 0 )

{{ substr($image_name, strpos( $image_name, ',') + 1)  }}

@else

@endif
            @endforeach

```

When the lightbox appears, you should be able to click the arrows to view all the remaining images.

Title: Loading only parent image in a loop

Body:
I'm working on a blade template in laravel and it's loading very slowly. I think the main issue is the images.

So, my page is built by using a foreach loop around a group container div and this creates multiple divs on the page (anywhere between 5 and 20 depending on the order form chosen). Anyway, within this foreach loop, there is another foreach loop just for images, here:

            @foreach ($pgroup->image_names as $image_name)

{{ substr($image_name, strpos( $image_name, ',') + 1)  }}

            @endforeach

I tried lazy loading them and it didn't help with loading speed/performance. However, I've thought of another solution if I can do it.

Right now, the images load as an ul vertically and there are anywhere from 1 to 6 images. what I'd like to do, using JS and/or CSS is keep the div/loop intact but only load the first li or the parent. Then when clicked, the lightbox on the image group will still contain the other images.

I'm just not sure how I would go about doing this. I want it to keep doing what it's doing but only load the parent image of the loop on the front end.

UPDATE:

I've tried this:

And it "works" but upon page load it shows all images, and then after a few seconds it hides the child images.

Body:
There is probably a lot of ways to do this. My solution would be to:
1. add a key to the foreach loop.
2. If the key is equal to 0, the first li, then print that li with the image. 3. If the key is not the first one, then print a hidden li tag and only add the link to the lightbox image.

 <div class="uk-grid">
    <div class="uk-width-2-10">
        <ul style="margin: 0; padding: 0; list-style-type: none; float: left; width: 100%;">
            @foreach ($pgroup->image_names as $key => $image_name)
@if ( $key == 0 )
            <li style="max-width: 220px;"><a href="Mediums/{{ substr($image_name, 0, strpos($image_name, ',')) }}" data-uk-lightbox="{group:'my-group'}" target=_blank><img src="Bigthumbs/{{ substr($image_name, 0, strpos($image_name, ',')) }}" style="width: 100%; height: auto;" /></a><span class="uk-text-center" style="padding: 0 0 5px;">{{ substr($image_name, strpos( $image_name, ',') + 1)  }}</span></li>
@else
<li class="hidden "><a href="http://sales.jacksonfurnind.com/imagelib/Mediums/{{ substr($image_name, 0, strpos($image_name, ',')) }}" data-uk-lightbox="{group:'my-group'}" target=_blank> </a> </li>
@endif
            @endforeach
        </ul>
    </div>
  </div>

When the lightbox appears, you should be able to click the arrows to view all the remaining images.


问:
Replacing a string with pdo on MySQL
I want to replace a string but I use PDO. Whatever I have tried is not working. Have you ever replaced a mysql string by using PDO connection?

Here is an example which is not working.

```<code>try
{
    $image = $_POST['data1'];
    $id= $_POST['data2'];

    $insert = "UPDATE myTable SET images=REPLACE(images,':image','') where id = :id";

    $insertStmt = $conn->prepare($insert);
    $insertStmt->bindValue(":image", $image);
    $insertStmt->bindValue(":id", $id);

        $insertStmt->execute();

        echo "success";
}

        catch(PDOException $ex)
{
        echo $ex->getMessage();
}
</code>```

答:
write :image instead of ':image'</p>

```<code>$insert = "UPDATE myTable SET images=REPLACE(images,:image,'') where id = :id";
</code>```

Title: Replacing a string with pdo on MySQL

Body:
I want to replace a string but I use PDO. Whatever I have tried is not working. Have you ever replaced a mysql string by using PDO connection?

Here is an example which is not working.

try
{
    $image = $_POST['data1'];
    $id= $_POST['data2'];

    $insert = "UPDATE myTable SET images=REPLACE(images,':image','') where id = :id";

    $insertStmt = $conn->prepare($insert);
    $insertStmt->bindValue(":image", $image);
    $insertStmt->bindValue(":id", $id);

        $insertStmt->execute();

        echo "success";
}

        catch(PDOException $ex)
{
        echo $ex->getMessage();
}

Body:
write :image instead of ':image'

$insert = "UPDATE myTable SET images=REPLACE(images,:image,'') where id = :id";


问:
How to make tkinter Canvas update only on-demand?
I'm writing a graphics program in Python and I would like to know how to make a Canvas update only on-demand; that is, stop a canvas from updating every run of the event loop and instead update only when I tell it to.

I want to do this because in my program I have a separate thread that reads graphics data from standard input to prevent blocking the event loop (given that there's no reliable, portable way to poll standard input in Python, and polling sucks anyway), but I want the screen to be updated only at intervals of a certain amount of time, not whenever the separate thread starts reading input.

答:
You can't pause the update of the canvas without pausing the entire GUI.

A simple solution would be for you to not draw to the canvas until you're ready for the update. Instead of calling canvas commands, push those commands onto a queue. When you're ready to refresh the display, iterate over the commands and run them.

You could also do your own double-buffering, where you have two canvases. The one you are actively drawing would be behind the visible one. When you are ready to display the results, swap the stacking order of the canvases.


问:
.htaccess rewrite URL to unminified version of file (if it exists) based on query string
I want to serve the unminified version of any file with nomin in its URL.

For example, if I request:

```<code>http://localhost/foo/bar.min.js?nomin
</code>```

I should receive the file:

```<code>http://localhost/foo/bar.js
</code>```

However, I want that to happen only if the file exists.

This is what I have in my .htaccess file:

```<code>RewriteCond %{QUERY_STRING} nomin
RewriteCond %{REQUEST_URI} (.*)\.min(\..*)
RewriteCond %{DOCUMENT_ROOT}/$1$2 -f
RewriteRule (.*)\.min(\..*) $1$2 [L,QSA,NC]
</code>```

However, it doesn't work. If I remove the line where I check if the file exists:

```<code>RewriteCond %{DOCUMENT_ROOT}/$1$2 -f
</code>```

It starts working, but may point to non-existent files.

I tried:

Removing the slash RewriteCond %{DOCUMENT_ROOT}$1$2 -f.

Using REQUEST_URI like that RewriteCond %{REQUEST_URI}/$1$2 -f (with and without slash), even though it doesn't make much sense.

Matching the whole thing and only checking the parts excluding ".min"

```<code>RewriteCond $0 (.*)\.min(\..*)
RewriteCond $1$2 -f
</code>```

What am I doing wrong?

Side question: Is there a way to change my RewriteCond and RewriteRule such that I don't have to write (.*)\.min(\..*) twice?

答:
This should work for you:

```<code>RewriteCond %{QUERY_STRING} ^nomin$ [NC]
RewriteCond %{REQUEST_URI} ^(.+)\.min(\.[^.]+)$ [NC]
RewriteCond %{DOCUMENT_ROOT}/%1%2 -f
RewriteRule ^ %1%2 [L,NC]
</code>```

Use %1, %2 instead of $1, $2 for values being captured from RewriteCond

Body:
I want to serve the unminified version of any file with nomin in its URL.

For example, if I request:

http://localhost/foo/bar.min.js?nomin

I should receive the file:

http://localhost/foo/bar.js

However, I want that to happen only if the file exists.

This is what I have in my .htaccess file:

RewriteCond %{QUERY_STRING} nomin
RewriteCond %{REQUEST_URI} (.*)\.min(\..*)
RewriteCond %{DOCUMENT_ROOT}/$1$2 -f
RewriteRule (.*)\.min(\..*) $1$2 [L,QSA,NC]

However, it doesn't work. If I remove the line where I check if the file exists:

RewriteCond %{DOCUMENT_ROOT}/$1$2 -f

It starts working, but may point to non-existent files.

I tried:

Removing the slash RewriteCond %{DOCUMENT_ROOT}$1$2 -f.

Using REQUEST_URI like that RewriteCond %{REQUEST_URI}/$1$2 -f (with and without slash), even though it doesn't make much sense.

Matching the whole thing and only checking the parts excluding ".min"

RewriteCond $0 (.*)\.min(\..*)
RewriteCond $1$2 -f

What am I doing wrong?

Side question: Is there a way to change my RewriteCond and RewriteRule such that I don't have to write (.*)\.min(\..*) twice?

Body:
This should work for you:

RewriteCond %{QUERY_STRING} ^nomin$ [NC]
RewriteCond %{REQUEST_URI} ^(.+)\.min(\.[^.]+)$ [NC]
RewriteCond %{DOCUMENT_ROOT}/%1%2 -f
RewriteRule ^ %1%2 [L,NC]

Use %1, %2 instead of $1, $2 for values being captured from RewriteCond


问:
R Shiny Javascript
I am trying to get some inject custom javascript into my shiny app. I am able to get the page to load and run the javascript, but cannot get the data back from the javascript into shiny for processing by pressing the 'confirm_list' button.  I have been following this tutorial (https://www.aridhia.com/blog/the-sky-is-not-the-limit-embedding-raw-html-and-javascript-to-create-dynamic-ui-elements-in-shiny-applications/).

The folder structure of the three files is

```<code>|-ui.r
|-server.r
|-widget.r
|-www
     |-script.js
</code>```

ui.r

```<code>library(shiny)
library(stringi)

source("../widgets.R")

attendeeForm <- stri_replace_all_charclass(attendeeForm, "\\p{WHITE_SPACE}", " ")

# Define UI space for our application
shinyUI(fluidPage(

  # First lets create a button which will trigger adding a new attendee form.
  actionButton('add_Button', 'Add attendee!'),

  # Now, lets create a DIV element to which we will be adding attendee forms.
  div(id="div"),

  tags$head(HTML(sprintf(
    "<script>
    function addAttendee() {
      var attendee = \'%s\';
      $('#div').append(attendee)
    }
  </script>", attendeeForm))),

  tags$body(HTML('<script>
addAttendee();
    </script>')),

  # On click event to triger addAttendee function
  tags$head(HTML("
  <script>
    $(document).on('shiny:connected', function(event) {
      $('#add_Button').on('click', function() {addAttendee()})
    })
  </script>
")),

  # Trigger removeAttendee function when button of class 'remover' is clicked.
  tags$head(HTML("
  <script>
    function removeAttendee(el) {
      $(el).parents(\"p\").remove()
    };

    $(document).on('click','.remover',function() {
      removeAttendee(this)
    });
  </script>
")),

  actionButton('confirm_list', 'Confirm attendees'),

  tags$head(HTML("
  <script>
    $(document).on('shiny:inputchanged', function(event) {

      $('#confirm_list').on('click', function() {getAttendees()})

    });
  </script>
")),

  tags$head(tags$script(src = 'script.js')),

  tableOutput('attendee_table')

))
</code>```

server.R

```<code># Define server logic
shinyServer(function(input, output) {

  # Server code goes here

  output$attendee_table <- renderTable({
    df <- data.frame(Name = unlist(input$attendees$name),
                     Department = unlist(input$attendees$department),
                     Email = unlist(input$attendees$email))
    df
  })
})
</code>```

widgets.R

```<code># Creating raw HTML widget form containing ("Name","Department","Email") fields and Remove button of CSS class 'remover'

attendeeForm <- '<p>

                     <label for="name">Name: </label>
                     <input style="width: 150px;" id="name" type="text" placeholder="Enter name">

                     <!--Department field-->
                     <label for="department">Department: </label>
                     <input style="width: 150px;" id="department" type="text" placeholder="Enter department">

                     <!--Email field-->
                     <label for="email">Email: </label>
                     <input style="width: 150px;" id="email" type="text" placeholder="example@email.com">

                     <!--Remove button-->
                     <input type = "button" class="remover" value = &#10008>
                     </p>
                     '
</code>```

script.js

```<code>function getAttendees() {
  var name = [];
  var department = [];
  var email = [];
  var attendees = [];

  $(".name").each(function() {
    name.push($(this).val())
  })

  $(".department").each(function() {
    department.push($(this).val())
  })

  $(".email").each(function() {
    email.push($(this).val())
  })

  Shiny.onInputChange("attendees", {name, department, email})
}
</code>```

答:
The error was in the widget and script combination. In the script I was trying to reference the classes name, department and email, but in the widgets.R where I built the html I used id instead of class.

Therefore widgets.r becomes

```<code>attendeeForm <- '<p>

                     <label for="name">Name: </label>
                     <input style="width: 150px;" class="name" type="text" placeholder="Enter name">

                     <!--Department field-->
                     <label for="department">Department: </label>
                     <input style="width: 150px;" class="department" type="text" placeholder="Enter department">

                     <!--Email field-->
                     <label for="email">Email: </label>
                     <input style="width: 150px;" class="email" type="text" placeholder="example@email.com">

                     <!--Remove button-->
                     <input type = "button" class="remover" value = &#10008>
                     </p>
                     '
</code>```

Title: R Shiny Javascript

Body:
I am trying to get some inject custom javascript into my shiny app. I am able to get the page to load and run the javascript, but cannot get the data back from the javascript into shiny for processing by pressing the 'confirm_list' button.  I have been following this tutorial (https://www.aridhia.com/blog/the-sky-is-not-the-limit-embedding-raw-html-and-javascript-to-create-dynamic-ui-elements-in-shiny-applications/).

The folder structure of the three files is

|-ui.r
|-server.r
|-widget.r
|-www
     |-script.js

ui.r

library(shiny)
library(stringi)

source("../widgets.R")

attendeeForm <- stri_replace_all_charclass(attendeeForm, "\\p{WHITE_SPACE}", " ")

# Define UI space for our application
shinyUI(fluidPage(

  # First lets create a button which will trigger adding a new attendee form.
  actionButton('add_Button', 'Add attendee!'),

  # Now, lets create a DIV element to which we will be adding attendee forms.
  div(id="div"),

  tags$head(HTML(sprintf(
    "", attendeeForm))),

  tags$body(HTML('')),

  # On click event to triger addAttendee function
  tags$head(HTML("

")),

  # Trigger removeAttendee function when button of class 'remover' is clicked.
  tags$head(HTML("

")),

  actionButton('confirm_list', 'Confirm attendees'),

  tags$head(HTML("

")),

  tags$head(tags$script(src = 'script.js')),

  tableOutput('attendee_table')

))

server.R

# Define server logic
shinyServer(function(input, output) {

  # Server code goes here

  output$attendee_table <- renderTable({
    df <- data.frame(Name = unlist(input$attendees$name),
                     Department = unlist(input$attendees$department),
                     Email = unlist(input$attendees$email))
    df
  })
})

widgets.R

# Creating raw HTML widget form containing ("Name","Department","Email") fields and Remove button of CSS class 'remover'

attendeeForm <- '

                     Name:
                     <input style="width: 150px;" id="name" type="text" placeholder="Enter name">

                     Department:
                     <input style="width: 150px;" id="department" type="text" placeholder="Enter department">

                     Email:
                     <input style="width: 150px;" id="email" type="text" placeholder="example@email.com">

                     <input type = "button" class="remover" value = &#10008>

                     '

script.js

function getAttendees() {
  var name = [];
  var department = [];
  var email = [];
  var attendees = [];

  $(".name").each(function() {
    name.push($(this).val())
  })

  $(".department").each(function() {
    department.push($(this).val())
  })

  $(".email").each(function() {
    email.push($(this).val())
  })

  Shiny.onInputChange("attendees", {name, department, email})
}

Body:
The error was in the widget and script combination. In the script I was trying to reference the classes name, department and email, but in the widgets.R where I built the html I used id instead of class.

Therefore widgets.r becomes

attendeeForm <- '<p>

                     <label for="name">Name: </label>
                     <input style="width: 150px;" class="name" type="text" placeholder="Enter name">

                     <!--Department field-->
                     <label for="department">Department: </label>
                     <input style="width: 150px;" class="department" type="text" placeholder="Enter department">

                     <!--Email field-->
                     <label for="email">Email: </label>
                     <input style="width: 150px;" class="email" type="text" placeholder="example@email.com">

                     <!--Remove button-->
                     <input type = "button" class="remover" value = &#10008>
                     </p>
                     '


问:
where goes the ret instruction of the main
I learned how assembly (x86) globally works in the book : "Programming from ground up".
In this book, every program ends with an interruption call to exit.

However, in C compiled programs, I found out that programs end with a ret. This supposes that there is an address to be popped and that would lead to the end of the program.

So my question is :
What is this address? (And what is the code there?)

答:
It is implementation specific.

On Linux, main is called by crt0,  and the _start entry point there is analyzing the initial call stack set up by the kernel interpreting the execve(2) system call of your executable program. On return from main the epilogue part of crt0 is dealing with atexit(3) registered functions and flushing stdio.

FWIW, crt0 is provided by your GCC compiler, and perhaps your C standard library. All this (with the Linux kernel) is free software on Linux distribution.

every program ends with an interruption call to exit.

Not really. It is a system call (see syscalls(2) for their list), not an interrupt. See also this.


问:
phalcon framework webtools not working when creating models, views and controllers
I'm having some problems while trying to get phalcon webtools working.

When using command line devtools I can create controllers and models without problems.

However, things aren't that easy with the webtools.

It correctly shows already created controllers and models:

Controllers (http://i.imgur.com/IRWPaVJ.png)

Models (http://i.imgur.com/rIbvbg9.png)

And I can also edit them (http://i.imgur.com/orJweLl.png).

Apparently, Db connexion is ok, since webtools shows every table in the DB:

Models (http://i.imgur.com/iOkZfyo.png)

Scaffolding (http://i.imgur.com/5ZLRuq5.png)

However, when trying to create a controller from the web interface, I got the next error:

"Please specify a controller directory"

Same when trying to create a Model from a database table :

"Database configuration cannot be loaded from your config file"

Or when trying to generate scaffold :

"Adapter was not found in the config. Please specify a config variable
  [database][adapter]"

My app/config/config.php content:

```<code>return new \Phalcon\Config(array(
    'database' => array(
        'adapter'     => 'Mysql',
        'host'        => 'localhost',
        'username'    => 'phalcon',
        'password'    => 'phalcon',
        'dbname'      => 'phalcon',
        'charset'     => 'utf8',
    ),
    'application' => array(
        'controllersDir' => __DIR__ . '/../../app/controllers/',
        'modelsDir'      => __DIR__ . '/../../app/models/',
        'viewsDir'       => __DIR__ . '/../../app/views/',
        'pluginsDir'     => __DIR__ . '/../../app/plugins/',
        'libraryDir'     => __DIR__ . '/../../app/library/',
        'cacheDir'       => __DIR__ . '/../../app/cache/',
        'baseUri'        => '/phalconTest/',

    )
));
</code>```

My public/webtools.config.php content:

```<code>define('PTOOLS_IP', '192.168.248.135');
define('PTOOLSPATH', 'C:/phalcon-devtools');
</code>```

My public/webtools.php:

```<code>use Phalcon\Web\Tools;
require 'webtools.config.php';
require PTOOLSPATH . '/scripts/Phalcon/Web/Tools.php';

Tools::main(PTOOLSPATH, PTOOLS_IP);
</code>```

Im running Phalcon 1.3.4 - Windows x86 for PHP 5.4.0 (VC9)

答:
Somewhat related, I had an issue with the webtools url getting longer and longer .. Eventually I could fix this by adding the word webtools in a replacement for the baseUri in config.php .

```<code><?php ### config.php ... somewhat relevant parts ...
return new \Phalcon\Config([
    'database' => [ # ... some things ...
    ],
    'application' => [ # ... some more ...
        // This allows the baseUri to be understand project paths that are not in the root directory
        // of the webpspace.  This will break if the public/index.php entry point is moved or
        // possibly if the web server rewrite rules are changed. This can also be set to a static path.
        'baseUri'        => preg_replace(
            '/(public([\/\\\\]))?(index)|(webtools).php$/',
            '',
            $_SERVER["PHP_SELF"]
        ),
    ]
]);
</code>```

Body:
I'm having some problems while trying to get phalcon webtools working.

When using command line devtools I can create controllers and models without problems.

However, things aren't that easy with the webtools.

It correctly shows already created controllers and models:

Controllers (http://i.imgur.com/IRWPaVJ.png)

Models (http://i.imgur.com/rIbvbg9.png)

And I can also edit them (http://i.imgur.com/orJweLl.png).

Apparently, Db connexion is ok, since webtools shows every table in the DB:

Models (http://i.imgur.com/iOkZfyo.png)

Scaffolding (http://i.imgur.com/5ZLRuq5.png)

However, when trying to create a controller from the web interface, I got the next error:

"Please specify a controller directory"

Same when trying to create a Model from a database table :

"Database configuration cannot be loaded from your config file"

Or when trying to generate scaffold :

"Adapter was not found in the config. Please specify a config variable
  [database][adapter]"

My app/config/config.php content:

return new \Phalcon\Config(array(
    'database' => array(
        'adapter'     => 'Mysql',
        'host'        => 'localhost',
        'username'    => 'phalcon',
        'password'    => 'phalcon',
        'dbname'      => 'phalcon',
        'charset'     => 'utf8',
    ),
    'application' => array(
        'controllersDir' => __DIR__ . '/../../app/controllers/',
        'modelsDir'      => __DIR__ . '/../../app/models/',
        'viewsDir'       => __DIR__ . '/../../app/views/',
        'pluginsDir'     => __DIR__ . '/../../app/plugins/',
        'libraryDir'     => __DIR__ . '/../../app/library/',
        'cacheDir'       => __DIR__ . '/../../app/cache/',
        'baseUri'        => '/phalconTest/',

    )
));

My public/webtools.config.php content:

define('PTOOLS_IP', '192.168.248.135');
define('PTOOLSPATH', 'C:/phalcon-devtools');

My public/webtools.php:

use Phalcon\Web\Tools;
require 'webtools.config.php';
require PTOOLSPATH . '/scripts/Phalcon/Web/Tools.php';

Tools::main(PTOOLSPATH, PTOOLS_IP);

Im running Phalcon 1.3.4 - Windows x86 for PHP 5.4.0 (VC9)

Body:
Somewhat related, I had an issue with the webtools url getting longer and longer .. Eventually I could fix this by adding the word webtools in a replacement for the baseUri in config.php .

<?php ### config.php ... somewhat relevant parts ...
return new \Phalcon\Config([
    'database' => [ # ... some things ...
    ],
    'application' => [ # ... some more ...
        // This allows the baseUri to be understand project paths that are not in the root directory
        // of the webpspace.  This will break if the public/index.php entry point is moved or
        // possibly if the web server rewrite rules are changed. This can also be set to a static path.
        'baseUri'        => preg_replace(
            '/(public([\/\\\\]))?(index)|(webtools).php$/',
            '',
            $_SERVER["PHP_SELF"]
        ),
    ]
]);


问:
DebugBreak() equivalent in C#
In C# is there any statement equivalent to DebugBreak()? I want to invoke the debugger when ever a particular condition is met.

答:
You can use the Break method of the Debugger class, in the System.Diagnostics namespace:

```<code>Debugger.Break();
</code>```

Now, there's also a different way you can add conditional breakpoints, without mucking about with adding code to your project.

This of course only works when already running your program through the debugger

What you can do is first add a regular breakpoint at the location where you want your debugger to stop, then right-click the red dot for the breakpoint:

and then edit the condition to fit your needs:

This will then be symbolized with a small + inside your breakpoint dot:

Title: DebugBreak() equivalent in C#

Body:
You can use the Break method of the Debugger class, in the System.Diagnostics namespace:

Debugger.Break();

Now, there's also a different way you can add conditional breakpoints, without mucking about with adding code to your project.

This of course only works when already running your program through the debugger

What you can do is first add a regular breakpoint at the location where you want your debugger to stop, then right-click the red dot for the breakpoint:

and then edit the condition to fit your needs:

This will then be symbolized with a small + inside your breakpoint dot:


问:
what do the parameters of bbox mean in pillow?
I am trying to take a screenshot of a delimited area of the screen using Pillow (python), but I'm having trouble figuring out what the four parameters mean. I searched the docs, but they only say it is a bbox, but not what they mean, someone know where is this specified?

This is the code I am trying to use, what do 'a', 'b', 'c' and 'd' represent?

```<code>ImageGrab.grab(bbox=(a,b,c,d))
</code>```

答:
according to the doc

Parameters: bbox – What region to copy. Default is the entire screen.

so as for the box the parameters are positions

Parameters: box – The crop rectangle, as a (left, upper, right, lower)-tuple.

As @Yury mention it below, a better explanation then the documentation can be found  on this blog here

Body:
I am trying to take a screenshot of a delimited area of the screen using Pillow (python), but I'm having trouble figuring out what the four parameters mean. I searched the docs, but they only say it is a bbox, but not what they mean, someone know where is this specified?

This is the code I am trying to use, what do 'a', 'b', 'c' and 'd' represent?

ImageGrab.grab(bbox=(a,b,c,d))