问:
CROSS APPLY Creating Additional Records
I am trying to create a report that display potential duplicate records based on three criteria: the last 4 of an SSN, last name and DOB.  I posted a question here on the issue and received an answer that I should be using a Cross Apply to unpivot the data. The query runs fast and the results look better than my original query.

The new query is below and I have added a filter to show two examples that I am seeing occur across the data:

```<code>DECLARE
@StartDate DATE = '1/1/2017',
@EndDate DATE = '3/1/2017';

WITH
CTE
AS
(
SELECT
    DENSE_RANK() OVER (ORDER BY c.socialSecurityNumber) AS [SSNRanking] ,

    c.id AS [CustomerID]  ,
    c.socialSecurityNumber AS [SSN],
    c.firstName AS [FirstName] ,
    c.lastName AS [LastName] ,
    c.birthDate [BirthDate] ,
    c.emailAddress AS [EmailAddress],
    c.createDate AS [CreateDate] ,
    MAX(co.orderDate) AS [LastOrderDate] ,
    ca.street1 AS [Addr1] ,
    ca.city AS [City] ,
    ca.stateAndTerritoriesID AS [State],
    ca.zipCode5 AS [Zip] ,

    c2.id AS [DupCustomerID] ,
    c2.socialSecurityNumber AS [DupSSN] ,
    c2.firstName AS [DupFirstName] ,
    c2.lastName AS [DupLastName] ,
    c2.birthDate AS [DupBirthDate] ,
    c2.emailAddress AS [DupEmailAddress] ,
    c2.createDate AS [DupCreateDate] ,
    MAX(co.orderDate) AS [DupLastOrderDate] ,
    ca.street1 AS [DupAddr1] ,
    ca.city AS [DupCity],
    ca.stateAndTerritoriesID AS [DupState] ,
    ca.zipCode5 AS [DupZip]

FROM
    dbo.Customers AS [c]
    INNER JOIN dbo.Customers AS [c2] ON ( SUBSTRING(c.socialSecurityNumber,6,4) = SUBSTRING(c2.socialSecurityNumber,6,4) AND c.birthDate = c2.birthDate AND c.lastName = c2.lastName AND c.id <> c2.id )
    INNER JOIN dbo.CustomerAddresses AS [ca] ON c.id = ca.customerID
    --INNER JOIN dbo.CustomerAddresses AS [ca2] ON ca2.customerID = c2.id
    LEFT OUTER JOIN dbo.Common_Orders AS [co] ON co.customerID = c.id
WHERE
    c.customerStatusTypeID <> 'M'
    AND c2.customerStatusTypeID <> 'M'
    AND ca.addressType = 'M'
    --AND ca2.addressType = 'M'
    AND c.mergedTo IS NULL
    AND c2.mergedTo IS NULL
    AND CAST(co.orderDate AS DATE) >= @StartDate
    AND CAST(co.orderDate AS DATE) <= @EndDate
    AND ( c.id = 1545229 OR c.id = 2020489 )
GROUP BY
    c.id ,
    c.socialSecurityNumber ,
    c.firstName ,
    c.lastName ,
    c.birthDate ,
    c.emailAddress ,
    c.createDate ,
    ca.street1 ,
    ca.city ,
    ca.stateAndTerritoriesID ,
    ca.zipCode5 ,

    c2.id ,
    c2.socialSecurityNumber ,
    c2.firstName ,
    c2.lastName ,
    c2.birthDate ,
    c2.emailAddress ,
    c2.createDate ,
    ca.street1 ,
    ca.city ,
    ca.stateAndTerritoriesID ,
    ca.zipCode5
)
SELECT CA.CustomerID,
CA.SSNRanking ,
CA.SSN ,
CA.FirstName,
CA.LastName,
CA.BirthDate,
CA.EmailAddress,
CA.CreateDate ,
CA.LastOrderDate ,
CA.Addr1,
CA.City,
CA.[State],
CA.Zip
FROM
CTE
CROSS APPLY
(
    VALUES
    (CTE.SSNRanking, CTE.CustomerID,    CTE.SSN,     CTE.FirstName,    CTE.LastName,    CTE.Birthdate,    CTE.EmailAddress,    CTE.CreateDate,    CTE.LastOrderDate,    CTE.Addr1,    CTE.City,    CTE.[State],  CTE.Zip),
    (CTE.SSNRanking, CTE.DupCustomerID, CTE.DupSSN,  CTE.DupFirstName, CTE.DuplastName, CTE.DupBirthDate, CTE.DupEmailAddress, CTE.DupCreateDate, CTE.DupLastOrderDate, CTE.DupAddr1, CTE.DupCity, CTE.DupState, CTE.DupZip)
) AS CA (SSNRanking, CustomerID, SSN, FirstName, LastName, BirthDate, EmailAddress, CreateDate, LastOrderDate, Addr1, City, [State], Zip)
ORDER BY CAST(CA.SSN AS INT) ASC, CA.CustomerID;
</code>```

And the result set looks like (Original Image):

```<code>+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + ------------ + --------------------- + ----------------------- + --------------------- + ------------ + ----- + ----- +
| CustomerId | SSNRanking | SSN       | FirstName  | LastName | BirthDate  | EmailAddress | CreateDate            | LastOrderDate           | Addr1                 | City         | State | Zip   |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + ------------ + --------------------- + ----------------------- + --------------------- + ------------ + ----- + ----- +
| 1545229    | 1          | 000000000 | Aquia Boat | SALES    | 1900-01-01 | null         | 2013-05-28 00:00:00.0 | 2017-01-23 11:08:30.723 | 236 Willow Landing Rd | Stafford     | VA    | 22554 |
| 1545229    | 1          | 000000000 | Aquia Boat | SALES    | 1900-01-01 | null         | 2013-05-28 00:00:00.0 | 2017-01-06 12:31:15.370 | 11963 Jefferson Ave   | Newport News | VA    | 23606 |
| 2020489    | 1          | 000000000 | DIXIE      | SALES    | 1900-01-01 | null         | 2017-01-06 12:27:56.5 | 2017-01-06 12:31:15.370 | 11963 Jefferson Ave   | Newport News | VA    | 23606 |
| 2020489    | 1          | 000000000 | DIXIE      | SALES    | 1900-01-01 | null         | 2017-01-06 12:27:56.5 | 2017-01-23 11:08:30.723 | 236 Willow Landing Rd | Stafford     | VA    | 22554 |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + ------------ + --------------------- + ----------------------- + --------------------- + ------------ + ----- + ----- +
</code>```

And I see that the last four of the SSN, last name and DOB all match.  But then I noticed duplicate Customer IDs Aqua Boats has an entry with the Dixie Sales address and Dixie Sales has an entry for Aqua Boats address - which I should not have and I looked in the Customer /Customer Addresses table at the particular accounts:

```<code>SELECT c.id, c.socialSecurityNumber, c.firstName, c.lastName, c.birthDate, ca.street1
    FROM dbo.Customers AS c
    INNER JOIN dbo.CustomerAddresses AS [ca] ON ca.customerID = c.id
    WHERE c.id IN (1545229,2020489) AND ca.addressType = 'M';
</code>```

And the results are here (Original Image):

```<code>+ ---------- + -------------------- + ---------- + -------- + ---------- + --------------------- +
| id         | socialSecurityNumber | firstName  | lastName | birthDate  | street 1              |
+ ---------- + -------------------- + ---------- + -------- + ---------- + --------------------- +
| 1545229    | 000000000            | Aquia Boat | SALES    | 1900-01-01 | 236 Willow Landing Rd |
| 2020489    | 000000000            | DIXIE      | SALES    | 1900-01-01 | 11963 Jefferson Ave   |
+ ---------- + -------------------- + ---------- + -------- + ---------- + --------------------- +
</code>```

When I run the query inside the CTE, I added two additional filters:

```<code>AND c.id <> ca2.customerID
AND c2.id <> ca.customerID
</code>```

And the dataset looks like I want (Original Image):

```<code>+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + --------------------- + ------------ + ----- + ----- + ------------- + --------- + ------------- + ----------- + ------------- + --------------------- + ------------ + -------- + ------ +
| SSNRanking | CustomerID | SSN       | FirstName  | LastName | BirthDate  | Addr1                 | City         | State | Zip   | DupCustomerID | DupSSN    | DupFirstName  | DupLastName | DupBirthDate  | DupAddr1              | DupCity      | DupState | DupZip |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + --------------------- + ------------ + ----- + ----- + ------------- + --------- + ------------- + ----------- + ------------- + --------------------- + ------------ + -------- + ------ +
| 1          | 1545229    | 000000000 | Aquia Boat | SALES    | 1900-01-01 | 236 Willow Landing Rd | Stafford     | VA    | 22554 | 2020589       | 000000000 | DIXIE         | SALES       | 1900-01-01    | 236 Willow Landing Rd | Stafford     | VA       | 22554  |
| 1          | 2020489    | 000000000 | DIXIE      | SALES    | 1900-01-01 | 11963 Jefferson Ave   | Newport News | VA    | 23606 | 1545229       | 000000000 | AQUIA BOAT    | SALES       | 1900-01-01    | 11963 Jefferson Ave   | Newport News | VA       | 23606  |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + --------------------- + ------------ + ----- + ----- + ------------- + --------- + ------------- + ----------- + ------------- + --------------------- + ------------ + -------- + ------ +
</code>```

Can I prevent the CROSS APPLY from creating additional records for customers with mailing address assigned to another customer?

Thanks,

答:
I kept fiddling with the report and I was able to achieve my desired results by adding another CTE and ROW_NUMBER function to remove the duplicate rows I was seeing.  Seems like overkill for my desired outcome, but this runs much faster than my original query:</p>

```<code>IF OBJECT_ID('tempdb..#DupSSN') IS NOT NULL
DROP TABLE #DupSSN;

WITH cte
AS
(
SELECT  DENSE_RANK() OVER (ORDER BY c.socialSecurityNumber) AS [SSNRanking] ,

    c.socialSecurityNumber AS [SSN],
    RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 6, 4))) AS [F_SSN] ,
    c.id AS [CustomerID] ,
    REPLACE(LTRIM(RTRIM(c.firstName)), CHAR(13) + CHAR(10), ' ') AS [FirstName] ,
    REPLACE(LTRIM(RTRIM(c.lastName)), CHAR(13) + CHAR(10), ' ') AS [LastName] ,
    c.birthDate AS [BirthDate] ,
    MAX(co.orderDate) AS [LastOrderDate] ,
    RTRIM(LTRIM(ca.street1)) AS [Addr1] ,
    RTRIM(LTRIM(ca.city)) AS [City] ,
    ca.stateAndTerritoriesID AS [State] ,
    ca.zipCode5 AS [Zip] ,
    RTRIM(LTRIM(c.emailAddress)) AS [EmailAddress] ,
    c.createDate AS [CreateDate] ,

    c2.socialSecurityNumber AS [DupSSN] ,
    RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 6, 4))) AS [F_DupSSn] ,
    c2.id AS [DupCustomerID] ,
    REPLACE(LTRIM(RTRIM(c2.firstName)), CHAR(13) + CHAR(10), ' ') AS [DupFirstName] ,
    REPLACE(LTRIM(RTRIM(c2.lastName)), CHAR(13) + CHAR(10), ' ') AS [DupLastName] ,
    c2.birthDate AS [DupBirthDate] ,
    MAX(co2.orderDate) AS [DupLastOrderDate] ,
    RTRIM(LTRIM(ca2.street1)) AS [DupAddr1] ,
    RTRIM(LTRIM(ca2.city)) AS [DupCity] ,
    ca2.stateAndTerritoriesID AS [DupState] ,
    ca2.zipCode5 AS [DupZip] ,
    RTRIM(LTRIM(c2.emailAddress)) AS [DupEmailAddress] ,
    c2.createDate AS [DupCreateDate]

FROM    dbo.Customers AS [c]
    INNER JOIN dbo.Customers AS [c2] ON ( SUBSTRING(c.socialSecurityNumber,6,4) = SUBSTRING(c2.socialSecurityNumber,6,4) AND c.birthDate = c2.birthDate AND c.lastName = c2.lastName AND c.id <> c2.id )
    INNER JOIN dbo.CustomerAddresses AS [ca] ON c.id = ca.customerID
    INNER JOIN dbo.CustomerAddresses AS [ca2] ON c2.id = ca2.customerID
    INNER JOIN dbo.Common_Orders AS [co] ON co.customerID = c.id
    INNER JOIN dbo.Common_Orders AS [co2] ON co2.customerID = c2.id
WHERE   c.customerStatusTypeID <> 'M'
    AND c2.customerStatusTypeID <> 'M'
    AND ca.addressType <> 'M'
    AND ca2.addressType <> 'M'
    AND c.mergedTo IS NULL
    AND c2.mergedTo IS NULL
    AND CAST(co.orderDate AS DATE) >= '3/1/2017'
    AND CAST(co.orderDate AS DATE) <= '3/31/2017'
GROUP BY c.socialSecurityNumber ,
    RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 6, 4))) ,
    c.id ,
    REPLACE(LTRIM(RTRIM(c.firstName)), CHAR(13) + CHAR(10), ' ') ,
    REPLACE(LTRIM(RTRIM(c.lastName)), CHAR(13) + CHAR(10), ' ') ,
    c.birthDate ,
    RTRIM(LTRIM(CA.street1)) ,
    RTRIM(LTRIM(CA.city)) ,
    CA.stateAndTerritoriesID ,
    CA.zipCode5 ,
    RTRIM(LTRIM(c.emailAddress)) ,
    c.createDate ,

    c2.socialSecurityNumber ,
    RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 6, 4))) ,
    c2.id ,
    REPLACE(LTRIM(RTRIM(c2.firstName)), CHAR(13) + CHAR(10), ' ') ,
    REPLACE(LTRIM(RTRIM(c2.lastName)), CHAR(13) + CHAR(10), ' ') ,
    c2.birthDate ,
    RTRIM(LTRIM(ca2.street1)) ,
    RTRIM(LTRIM(ca2.city)) ,
    ca2.stateAndTerritoriesID ,
    ca2.zipCode5 ,
    RTRIM(LTRIM(c2.emailAddress)) ,
    c2.createDate
)
-- Use a CTE to cross apply or unpivot the potential duplicates into separate rows
SELECT  ca.SSNRanking ,
    ca.SSN ,
    ca.F_SSN ,
    ca.CustomerID ,
    ca.FirstName ,
    ca.LastName ,
    ca.BirthDate ,
    ca.LastOrderDate ,
    ca.Addr1 ,
    ca.City ,
    ca.[State] ,
    ca.Zip ,
    ca.EmailAddress ,
    ca.CreateDate
INTO    #DupSSN

FROM cte
CROSS APPLY
(
VALUES
( cte.SSNRanking, cte.SSN,    cte.F_SSN, cte.CustomerID,    cte.FirstName,    cte.LastName,    cte.BirthDate,    cte.LastOrderDate,   cte.Addr1,    cte.City,    cte.[State],  cte.Zip,    cte.EmailAddress,    cte.CreateDate ) ,
( cte.SSNRanking, cte.DupSSN, cte.F_SSN, cte.DupCustomerID, cte.DupFirstName, cte.DupLastName, cte.DupBirthDate, cte.DupLastOrderDate,cte.DupAddr1, cte.DupCity, cte.DupState, cte.DupZip, cte.DupEmailAddress, cte.DupCreateDate )
) AS ca (SSNRanking, SSN, F_SSN, CustomerID, FirstName, LastName, BirthDate, LastOrderDate, Addr1, City, State, Zip, EmailAddress, CreateDate)
ORDER BY CAST(ca.SSN AS INT) ASC, ca.CustomerID;

-- Use CTE to create ROW_NUMBER function to eliminate duplicate records
WITH SSN_RN AS
(
SELECT  SSNRanking ,
    ROW_NUMBER() OVER ( PARTITION BY SSN, CustomerID, FirstName, LastName, BirthDate, LastOrderDate, Addr1, City, CreateDate ORDER BY ( SELECT NULL ) ) AS [RowNumber] ,
    SSN ,
    F_SSN ,
    CustomerID ,
    FirstName ,
    LastName ,
    BirthDate ,
    LastOrderDate ,
    Addr1 ,
    City ,
    State ,
    Zip ,
    EmailAddress ,
    CreateDate
FROM    #DupSSN
)
SELECT  SSN_RN.SSNRanking ,
    SSN_RN.RowNumber ,
    SSN_RN.SSN ,
    SSN_RN.F_SSN ,
    SSN_RN.CustomerID ,
    SSN_RN.FirstName ,
    SSN_RN.LastName ,
    SSN_RN.BirthDate ,
    SSN_RN.LastOrderDate ,
    SSN_RN.Addr1 ,
    SSN_RN.City ,
    SSN_RN.State ,
    SSN_RN.Zip ,
    SSN_RN.EmailAddress ,
    SSN_RN.CreateDate
FROM    SSN_RN
WHERE   SSN_RN.RowNumber = 1
ORDER BY CAST(SSN_RN.SSN AS INT) ASC ,
    SSN_RN.CustomerID;

DROP TABLE #DupSSN;
</code>```

Title: CROSS APPLY Creating Additional Records

Body:
I am trying to create a report that display potential duplicate records based on three criteria: the last 4 of an SSN, last name and DOB.  I posted a question here on the issue and received an answer that I should be using a Cross Apply to unpivot the data. The query runs fast and the results look better than my original query.

The new query is below and I have added a filter to show two examples that I am seeing occur across the data:

DECLARE
@StartDate DATE = '1/1/2017',
@EndDate DATE = '3/1/2017';

WITH
CTE
AS
(
SELECT
    DENSE_RANK() OVER (ORDER BY c.socialSecurityNumber) AS [SSNRanking] ,

    c.id AS [CustomerID]  ,
    c.socialSecurityNumber AS [SSN],
    c.firstName AS [FirstName] ,
    c.lastName AS [LastName] ,
    c.birthDate [BirthDate] ,
    c.emailAddress AS [EmailAddress],
    c.createDate AS [CreateDate] ,
    MAX(co.orderDate) AS [LastOrderDate] ,
    ca.street1 AS [Addr1] ,
    ca.city AS [City] ,
    ca.stateAndTerritoriesID AS [State],
    ca.zipCode5 AS [Zip] ,

    c2.id AS [DupCustomerID] ,
    c2.socialSecurityNumber AS [DupSSN] ,
    c2.firstName AS [DupFirstName] ,
    c2.lastName AS [DupLastName] ,
    c2.birthDate AS [DupBirthDate] ,
    c2.emailAddress AS [DupEmailAddress] ,
    c2.createDate AS [DupCreateDate] ,
    MAX(co.orderDate) AS [DupLastOrderDate] ,
    ca.street1 AS [DupAddr1] ,
    ca.city AS [DupCity],
    ca.stateAndTerritoriesID AS [DupState] ,
    ca.zipCode5 AS [DupZip]

FROM
    dbo.Customers AS [c]
    INNER JOIN dbo.Customers AS [c2] ON ( SUBSTRING(c.socialSecurityNumber,6,4) = SUBSTRING(c2.socialSecurityNumber,6,4) AND c.birthDate = c2.birthDate AND c.lastName = c2.lastName AND c.id <> c2.id )
    INNER JOIN dbo.CustomerAddresses AS [ca] ON c.id = ca.customerID
    --INNER JOIN dbo.CustomerAddresses AS [ca2] ON ca2.customerID = c2.id
    LEFT OUTER JOIN dbo.Common_Orders AS [co] ON co.customerID = c.id
WHERE
    c.customerStatusTypeID <> 'M'
    AND c2.customerStatusTypeID <> 'M'
    AND ca.addressType = 'M'
    --AND ca2.addressType = 'M'
    AND c.mergedTo IS NULL
    AND c2.mergedTo IS NULL
    AND CAST(co.orderDate AS DATE) >= @StartDate
    AND CAST(co.orderDate AS DATE) <= @EndDate
    AND ( c.id = 1545229 OR c.id = 2020489 )
GROUP BY
    c.id ,
    c.socialSecurityNumber ,
    c.firstName ,
    c.lastName ,
    c.birthDate ,
    c.emailAddress ,
    c.createDate ,
    ca.street1 ,
    ca.city ,
    ca.stateAndTerritoriesID ,
    ca.zipCode5 ,

    c2.id ,
    c2.socialSecurityNumber ,
    c2.firstName ,
    c2.lastName ,
    c2.birthDate ,
    c2.emailAddress ,
    c2.createDate ,
    ca.street1 ,
    ca.city ,
    ca.stateAndTerritoriesID ,
    ca.zipCode5
)
SELECT CA.CustomerID,
CA.SSNRanking ,
CA.SSN ,
CA.FirstName,
CA.LastName,
CA.BirthDate,
CA.EmailAddress,
CA.CreateDate ,
CA.LastOrderDate ,
CA.Addr1,
CA.City,
CA.[State],
CA.Zip
FROM
CTE
CROSS APPLY
(
    VALUES
    (CTE.SSNRanking, CTE.CustomerID,    CTE.SSN,     CTE.FirstName,    CTE.LastName,    CTE.Birthdate,    CTE.EmailAddress,    CTE.CreateDate,    CTE.LastOrderDate,    CTE.Addr1,    CTE.City,    CTE.[State],  CTE.Zip),
    (CTE.SSNRanking, CTE.DupCustomerID, CTE.DupSSN,  CTE.DupFirstName, CTE.DuplastName, CTE.DupBirthDate, CTE.DupEmailAddress, CTE.DupCreateDate, CTE.DupLastOrderDate, CTE.DupAddr1, CTE.DupCity, CTE.DupState, CTE.DupZip)
) AS CA (SSNRanking, CustomerID, SSN, FirstName, LastName, BirthDate, EmailAddress, CreateDate, LastOrderDate, Addr1, City, [State], Zip)
ORDER BY CAST(CA.SSN AS INT) ASC, CA.CustomerID;

And the result set looks like (Original Image):

+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + ------------ + --------------------- + ----------------------- + --------------------- + ------------ + ----- + ----- +
| CustomerId | SSNRanking | SSN       | FirstName  | LastName | BirthDate  | EmailAddress | CreateDate            | LastOrderDate           | Addr1                 | City         | State | Zip   |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + ------------ + --------------------- + ----------------------- + --------------------- + ------------ + ----- + ----- +
| 1545229    | 1          | 000000000 | Aquia Boat | SALES    | 1900-01-01 | null         | 2013-05-28 00:00:00.0 | 2017-01-23 11:08:30.723 | 236 Willow Landing Rd | Stafford     | VA    | 22554 |
| 1545229    | 1          | 000000000 | Aquia Boat | SALES    | 1900-01-01 | null         | 2013-05-28 00:00:00.0 | 2017-01-06 12:31:15.370 | 11963 Jefferson Ave   | Newport News | VA    | 23606 |
| 2020489    | 1          | 000000000 | DIXIE      | SALES    | 1900-01-01 | null         | 2017-01-06 12:27:56.5 | 2017-01-06 12:31:15.370 | 11963 Jefferson Ave   | Newport News | VA    | 23606 |
| 2020489    | 1          | 000000000 | DIXIE      | SALES    | 1900-01-01 | null         | 2017-01-06 12:27:56.5 | 2017-01-23 11:08:30.723 | 236 Willow Landing Rd | Stafford     | VA    | 22554 |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + ------------ + --------------------- + ----------------------- + --------------------- + ------------ + ----- + ----- +

And I see that the last four of the SSN, last name and DOB all match.  But then I noticed duplicate Customer IDs Aqua Boats has an entry with the Dixie Sales address and Dixie Sales has an entry for Aqua Boats address - which I should not have and I looked in the Customer /Customer Addresses table at the particular accounts:

SELECT c.id, c.socialSecurityNumber, c.firstName, c.lastName, c.birthDate, ca.street1
    FROM dbo.Customers AS c
    INNER JOIN dbo.CustomerAddresses AS [ca] ON ca.customerID = c.id
    WHERE c.id IN (1545229,2020489) AND ca.addressType = 'M';

And the results are here (Original Image):

+ ---------- + -------------------- + ---------- + -------- + ---------- + --------------------- +
| id         | socialSecurityNumber | firstName  | lastName | birthDate  | street 1              |
+ ---------- + -------------------- + ---------- + -------- + ---------- + --------------------- +
| 1545229    | 000000000            | Aquia Boat | SALES    | 1900-01-01 | 236 Willow Landing Rd |
| 2020489    | 000000000            | DIXIE      | SALES    | 1900-01-01 | 11963 Jefferson Ave   |
+ ---------- + -------------------- + ---------- + -------- + ---------- + --------------------- +

When I run the query inside the CTE, I added two additional filters:

AND c.id <> ca2.customerID
AND c2.id <> ca.customerID

And the dataset looks like I want (Original Image):

+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + --------------------- + ------------ + ----- + ----- + ------------- + --------- + ------------- + ----------- + ------------- + --------------------- + ------------ + -------- + ------ +
| SSNRanking | CustomerID | SSN       | FirstName  | LastName | BirthDate  | Addr1                 | City         | State | Zip   | DupCustomerID | DupSSN    | DupFirstName  | DupLastName | DupBirthDate  | DupAddr1              | DupCity      | DupState | DupZip |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + --------------------- + ------------ + ----- + ----- + ------------- + --------- + ------------- + ----------- + ------------- + --------------------- + ------------ + -------- + ------ +
| 1          | 1545229    | 000000000 | Aquia Boat | SALES    | 1900-01-01 | 236 Willow Landing Rd | Stafford     | VA    | 22554 | 2020589       | 000000000 | DIXIE         | SALES       | 1900-01-01    | 236 Willow Landing Rd | Stafford     | VA       | 22554  |
| 1          | 2020489    | 000000000 | DIXIE      | SALES    | 1900-01-01 | 11963 Jefferson Ave   | Newport News | VA    | 23606 | 1545229       | 000000000 | AQUIA BOAT    | SALES       | 1900-01-01    | 11963 Jefferson Ave   | Newport News | VA       | 23606  |
+ ---------- + ---------- + --------- + ---------- + -------- + ---------- + --------------------- + ------------ + ----- + ----- + ------------- + --------- + ------------- + ----------- + ------------- + --------------------- + ------------ + -------- + ------ +

Can I prevent the CROSS APPLY from creating additional records for customers with mailing address assigned to another customer?

Thanks,

Body:
I kept fiddling with the report and I was able to achieve my desired results by adding another CTE and ROW_NUMBER function to remove the duplicate rows I was seeing.  Seems like overkill for my desired outcome, but this runs much faster than my original query:

IF OBJECT_ID('tempdb..#DupSSN') IS NOT NULL
DROP TABLE #DupSSN;

WITH cte
AS
(
SELECT  DENSE_RANK() OVER (ORDER BY c.socialSecurityNumber) AS [SSNRanking] ,

    c.socialSecurityNumber AS [SSN],
    RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 6, 4))) AS [F_SSN] ,
    c.id AS [CustomerID] ,
    REPLACE(LTRIM(RTRIM(c.firstName)), CHAR(13) + CHAR(10), ' ') AS [FirstName] ,
    REPLACE(LTRIM(RTRIM(c.lastName)), CHAR(13) + CHAR(10), ' ') AS [LastName] ,
    c.birthDate AS [BirthDate] ,
    MAX(co.orderDate) AS [LastOrderDate] ,
    RTRIM(LTRIM(ca.street1)) AS [Addr1] ,
    RTRIM(LTRIM(ca.city)) AS [City] ,
    ca.stateAndTerritoriesID AS [State] ,
    ca.zipCode5 AS [Zip] ,
    RTRIM(LTRIM(c.emailAddress)) AS [EmailAddress] ,
    c.createDate AS [CreateDate] ,

    c2.socialSecurityNumber AS [DupSSN] ,
    RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 6, 4))) AS [F_DupSSn] ,
    c2.id AS [DupCustomerID] ,
    REPLACE(LTRIM(RTRIM(c2.firstName)), CHAR(13) + CHAR(10), ' ') AS [DupFirstName] ,
    REPLACE(LTRIM(RTRIM(c2.lastName)), CHAR(13) + CHAR(10), ' ') AS [DupLastName] ,
    c2.birthDate AS [DupBirthDate] ,
    MAX(co2.orderDate) AS [DupLastOrderDate] ,
    RTRIM(LTRIM(ca2.street1)) AS [DupAddr1] ,
    RTRIM(LTRIM(ca2.city)) AS [DupCity] ,
    ca2.stateAndTerritoriesID AS [DupState] ,
    ca2.zipCode5 AS [DupZip] ,
    RTRIM(LTRIM(c2.emailAddress)) AS [DupEmailAddress] ,
    c2.createDate AS [DupCreateDate]

FROM    dbo.Customers AS [c]
    INNER JOIN dbo.Customers AS [c2] ON ( SUBSTRING(c.socialSecurityNumber,6,4) = SUBSTRING(c2.socialSecurityNumber,6,4) AND c.birthDate = c2.birthDate AND c.lastName = c2.lastName AND c.id <> c2.id )
    INNER JOIN dbo.CustomerAddresses AS [ca] ON c.id = ca.customerID
    INNER JOIN dbo.CustomerAddresses AS [ca2] ON c2.id = ca2.customerID
    INNER JOIN dbo.Common_Orders AS [co] ON co.customerID = c.id
    INNER JOIN dbo.Common_Orders AS [co2] ON co2.customerID = c2.id
WHERE   c.customerStatusTypeID <> 'M'
    AND c2.customerStatusTypeID <> 'M'
    AND ca.addressType <> 'M'
    AND ca2.addressType <> 'M'
    AND c.mergedTo IS NULL
    AND c2.mergedTo IS NULL
    AND CAST(co.orderDate AS DATE) >= '3/1/2017'
    AND CAST(co.orderDate AS DATE) <= '3/31/2017'
GROUP BY c.socialSecurityNumber ,
    RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(c.socialSecurityNumber, 6, 4))) ,
    c.id ,
    REPLACE(LTRIM(RTRIM(c.firstName)), CHAR(13) + CHAR(10), ' ') ,
    REPLACE(LTRIM(RTRIM(c.lastName)), CHAR(13) + CHAR(10), ' ') ,
    c.birthDate ,
    RTRIM(LTRIM(CA.street1)) ,
    RTRIM(LTRIM(CA.city)) ,
    CA.stateAndTerritoriesID ,
    CA.zipCode5 ,
    RTRIM(LTRIM(c.emailAddress)) ,
    c.createDate ,

    c2.socialSecurityNumber ,
    RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 1, 3))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 4, 2))) + '-' + RTRIM(LTRIM(SUBSTRING(C2.socialSecurityNumber, 6, 4))) ,
    c2.id ,
    REPLACE(LTRIM(RTRIM(c2.firstName)), CHAR(13) + CHAR(10), ' ') ,
    REPLACE(LTRIM(RTRIM(c2.lastName)), CHAR(13) + CHAR(10), ' ') ,
    c2.birthDate ,
    RTRIM(LTRIM(ca2.street1)) ,
    RTRIM(LTRIM(ca2.city)) ,
    ca2.stateAndTerritoriesID ,
    ca2.zipCode5 ,
    RTRIM(LTRIM(c2.emailAddress)) ,
    c2.createDate
)
-- Use a CTE to cross apply or unpivot the potential duplicates into separate rows
SELECT  ca.SSNRanking ,
    ca.SSN ,
    ca.F_SSN ,
    ca.CustomerID ,
    ca.FirstName ,
    ca.LastName ,
    ca.BirthDate ,
    ca.LastOrderDate ,
    ca.Addr1 ,
    ca.City ,
    ca.[State] ,
    ca.Zip ,
    ca.EmailAddress ,
    ca.CreateDate
INTO    #DupSSN

FROM cte
CROSS APPLY
(
VALUES
( cte.SSNRanking, cte.SSN,    cte.F_SSN, cte.CustomerID,    cte.FirstName,    cte.LastName,    cte.BirthDate,    cte.LastOrderDate,   cte.Addr1,    cte.City,    cte.[State],  cte.Zip,    cte.EmailAddress,    cte.CreateDate ) ,
( cte.SSNRanking, cte.DupSSN, cte.F_SSN, cte.DupCustomerID, cte.DupFirstName, cte.DupLastName, cte.DupBirthDate, cte.DupLastOrderDate,cte.DupAddr1, cte.DupCity, cte.DupState, cte.DupZip, cte.DupEmailAddress, cte.DupCreateDate )
) AS ca (SSNRanking, SSN, F_SSN, CustomerID, FirstName, LastName, BirthDate, LastOrderDate, Addr1, City, State, Zip, EmailAddress, CreateDate)
ORDER BY CAST(ca.SSN AS INT) ASC, ca.CustomerID;

-- Use CTE to create ROW_NUMBER function to eliminate duplicate records
WITH SSN_RN AS
(
SELECT  SSNRanking ,
    ROW_NUMBER() OVER ( PARTITION BY SSN, CustomerID, FirstName, LastName, BirthDate, LastOrderDate, Addr1, City, CreateDate ORDER BY ( SELECT NULL ) ) AS [RowNumber] ,
    SSN ,
    F_SSN ,
    CustomerID ,
    FirstName ,
    LastName ,
    BirthDate ,
    LastOrderDate ,
    Addr1 ,
    City ,
    State ,
    Zip ,
    EmailAddress ,
    CreateDate
FROM    #DupSSN
)
SELECT  SSN_RN.SSNRanking ,
    SSN_RN.RowNumber ,
    SSN_RN.SSN ,
    SSN_RN.F_SSN ,
    SSN_RN.CustomerID ,
    SSN_RN.FirstName ,
    SSN_RN.LastName ,
    SSN_RN.BirthDate ,
    SSN_RN.LastOrderDate ,
    SSN_RN.Addr1 ,
    SSN_RN.City ,
    SSN_RN.State ,
    SSN_RN.Zip ,
    SSN_RN.EmailAddress ,
    SSN_RN.CreateDate
FROM    SSN_RN
WHERE   SSN_RN.RowNumber = 1
ORDER BY CAST(SSN_RN.SSN AS INT) ASC ,
    SSN_RN.CustomerID;

DROP TABLE #DupSSN;


来源: stackexchange

问:
Draw Graph curves with UIBezierPath
I'm drawing a graph in my application. My problem is that I want to draw line joining vertex points as curves. Currently I'm drawing them with UIBezierPath's function addLineToPoint:. I want to draw them as curves. I'm well aware that UIBezierPath has following two functions to support this feature.

Cubic curve:addCurveToPoint:controlPoint1:controlPoint2:
Quadratic curve:addQuadCurveToPoint:controlPoint:

But problem is that I don't have control points. All i have is two end points. Neither I found a method/formula to determine control points. Can anyone help me here? I will appreciate if someone can suggest some alternative...

答:
While analyzing the code from @roman-filippov, I simplified the code some. Here's a complete Swift playground version, and an ObjC version below that.

I found that if x increments are not regular, then the original algorithm creates some unfortunate retrograde lines when points are close together on the x axis. Simply constraining the control points to not exceed the following x-value seems to fix the problem, although I have no mathematical justification for this, just experimentation. There are two sections marked as //**added` which implement this change.

```<code>import UIKit
import PlaygroundSupport

infix operator °
func °(x: CGFloat, y: CGFloat) -> CGPoint {
    return CGPoint(x: x, y: y)
}

extension UIBezierPath {
    func drawPoint(point: CGPoint, color: UIColor, radius: CGFloat) {
        let ovalPath = UIBezierPath(ovalIn: CGRect(x: point.x - radius, y: point.y - radius, width: radius * 2, height: radius * 2))
        color.setFill()
        ovalPath.fill()
    }

    func drawWithLine (point: CGPoint, color: UIColor) {
        let startP = self.currentPoint
        self.addLine(to: point)
        drawPoint(point: point, color: color, radius: 3)
        self.move(to: startP)
    }

}

class TestView : UIView {
    var step: CGFloat = 1.0;
    var yMaximum: CGFloat = 1.0
    var xMaximum: CGFloat = 1.0
    var data: [CGPoint] = [] {
        didSet {
            xMaximum = data.reduce(-CGFloat.greatestFiniteMagnitude, { max($0, $1.x) })
            yMaximum = data.reduce(-CGFloat.greatestFiniteMagnitude, { max($0, $1.y) })
            setNeedsDisplay()
        }
    }

    func scale(point: CGPoint) -> CGPoint {
        return  CGPoint(x: bounds.width * point.x / xMaximum ,
                        y: (bounds.height - bounds.height * point.y / yMaximum))
    }

    override func draw(_ rect: CGRect) {
        if data.count <= 1 {
            return
        }
        let path = cubicCurvedPath()

        UIColor.black.setStroke()
        path.lineWidth = 1
        path.stroke()
    }

    func cubicCurvedPath() -> UIBezierPath {
        let path = UIBezierPath()

        var p1 = scale(point: data[0])
        path.drawPoint(point: p1, color: UIColor.red, radius: 3)
        path.move(to: p1)
        var oldControlP = p1

        for i in 0..<data.count {
            let p2 = scale(point:data[i])
            path.drawPoint(point: p2, color: UIColor.red, radius: 3)
            var p3: CGPoint? = nil
            if i < data.count - 1 {
                p3 = scale(point:data [i+1])
            }

            let newControlP = controlPointForPoints(p1: p1, p2: p2, p3: p3)
            //uncomment the following four lines to graph control points
            //if let controlP = newControlP {
            //    path.drawWithLine(point:controlP, color: UIColor.blue)
            //}
            //path.drawWithLine(point:oldControlP, color: UIColor.gray)

            path.addCurve(to: p2, controlPoint1: oldControlP , controlPoint2: newControlP ?? p2)
            oldControlP = imaginFor(point1: newControlP, center: p2) ?? p1
            //***added to algorithm
            if let p3 = p3 {
                if oldControlP.x > p3.x { oldControlP.x = p3.x }
            }
            //***
            p1 = p2
        }
        return path;
    }

    func imaginFor(point1: CGPoint?, center: CGPoint?) -> CGPoint? {
        //returns "mirror image" of point: the point that is symmetrical through center.
        //aka opposite of midpoint; returns the point whose midpoint with point1 is center)
        guard let p1 = point1, let center = center else {
            return nil
        }
        let newX = center.x + center.x - p1.x
        let newY = center.y + center.y - p1.y

        return CGPoint(x: newX, y: newY)
    }

    func midPointForPoints(p1: CGPoint, p2: CGPoint) -> CGPoint {
        return CGPoint(x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2);
    }

    func clamp(num: CGFloat, bounds1: CGFloat, bounds2: CGFloat) -> CGFloat {
        //ensure num is between bounds.
        if (bounds1 < bounds2) {
            return min(max(bounds1,num),bounds2);
        } else {
            return min(max(bounds2,num),bounds1);
        }
    }

    func controlPointForPoints(p1: CGPoint, p2: CGPoint, p3: CGPoint?) -> CGPoint? {
        guard let p3 = p3 else {
            return nil
        }

        let leftMidPoint  = midPointForPoints(p1: p1, p2: p2)
        let rightMidPoint = midPointForPoints(p1: p2, p2: p3)
        let imaginPoint = imaginFor(point1: rightMidPoint, center: p2)

        var controlPoint = midPointForPoints(p1: leftMidPoint, p2: imaginPoint!)

        controlPoint.y = clamp(num: controlPoint.y, bounds1: p1.y, bounds2: p2.y)

        let flippedP3 = p2.y + (p2.y-p3.y)

        controlPoint.y = clamp(num: controlPoint.y, bounds1: p2.y, bounds2: flippedP3);
        //***added:
        controlPoint.x = clamp (num:controlPoint.x, bounds1: p1.x, bounds2: p2.x)
        //***
        // print ("p1: \(p1), p2: \(p2), p3: \(p3), LM:\(leftMidPoint), RM:\(rightMidPoint), IP:\(imaginPoint), fP3:\(flippedP3), CP:\(controlPoint)")
        return controlPoint
    }

}

let u = TestView(frame: CGRect(x: 0, y: 0, width: 700, height: 600));
u.backgroundColor = UIColor.white

PlaygroundPage.current.liveView = u
u.data = [0.5 ° 1, 1 ° 3, 2 ° 5, 4 ° 9, 8 ° 15, 9.4 ° 8, 9.5 ° 10, 12 ° 4, 13 ° 10, 15 ° 3, 16 ° 1]
</code>```

And the same code in ObjC (more or less. this doesn't include the drawing routines themselves, and it does allow the points array to include missing data

```<code>+ (UIBezierPath *)pathWithPoints:(NSArray <NSValue *> *)points open:(BOOL) open {
    //based on Roman Filippov code: http://stackoverflow.com/a/40203583/580850
    //open means allow gaps in path.
    UIBezierPath *path = [UIBezierPath bezierPath];
    CGPoint p1 = [points[0] CGPointValue];
    [path moveToPoint:p1];
    CGPoint oldControlPoint = p1;
    for (NSUInteger pointIndex = 1; pointIndex< points.count; pointIndex++) {
        CGPoint p2 = [points[pointIndex]  CGPointValue];  //note: mark missing data with CGFloatMax

        if (p1.y >= CGFloatMax || p2.y >= CGFloatMax) {
            if (open) {
                [path moveToPoint:p2];
            } else {
                [path addLineToPoint:p2];
            }
            oldControlPoint = p2;
        } else {
            CGPoint p3 = CGPointZero;
            if (pointIndex +1 < points.count) p3 = [points[pointIndex+1] CGPointValue] ;
            if (p3.y >= CGFloatMax) p3 = CGPointZero;
            CGPoint newControlPoint = controlPointForPoints2(p1, p2, p3);
            if (!CGPointEqualToPoint( newControlPoint, CGPointZero)) {
                [path addCurveToPoint: p2 controlPoint1:oldControlPoint controlPoint2: newControlPoint];
                oldControlPoint = imaginForPoints( newControlPoint,  p2);
                //**added to algorithm
                if (! CGPointEqualToPoint(p3,CGPointZero)) {
                   if (oldControlPoint.x > p3.x ) {
                       oldControlPoint.x = p3.x;
                   }
                //***
            } else {
                [path addCurveToPoint: p2 controlPoint1:oldControlPoint controlPoint2: p2];
                oldControlPoint = p2;
            }
        }
        p1 = p2;
    }
    return path;
}

static CGPoint imaginForPoints(CGPoint point, CGPoint center) {
    //returns "mirror image" of point: the point that is symmetrical through center.
    if (CGPointEqualToPoint(point, CGPointZero) || CGPointEqualToPoint(center, CGPointZero)) {
        return CGPointZero;
    }
    CGFloat newX = center.x + (center.x-point.x);
    CGFloat newY = center.y + (center.y-point.y);
    if (isinf(newY)) {
        newY = BEMNullGraphValue;
    }
    return CGPointMake(newX,newY);
}

static CGFloat clamp(CGFloat num, CGFloat bounds1, CGFloat bounds2) {
    //ensure num is between bounds.
    if (bounds1 < bounds2) {
        return MIN(MAX(bounds1,num),bounds2);
    } else {
        return MIN(MAX(bounds2,num),bounds1);
    }
}

static CGPoint controlPointForPoints2(CGPoint p1, CGPoint p2, CGPoint p3) {
    if (CGPointEqualToPoint(p3, CGPointZero)) return CGPointZero;
    CGPoint leftMidPoint = midPointForPoints(p1, p2);
    CGPoint rightMidPoint = midPointForPoints(p2, p3);
    CGPoint imaginPoint = imaginForPoints(rightMidPoint, p2);
    CGPoint controlPoint = midPointForPoints(leftMidPoint, imaginPoint);

    controlPoint.y = clamp(controlPoint.y, p1.y, p2.y);

    CGFloat flippedP3 = p2.y + (p2.y-p3.y);

    controlPoint.y = clamp(controlPoint.y, p2.y, flippedP3);
   //**added to algorithm
    controlPoint.x = clamp(controlPoint.x, p1.x, p2.x);
   //**
    return controlPoint;
}
</code>```

ContentLicense: CC BY-SA 3.0

Title: Draw Graph curves with UIBezierPath

Body:
While analyzing the code from @roman-filippov, I simplified the code some. Here's a complete Swift playground version, and an ObjC version below that.

I found that if x increments are not regular, then the original algorithm creates some unfortunate retrograde lines when points are close together on the x axis. Simply constraining the control points to not exceed the following x-value seems to fix the problem, although I have no mathematical justification for this, just experimentation. There are two sections marked as //**added` which implement this change.

import UIKit
import PlaygroundSupport

infix operator °
func °(x: CGFloat, y: CGFloat) -> CGPoint {
    return CGPoint(x: x, y: y)
}

extension UIBezierPath {
    func drawPoint(point: CGPoint, color: UIColor, radius: CGFloat) {
        let ovalPath = UIBezierPath(ovalIn: CGRect(x: point.x - radius, y: point.y - radius, width: radius * 2, height: radius * 2))
        color.setFill()
        ovalPath.fill()
    }

    func drawWithLine (point: CGPoint, color: UIColor) {
        let startP = self.currentPoint
        self.addLine(to: point)
        drawPoint(point: point, color: color, radius: 3)
        self.move(to: startP)
    }

}

class TestView : UIView {
    var step: CGFloat = 1.0;
    var yMaximum: CGFloat = 1.0
    var xMaximum: CGFloat = 1.0
    var data: [CGPoint] = [] {
        didSet {
            xMaximum = data.reduce(-CGFloat.greatestFiniteMagnitude, { max($0, $1.x) })
            yMaximum = data.reduce(-CGFloat.greatestFiniteMagnitude, { max($0, $1.y) })
            setNeedsDisplay()
        }
    }

    func scale(point: CGPoint) -> CGPoint {
        return  CGPoint(x: bounds.width * point.x / xMaximum ,
                        y: (bounds.height - bounds.height * point.y / yMaximum))
    }

    override func draw(_ rect: CGRect) {
        if data.count <= 1 {
            return
        }
        let path = cubicCurvedPath()

        UIColor.black.setStroke()
        path.lineWidth = 1
        path.stroke()
    }

    func cubicCurvedPath() -> UIBezierPath {
        let path = UIBezierPath()

        var p1 = scale(point: data[0])
        path.drawPoint(point: p1, color: UIColor.red, radius: 3)
        path.move(to: p1)
        var oldControlP = p1

        for i in 0..<data.count {
            let p2 = scale(point:data[i])
            path.drawPoint(point: p2, color: UIColor.red, radius: 3)
            var p3: CGPoint? = nil
            if i < data.count - 1 {
                p3 = scale(point:data [i+1])
            }

            let newControlP = controlPointForPoints(p1: p1, p2: p2, p3: p3)
            //uncomment the following four lines to graph control points
            //if let controlP = newControlP {
            //    path.drawWithLine(point:controlP, color: UIColor.blue)
            //}
            //path.drawWithLine(point:oldControlP, color: UIColor.gray)

            path.addCurve(to: p2, controlPoint1: oldControlP , controlPoint2: newControlP ?? p2)
            oldControlP = imaginFor(point1: newControlP, center: p2) ?? p1
            //***added to algorithm
            if let p3 = p3 {
                if oldControlP.x > p3.x { oldControlP.x = p3.x }
            }
            //***
            p1 = p2
        }
        return path;
    }

    func imaginFor(point1: CGPoint?, center: CGPoint?) -> CGPoint? {
        //returns "mirror image" of point: the point that is symmetrical through center.
        //aka opposite of midpoint; returns the point whose midpoint with point1 is center)
        guard let p1 = point1, let center = center else {
            return nil
        }
        let newX = center.x + center.x - p1.x
        let newY = center.y + center.y - p1.y

        return CGPoint(x: newX, y: newY)
    }

    func midPointForPoints(p1: CGPoint, p2: CGPoint) -> CGPoint {
        return CGPoint(x: (p1.x + p2.x) / 2, y: (p1.y + p2.y) / 2);
    }

    func clamp(num: CGFloat, bounds1: CGFloat, bounds2: CGFloat) -> CGFloat {
        //ensure num is between bounds.
        if (bounds1 < bounds2) {
            return min(max(bounds1,num),bounds2);
        } else {
            return min(max(bounds2,num),bounds1);
        }
    }

    func controlPointForPoints(p1: CGPoint, p2: CGPoint, p3: CGPoint?) -> CGPoint? {
        guard let p3 = p3 else {
            return nil
        }

        let leftMidPoint  = midPointForPoints(p1: p1, p2: p2)
        let rightMidPoint = midPointForPoints(p1: p2, p2: p3)
        let imaginPoint = imaginFor(point1: rightMidPoint, center: p2)

        var controlPoint = midPointForPoints(p1: leftMidPoint, p2: imaginPoint!)

        controlPoint.y = clamp(num: controlPoint.y, bounds1: p1.y, bounds2: p2.y)

        let flippedP3 = p2.y + (p2.y-p3.y)

        controlPoint.y = clamp(num: controlPoint.y, bounds1: p2.y, bounds2: flippedP3);
        //***added:
        controlPoint.x = clamp (num:controlPoint.x, bounds1: p1.x, bounds2: p2.x)
        //***
        // print ("p1: \(p1), p2: \(p2), p3: \(p3), LM:\(leftMidPoint), RM:\(rightMidPoint), IP:\(imaginPoint), fP3:\(flippedP3), CP:\(controlPoint)")
        return controlPoint
    }

}

let u = TestView(frame: CGRect(x: 0, y: 0, width: 700, height: 600));
u.backgroundColor = UIColor.white

PlaygroundPage.current.liveView = u
u.data = [0.5 ° 1, 1 ° 3, 2 ° 5, 4 ° 9, 8 ° 15, 9.4 ° 8, 9.5 ° 10, 12 ° 4, 13 ° 10, 15 ° 3, 16 ° 1]

And the same code in ObjC (more or less. this doesn't include the drawing routines themselves, and it does allow the points array to include missing data

+ (UIBezierPath *)pathWithPoints:(NSArray <NSValue *> *)points open:(BOOL) open {
    //based on Roman Filippov code: http://stackoverflow.com/a/40203583/580850
    //open means allow gaps in path.
    UIBezierPath *path = [UIBezierPath bezierPath];
    CGPoint p1 = [points[0] CGPointValue];
    [path moveToPoint:p1];
    CGPoint oldControlPoint = p1;
    for (NSUInteger pointIndex = 1; pointIndex< points.count; pointIndex++) {
        CGPoint p2 = [points[pointIndex]  CGPointValue];  //note: mark missing data with CGFloatMax

        if (p1.y >= CGFloatMax || p2.y >= CGFloatMax) {
            if (open) {
                [path moveToPoint:p2];
            } else {
                [path addLineToPoint:p2];
            }
            oldControlPoint = p2;
        } else {
            CGPoint p3 = CGPointZero;
            if (pointIndex +1 < points.count) p3 = [points[pointIndex+1] CGPointValue] ;
            if (p3.y >= CGFloatMax) p3 = CGPointZero;
            CGPoint newControlPoint = controlPointForPoints2(p1, p2, p3);
            if (!CGPointEqualToPoint( newControlPoint, CGPointZero)) {
                [path addCurveToPoint: p2 controlPoint1:oldControlPoint controlPoint2: newControlPoint];
                oldControlPoint = imaginForPoints( newControlPoint,  p2);
                //**added to algorithm
                if (! CGPointEqualToPoint(p3,CGPointZero)) {
                   if (oldControlPoint.x > p3.x ) {
                       oldControlPoint.x = p3.x;
                   }
                //***
            } else {
                [path addCurveToPoint: p2 controlPoint1:oldControlPoint controlPoint2: p2];
                oldControlPoint = p2;
            }
        }
        p1 = p2;
    }
    return path;
}

static CGPoint imaginForPoints(CGPoint point, CGPoint center) {
    //returns "mirror image" of point: the point that is symmetrical through center.
    if (CGPointEqualToPoint(point, CGPointZero) || CGPointEqualToPoint(center, CGPointZero)) {
        return CGPointZero;
    }
    CGFloat newX = center.x + (center.x-point.x);
    CGFloat newY = center.y + (center.y-point.y);
    if (isinf(newY)) {
        newY = BEMNullGraphValue;
    }
    return CGPointMake(newX,newY);
}

static CGFloat clamp(CGFloat num, CGFloat bounds1, CGFloat bounds2) {
    //ensure num is between bounds.
    if (bounds1 < bounds2) {
        return MIN(MAX(bounds1,num),bounds2);
    } else {
        return MIN(MAX(bounds2,num),bounds1);
    }
}

static CGPoint controlPointForPoints2(CGPoint p1, CGPoint p2, CGPoint p3) {
    if (CGPointEqualToPoint(p3, CGPointZero)) return CGPointZero;
    CGPoint leftMidPoint = midPointForPoints(p1, p2);
    CGPoint rightMidPoint = midPointForPoints(p2, p3);
    CGPoint imaginPoint = imaginForPoints(rightMidPoint, p2);
    CGPoint controlPoint = midPointForPoints(leftMidPoint, imaginPoint);

    controlPoint.y = clamp(controlPoint.y, p1.y, p2.y);

    CGFloat flippedP3 = p2.y + (p2.y-p3.y);

    controlPoint.y = clamp(controlPoint.y, p2.y, flippedP3);
   //**added to algorithm
    controlPoint.x = clamp(controlPoint.x, p1.x, p2.x);
   //**
    return controlPoint;
}


问:
Cannot hide Spinners ina ScrollView
Spinners do not get hidden after they pass the bounds of the scroll view for some reason. I know the problem is with the appcompat spinner because I tried other widgets (such as rey5137's spinner) and they work perfectly fine with the scroll view.

Here is the code:

```<code>    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.spinners.MainActivity">

    <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
        android:textSize="30sp"
        android:text="YOU SHALL NOT PASS !!!"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingEnd="5dp"
                    android:text="NormalSpinner:"/>
                <Spinner
                    android:layout_width="200dp"
                    android:layout_height="30dp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingEnd="5dp"
                    android:text="ReySpinner:"/>

                <com.rey.material.widget.Spinner
                    android:layout_width="200dp"
                    android:layout_height="30dp"
                    app:spn_dividerColor="@color/colorAccent"
                    style="@style/Material.Widget.Spinner"
                    app:rd_style="@style/Material.Drawable.Ripple.Wave"
                    />
            </LinearLayout>

            <!-- spamming the same spinner layout above -->
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingEnd="5dp"
                    android:text="NormalSpinner:"/>
                <Spinner
                    android:layout_width="200dp"
                    android:layout_height="30dp" />

            </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout>

        </LinearLayout>
    </ScrollView>
</LinearLayout>
</code>```

Here is pic of what is going on:
The issue

答: Appears to be (as of March 2017) a platform defect (see https://code.google.com/p/android/issues/detail?id=199453). You'll probably have to use one of the other spinner solutions until a bug fix is released.</p>

Title: Cannot hide Spinners ina ScrollView

Body:
Spinners do not get hidden after they pass the bounds of the scroll view for some reason. I know the problem is with the appcompat spinner because I tried other widgets (such as rey5137's spinner) and they work perfectly fine with the scroll view.

Here is the code:

    <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.spinners.MainActivity">

    <TextView android:layout_height="wrap_content" android:layout_width="wrap_content"
        android:textSize="30sp"
        android:text="YOU SHALL NOT PASS !!!"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="300dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingEnd="5dp"
                    android:text="NormalSpinner:"/>
                <Spinner
                    android:layout_width="200dp"
                    android:layout_height="30dp" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingEnd="5dp"
                    android:text="ReySpinner:"/>

                <com.rey.material.widget.Spinner
                    android:layout_width="200dp"
                    android:layout_height="30dp"
                    app:spn_dividerColor="@color/colorAccent"
                    style="@style/Material.Widget.Spinner"
                    app:rd_style="@style/Material.Drawable.Ripple.Wave"
                    />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal">

                <TextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:paddingEnd="5dp"
                    android:text="NormalSpinner:"/>
                <Spinner
                    android:layout_width="200dp"
                    android:layout_height="30dp" />

            </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout><LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:paddingEnd="5dp"
                android:text="NormalSpinner:"/>
            <Spinner
                android:layout_width="200dp"
                android:layout_height="30dp" />

        </LinearLayout>

        </LinearLayout>
    </ScrollView>
</LinearLayout>

Here is pic of what is going on:
The issue


问:
delete openshift git/objects folder
I am trying to clean up openshift git repo. objects folder in .git seems huge. I can ssh into application and execute the commands

```<code>git reflog expire --expire=now --all
git gc --prune=now --aggressive
</code>```

server is getting restarted while the command is being executed and the connection gets disconnected. The total size of objects folder is more than 3 GB for an application that should be less than 100 MB.
please advice. Thanks.

答:
git gc alone can increase the size of your repo.

I prefer:

```<code>git gc
git repack -Ad      # kills in-pack garbage
git prune           # kills loose garbage
</code>```

The reflog part can be used to remove unreferenced elements and would come first:

```<code>git reflog expire --expire-unreachable=now --all
git gc --prune=now
</code>```

Title: delete openshift git/objects folder

Body:
I am trying to clean up openshift git repo. objects folder in .git seems huge. I can ssh into application and execute the commands

git reflog expire --expire=now --all
git gc --prune=now --aggressive

server is getting restarted while the command is being executed and the connection gets disconnected. The total size of objects folder is more than 3 GB for an application that should be less than 100 MB.
please advice. Thanks.

Body:
git gc alone can increase the size of your repo.

I prefer:

git gc
git repack -Ad      # kills in-pack garbage
git prune           # kills loose garbage

The reflog part can be used to remove unreferenced elements and would come first:

git reflog expire --expire-unreachable=now --all
git gc --prune=now


问:
How to have a Text Area in my Web application?
I want to make a blog page in my web application. I want to have a large text area to enter atleast 300 words in my blog page. it should have spell check. making bold option. It should be like the s*ame window in StackOverFlow where am entering my question now*.

How to achieve this. Any suggestions Please?

答:
There are a few WSIWYG editors out there.  The one probably most-used is TinyMCE.

Personally, I prefer the YUI Rich Text Editor.

ContentLicense: CC BY-SA 2.5


问:
jQuery or CSS changing and fading background-position on hover
I have tried a few things but at this point now, i want to fadeout change background position and fadein but not working.... any ideas? or a better solution?

```<code>  $('.collection-hover a').on("mouseenter touchstart", function(event) {
    $(this).find('.collection-list-hover-desc').fadeIn(1000);
    $(this).animate({backgroundPosition: "-50% 100%"});
  });
  $('.collection-hover a').on("mouseleave touchend", function(event) {
    $(this).find('.collection-list-hover-desc').fadeOut(1000);
    $(this).animate({backgroundPosition: "0 0"});
  });
</code>```

snippet of html

```<code><li class="collection-list-item grid-item first collection-hover">
   <a href="/collections/butterfly-sofa" class="position-left" data-image="//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1491014401" style="background-image: url("//cdn.shopify.com/s/files/1/1839/7697/collections/category-panel-butterfly.jpg?v=1491014401"); height: 108.009px;">
  <div class="collection-list-hover-desc">

    <p>Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.</p>
  </div>
  <div class="collection-list-hover-button">
    <span class="button" style="
    padding: 5px 8px;
">Entdecken</span>
  </div>
</a>
</li>
</code>```

答:
You want to animate the background-position-x and background-position-y properties separately.

$('.collection-hover a').on("mouseenter touchstart", function(event) {
  $(this).find('.collection-list-hover-desc').fadeIn(1000);
  $(this).animate({
    'background-position-x': "-50%",
    'background-position-y': '100%'
  });
});
$('.collection-hover a').on("mouseleave touchend", function(event) {
  $(this).find('.collection-list-hover-desc').fadeOut(1000);
  $(this).animate({
    'background-position-x': "0",
    'background-position-y': "0",
  });
});```
<pre class="snippet-code-css lang-css prettyprint-override"><code>.collection-hover a {
  background: url('http://kenwheeler.github.io/slick/img/fonz1.png') 0 0 no-repeat;
  width: 100vw;
  height: 100vh;
  display: block;
}
.collection-list-hover-desc {
  display: none;
}</code>```

Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.

```

Body:
I have tried a few things but at this point now, i want to fadeout change background position and fadein but not working.... any ideas? or a better solution?

  $('.collection-hover a').on("mouseenter touchstart", function(event) {
    $(this).find('.collection-list-hover-desc').fadeIn(1000);
    $(this).animate({backgroundPosition: "-50% 100%"});
  });
  $('.collection-hover a').on("mouseleave touchend", function(event) {
    $(this).find('.collection-list-hover-desc').fadeOut(1000);
    $(this).animate({backgroundPosition: "0 0"});
  });

snippet of html

Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.

    Entdecken

Body:
You want to animate the background-position-x and background-position-y properties separately.

$('.collection-hover a').on("mouseenter touchstart", function(event) {
  $(this).find('.collection-list-hover-desc').fadeIn(1000);
  $(this).animate({
    'background-position-x': "-50%",
    'background-position-y': '100%'
  });
});
$('.collection-hover a').on("mouseleave touchend", function(event) {
  $(this).find('.collection-list-hover-desc').fadeOut(1000);
  $(this).animate({
    'background-position-x': "0",
    'background-position-y': "0",
  });
});

.collection-hover a {
  background: url('http://kenwheeler.github.io/slick/img/fonz1.png') 0 0 no-repeat;
  width: 100vw;
  height: 100vh;
  display: block;
}
.collection-list-hover-desc {
  display: none;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li class="collection-list-item grid-item first collection-hover">
  <a href="/collections/butterfly-sofa">
    <div class="collection-list-hover-desc">
    <p>Dein eigener Ruhepol in einer hektischen Welt. Der durch eine Struktur im Inneren formstabile Sitzsack vereint Komfort und Ästhetik.</p>
  </div>
  </a>
</li>


问:
Why aren't the numbers from my input file going into my array c++?
I am passing a text file of integers to a function by reference. They are separated by a new line. I am wanting to push them into a new array in the function. I can count the number of lines no problem, and I use that variable to create the array of that given size, so a vector is not necessary. But when I print what should be the contents of my array it is way off. Do I need to convert the integers from the file into int values again (since I am reading from a text file, is it reading them as strings?) Help?

C++ Code:

```<code>void myFunction(ifstream& infile)
{
    int NumberOfLines = 0;
    int index;
    string line;
    //Count the number of lines in the file
    if(infile.is_open())
    {
        while(getline(infile, line))
        {
            ++NumberOfLines;
        }
    }
    int arr[NumberOfLines];
    //Put the numbers into an array
    while(!infile.eof())
    {
        infile>>arr[NumberOfLines];
    }
    //Print the array
    for(int i=0; i<NumberOfLines; i++)
    {
        cout<<arr[i]<<endl;
    }
}
</code>```

答:
When you first scan the file, in order to count the lines, the ifstream position indicator reaches the end of the file.

In order to read the file again, you should reset the position indicator to the beginning, using:

infile.seekg(0, std::ios_base::beg);

More info: seekg, ifstream

Body:
I am passing a text file of integers to a function by reference. They are separated by a new line. I am wanting to push them into a new array in the function. I can count the number of lines no problem, and I use that variable to create the array of that given size, so a vector is not necessary. But when I print what should be the contents of my array it is way off. Do I need to convert the integers from the file into int values again (since I am reading from a text file, is it reading them as strings?) Help?

C++ Code:

void myFunction(ifstream& infile)
{
    int NumberOfLines = 0;
    int index;
    string line;
    //Count the number of lines in the file
    if(infile.is_open())
    {
        while(getline(infile, line))
        {
            ++NumberOfLines;
        }
    }
    int arr[NumberOfLines];
    //Put the numbers into an array
    while(!infile.eof())
    {
        infile>>arr[NumberOfLines];
    }
    //Print the array
    for(int i=0; i<NumberOfLines; i++)
    {
        cout<<arr[i]<<endl;
    }
}


问:
Variable inside selector - jQuery - this is tricky
I have a function:

```<code>function ConditionalMake( $makeselector, $modelselector ) {
 // my code in here
}
</code>```

I am initializing my function like this:

```<code>var make_selector = $('select#make');
var model_selector = $('select#model');
ConditionalMake( make_selector, model_selector );
</code>```

How can I use a variable inside a selector like this (obviously this does not work):

```<code>var chosen = $makeselector + 'option:selected'.text();
</code>```

When using my function without this variable it works fine, such as:

```<code>$('select#make option:selected').text();
</code>```

How do I add 'option:selected' to my selector which is already a variable which is a selector (hope that makes sense)?
Thanks for your answer.

答:
You're pretty close, all you need is the find function:

```<code>var chosen = $makeselector.find('option:selected').text();
</code>```

Alternatively, you can use .children().  But this may not work because it only searches immediate children of the current element.

```<code>var chosen = $makeselector.children('option:selected').text();
</code>```

Body:
I have a function:

function ConditionalMake( $makeselector, $modelselector ) {
 // my code in here
}

I am initializing my function like this:

var make_selector = $('select#make');
var model_selector = $('select#model');
ConditionalMake( make_selector, model_selector );

How can I use a variable inside a selector like this (obviously this does not work):

var chosen = $makeselector + 'option:selected'.text();

When using my function without this variable it works fine, such as:

$('select#make option:selected').text();

How do I add 'option:selected' to my selector which is already a variable which is a selector (hope that makes sense)?
Thanks for your answer.

Body:
You're pretty close, all you need is the find function:

var chosen = $makeselector.find('option:selected').text();

Alternatively, you can use .children().  But this may not work because it only searches immediate children of the current element.

var chosen = $makeselector.children('option:selected').text();


问:
GitBash VisualStudio Solution gitignore
I deleted gitignore and gitattributes files and used gitbash to -f commit everything and it put the obj, debug, etc files I don't want. So i want to recommit everything but also want the git ignore rules to be inforced.

答:
I want to recommit everything

Simply (in commandline) do a:

```<code>git reset @~
</code>```

That will reset HEAD to the previous commit, allowing you to re-add and commit what you want.

I deleted gitignore and gitattributes files

Restore at least the .gitignore file if you want gitignore rules to be enforced:

```<code>git checkout -- .gitignore
</code>```

Title: GitBash VisualStudio Solution gitignore

Body:
I want to recommit everything

Simply (in commandline) do a:

git reset @~

That will reset HEAD to the previous commit, allowing you to re-add and commit what you want.

I deleted gitignore and gitattributes files

Restore at least the .gitignore file if you want gitignore rules to be enforced:

git checkout -- .gitignore


问:
How to use Task Queue in GAE flexible env?
Currently I'm doing migration from GAE standard environment to flex environment. In the standard env app, we have included task queue and cron.

This ensures that we can use cron on flexible env but I'm unsure about the task queue.

答:
From the Task Queue section of Migrating Services from the Standard Environment to the Flexible Environment:

The Task Queue service has limited availability outside of the
  standard environment. If you want to use the service outside of the
  standard environment, you can sign up for the Cloud Tasks alpha.

Outside of the standard environment, you can't add tasks to push
  queues, but a service running in the flexible environment can be
  the target of a push task. You can specify this using the
  target parameter when adding a task to queue or by specifying
  the default target for the queue in queue.yaml.

In many cases where you might use pull queues, such as queuing up
  tasks or messages that will be pulled and processed by separate
  workers, Cloud Pub/Sub can be a good alternative as it offers
  similar functionality and delivery guarantees.


问:
Randomly Generate a Word from a txt.file (Python)
I have a text file of sentences. I need to randomly read strings and output the string and its line number in an output file. I have written the following code:

```<code>ifile = open("test2.txt", "r")
otfile = open("OUT3.txt", "w")
otfile.write("Randomly Selected String \t\t\t Line Number")

import random

i=0

for lines in ifile.readline():

  line = lines[i]

  words = line.split()
  myword = random.choice(words)

  otfile.write(myword)
  otfile.write(str(i))
  i +=1
  otfile.write("\n")
</code>```

However I am only getting one character and no line number. I have been trying to change the code but I am just creating errors. Any ideas?

(Edit)
Test2.txt has the following sentences:

```<code>Brooklyn is the best place on Earth.
I had chocolate ice cream today.
I ate all the cookies in the cookie jar.
Today was a no good very bad day.
He got his clothes dirty playing outside.
</code>```

答:
Another solution! Added a counter that counts the number of lines and outputs the count as lines.

```<code>ifile = open("text2.txt", "r")
otfile = open("OUT3.txt", "w")
otfile.write("")
lst = []
import random
count = 1 # count the number of lines. Starts at 1.
for lines in ifile.readlines():
   words = lines.split()
   lst.extend(words) # add all the words to a list using .extend method
   myword = random.choice(lst)
   otfile.write("Line:{} Word: {} ".format(count, myword))
   count += 1
</code>```

Out: Line:1 Word: the Line:2 Word: icecream Line:3 Word: chocolate Line:4 Word: the Line:5 Word: today. Line:6 Word: bad

Body:
I have a text file of sentences. I need to randomly read strings and output the string and its line number in an output file. I have written the following code:

ifile = open("test2.txt", "r")
otfile = open("OUT3.txt", "w")
otfile.write("Randomly Selected String \t\t\t Line Number")

import random

i=0

for lines in ifile.readline():

  line = lines[i]

  words = line.split()
  myword = random.choice(words)

  otfile.write(myword)
  otfile.write(str(i))
  i +=1
  otfile.write("\n")

However I am only getting one character and no line number. I have been trying to change the code but I am just creating errors. Any ideas?

(Edit)
Test2.txt has the following sentences:

Brooklyn is the best place on Earth.
I had chocolate ice cream today.
I ate all the cookies in the cookie jar.
Today was a no good very bad day.
He got his clothes dirty playing outside.

Body:
Another solution! Added a counter that counts the number of lines and outputs the count as lines.

ifile = open("text2.txt", "r")
otfile = open("OUT3.txt", "w")
otfile.write("")
lst = []
import random
count = 1 # count the number of lines. Starts at 1.
for lines in ifile.readlines():
   words = lines.split()
   lst.extend(words) # add all the words to a list using .extend method
   myword = random.choice(lst)
   otfile.write("Line:{} Word: {} ".format(count, myword))
   count += 1

Out: Line:1 Word: the Line:2 Word: icecream Line:3 Word: chocolate Line:4 Word: the Line:5 Word: today. Line:6 Word: bad


问:
Configure sublime text 3 folder node_modules for node.js
I need node_modules in the sidebar but not when searching files, "go to files".

If I use

```<code>{
  "folder_exclude_patterns": [ "node_modules"]
}
</code>```

It works ok except for the sidebar.

答:
Sublime text -> Preferences -> Settings->  opens a new window with all the program settings on the left and your user settings on the right.   You would add this line between the {} brackets - </p>

```<code>"binary_file_patterns": [".svn/", ".git/", "node_modules/", "bower_components/"]
</code>```

Body:
I need node_modules in the sidebar but not when searching files, "go to files".

If I use

{
  "folder_exclude_patterns": [ "node_modules"]
}

It works ok except for the sidebar.

Body:
Sublime text -> Preferences -> Settings->  opens a new window with all the program settings on the left and your user settings on the right.   You would add this line between the {} brackets -

"binary_file_patterns": [".svn/", ".git/", "node_modules/", "bower_components/"]


问:
Update table content in angularjs
i'm having trouble to update the data of a table after a ng-click. After i select an item on a combobox (dropdown), it doesn't update the table content. Here is my combobox:

```<code><!-- Combobox -->
        <div class="row">
        <div class="dropdown" ng-controller="StabPageCtrl">
            <button class="btn btn-default dropdown-toggle" type="button" id="dropdown_stabs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
                Estabelecimentos
                <span class="caret"></span>
            </button>
            <ul class="dropdown-menu" aria-labelledby="dropdown_stabs" >
                <li>
                    <a ng-repeat="estab in stablishmentList" ng-click="passdata(stab.stabId)">
                      {{estab.nomeEstab}}
                    </a>
                </li>
            </ul>
        </div>
        </div>
</code>```

Table with the ng-repeat:

```<code><table class="table table-hover" ng-controller="StabPageCtrl">
                    <thead>
                    <tr>
                        <th>Serviço</th>
                        <th>Descrição Serviço</th>
                        <th>Valor / Valor hora</th>
                        <th>Status</th>
                    </tr>
                    </thead>
                    <tbody ng-repeat="servico in listaDeServicos">
                    <tr>
                        <td>{{servico.nomeServico}}</td>
                        <td>{{servico.descServico}}</td>
                        <td>Valor: R${{servico.precoServico}} - Valor/Hora: R${{servico.precoHoraServico}}</td>
                        <td>VER FLAG DEPOIS</td>
                        <li ng-hide="listaDeServicos.length > 0">Lista vazia.</li>
                    </tr>
                    </tbody>
                </table>
</code>```

Controller:

```<code>angular.module('yapp').controller('StabPageCtrl', function($scope, $state, ListServicoService, ListStabService) {

/**
 * Controller do dropdown que escolhe o estabelecimento
 */
  $scope.passdata = function(id){
    console.log("ctrl: " + id);

    ListServicoService.listarServicos(id).then(function(dados){
      $scope.listaDeServicos = dados;

      console.log($scope.listaDeServicos);
    });
  }

/**
 * Controller que lista os estabelecimentos
 */
ListStabService.listAllStabs.then(function(estabs){
    $scope.stablishmentList = estabs;
}); });
</code>```

Service

```<code>angular.module('yapp')
.service('ListServicoService', function($http){
  return{
    listarServicos : function (id){
        console.log("serv: " + id);
        return $http.get('http://localhost:3854/listarServicosByEstab/' + id).then(function(response){
            return response.data;
        });
    }
}});
</code>```

答:
```

    ng-repeat="servico in listaDeServicos track by $index"

```

是你数据返回有重复值? 尝试一下上面办法,增加 track by $index

(English: Is your data returned with duplicate values? Try the above approach to add)

Title: Update table content in angularjs

Body:
i'm having trouble to update the data of a table after a ng-click. After i select an item on a combobox (dropdown), it doesn't update the table content. Here is my combobox:

            <button class="btn btn-default dropdown-toggle" type="button" id="dropdown_stabs" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
                Estabelecimentos

            </button>

                      {{estab.nomeEstab}}

Table with the ng-repeat:

                        Serviço
                        Descrição Serviço
                        Valor / Valor hora
                        Status

                        {{servico.nomeServico}}
                        {{servico.descServico}}
                        Valor: R${{servico.precoServico}} - Valor/Hora: R${{servico.precoHoraServico}}
                        VER FLAG DEPOIS

 0">Lista vazia.

Controller:

angular.module('yapp').controller('StabPageCtrl', function($scope, $state, ListServicoService, ListStabService) {

/**
 * Controller do dropdown que escolhe o estabelecimento
 */
  $scope.passdata = function(id){
    console.log("ctrl: " + id);

    ListServicoService.listarServicos(id).then(function(dados){
      $scope.listaDeServicos = dados;

      console.log($scope.listaDeServicos);
    });
  }

/**
 * Controller que lista os estabelecimentos
 */
ListStabService.listAllStabs.then(function(estabs){
    $scope.stablishmentList = estabs;
}); });

Service

angular.module('yapp')
.service('ListServicoService', function($http){
  return{
    listarServicos : function (id){
        console.log("serv: " + id);
        return $http.get('http://localhost:3854/listarServicosByEstab/' + id).then(function(response){
            return response.data;
        });
    }
}});

Body:
    ng-repeat="servico in listaDeServicos track by $index"

是你数据返回有重复值? 尝试一下上面办法,增加 track by $index

(English: Is your data returned with duplicate values? Try the above approach to add)


问:
add comma after thousand amount in javascript
I am using slide input with following javascript,

```<code><script type="text/javascript">
    jQuery(document).ready(function(e){
        var val1 = 0;
        var val2 = 0;
        $("#ex1").slider();
        $("#ex1").on("slide", function(slideEvt1) {
            //$("#ex1SliderVal").text((Number(slideEvt1.value) * 2.90) + (Number(val2) * 0.30));
            val1 = Number(slideEvt1.value);

            $("#ex1SliderVal").text((Number(val1) * 0.0290) + (Number(val2) * 0.30));

            $("#ex2SliderVal").text((Number(val1) * 0.0199) + (Number(val2) * 0.15));

            $("#ex3SliderVal").text((Number(val1) * 0.0225) + (Number(val2) * 0.10));

            $("#showex1").text(Number(val1));
            //console.log(val1)
        });
});
</script>

<div class="col-xs-12">
                <input id="ex1" type="text" data-slider-min="0000" data-slider-max="8000" data-slider-step="1" data-slider-value="0"/>
                <span><span style="margin-left: 30px; font-size:14px;"id="showex1">0</span></span>
            </div>
</code>```

This is working properly. Only thing I want to add a comma after thousands.
like 2,000 80,000 170,000

Please help me add this.
Thank you+

答:
How about this? just a little example

 var mynumber = document.getElementById("mynumber").innerHTML;
 mynumber = parseInt(mynumber);
 document.getElementById("mynumber-after").innerHTML = mynumber.toFixed(0).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");```
<pre class="snippet-code-html lang-html prettyprint-override"><code><div id="mynumber">80000</div>
<div id="mynumber-after"></div></code>```

Body:
I am using slide input with following javascript,

                <input id="ex1" type="text" data-slider-min="0000" data-slider-max="8000" data-slider-step="1" data-slider-value="0"/>
                0

This is working properly. Only thing I want to add a comma after thousands.
like 2,000 80,000 170,000

Please help me add this.
Thank you+

Body:
How about this? just a little example

 var mynumber = document.getElementById("mynumber").innerHTML;
 mynumber = parseInt(mynumber);
 document.getElementById("mynumber-after").innerHTML = mynumber.toFixed(0).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,");

<div id="mynumber">80000</div>
<div id="mynumber-after"></div>


问:
How to call a tabbed activity fragment from main activity?
I have selected a tabbed activity template with "Action bar tabs" in android studio.

Then i had created three fragments (One.java, Two.java, Three.java) one for each of the tabs.

I have the code related to the cursors in the second fragment.The thing is when i run the application the code in the second fragment is not being executed.

My question is will the fragment (Two.java) will be called implicitly or it is needed to call by creating an instance (if yes, how?).

code snippet for MainActivity.java

```<code> public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

       if(getArguments().getInt(ARG_SECTION_NUMBER)==1){
            View rootView = inflater.inflate(R.layout.fragment_one, container, false);

            return rootView;
        }
        else if (getArguments().getInt(ARG_SECTION_NUMBER) == 2) {
           View rootView = inflater.inflate(R.layout.fragment_two, container, false);
               return rootView;

           } else {
               View rootView = inflater.inflate(R.layout.fragment_three, container, false);
               return rootView;
           }
    }
</code>```

code snippet for Two.java

```<code>public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    logReader1 = new LogReader(getContext());
    db = logReader1.getReadableDatabase();
    Cursor logCursor = db.rawQuery("SELECT rowid _id,name,Time_Used,app_Image FROM logs ORDER BY Time_Used DESC", null);
    LogCursorAdapter logAdapter = new LogCursorAdapter((MainActivity) getContext(), logCursor);
    ListView log_Items = (ListView) container.findViewById(R.id.list_item);
    log_Items.setAdapter((logAdapter));
    return log_Items;

}
</code>```

答:
From what I can tell you aren't actually creating a new fragment. You're inflating the layout that you're intending to use as the layout for the fragment two.

Something like https://developer.android.com/training/implementing-navigation/lateral.html should get you pointed in the right direction. Notice how they create and return a fragment in the DemoCollectionPagerAdapter.

Body:
I have selected a tabbed activity template with "Action bar tabs" in android studio.

Then i had created three fragments (One.java, Two.java, Three.java) one for each of the tabs.

I have the code related to the cursors in the second fragment.The thing is when i run the application the code in the second fragment is not being executed.

My question is will the fragment (Two.java) will be called implicitly or it is needed to call by creating an instance (if yes, how?).

code snippet for MainActivity.java

 public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

       if(getArguments().getInt(ARG_SECTION_NUMBER)==1){
            View rootView = inflater.inflate(R.layout.fragment_one, container, false);

            return rootView;
        }
        else if (getArguments().getInt(ARG_SECTION_NUMBER) == 2) {
           View rootView = inflater.inflate(R.layout.fragment_two, container, false);
               return rootView;

           } else {
               View rootView = inflater.inflate(R.layout.fragment_three, container, false);
               return rootView;
           }
    }

code snippet for Two.java

public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    logReader1 = new LogReader(getContext());
    db = logReader1.getReadableDatabase();
    Cursor logCursor = db.rawQuery("SELECT rowid _id,name,Time_Used,app_Image FROM logs ORDER BY Time_Used DESC", null);
    LogCursorAdapter logAdapter = new LogCursorAdapter((MainActivity) getContext(), logCursor);
    ListView log_Items = (ListView) container.findViewById(R.id.list_item);
    log_Items.setAdapter((logAdapter));
    return log_Items;

}


问:
How to check if input is an enumeration type
I am reading input from the keyboard. The input is supposed to match one of the elements defined in an enumeration type. Here is an example of the enum type:

```<code>type NameType is (Bob, Jamie, Steve);
</code>```

If I receive an input that is not one of these 3, Ada raises an IO exception. How do I handle this to where I can simply display a "try again" message and not have the program stop?

答:
You might try an unchecked conversion to get the value into a variable of NameType then call 'valid on that variable.

Edit to include the example from ADAIC

```<code>with Ada.Unchecked_Conversion;
with Ada.Text_IO;
with Ada.Integer_Text_IO;

procedure Test is

   type Color is (Red, Yellow, Blue);
   for Color'Size use Integer'Size;

   function Integer_To_Color is
      new Ada.Unchecked_Conversion (Source => Integer,
                                    Target => Color);

   Possible_Color : Color;
   Number         : Integer;

begin  -- Test

   Ada.Integer_Text_IO.Get (Number);
   Possible_Color := Integer_To_Color (Number);

   if Possible_Color'Valid then
      Ada.Text_IO.Put_Line(Color'Image(Possible_Color));
   else
      Ada.Text_IO.Put_Line("Number does not correspond to a color.");
   end if;

end Test;
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I am reading input from the keyboard. The input is supposed to match one of the elements defined in an enumeration type. Here is an example of the enum type:

type NameType is (Bob, Jamie, Steve);

If I receive an input that is not one of these 3, Ada raises an IO exception. How do I handle this to where I can simply display a "try again" message and not have the program stop?

Body:
You might try an unchecked conversion to get the value into a variable of NameType then call 'valid on that variable.

Edit to include the example from ADAIC

with Ada.Unchecked_Conversion;
with Ada.Text_IO;
with Ada.Integer_Text_IO;

procedure Test is

   type Color is (Red, Yellow, Blue);
   for Color'Size use Integer'Size;

   function Integer_To_Color is
      new Ada.Unchecked_Conversion (Source => Integer,
                                    Target => Color);

   Possible_Color : Color;
   Number         : Integer;

begin  -- Test

   Ada.Integer_Text_IO.Get (Number);
   Possible_Color := Integer_To_Color (Number);

   if Possible_Color'Valid then
      Ada.Text_IO.Put_Line(Color'Image(Possible_Color));
   else
      Ada.Text_IO.Put_Line("Number does not correspond to a color.");
   end if;

end Test;