问:
Convolution using CUDA with Sobel Filter
So I have implemented (or at least tried to) a Sobel filter in CUDA and my code is as follows. When I execute this file, i get half of a correctly Sobel filtered image and the other half is black. I am not able to upload the pictures because they are in .pgm format. So what the code does is read in a grayscale image which is in .pgm format and convolves Sobel filter mask with it using shared memory concept. I used a 1024 by 1024 .pgm image as input and it return a Sobel filtered image with edges that has half of it cut horizontally so it is black in the bottom half. Can someone please help me out here. Also, I am a little curious about the code, I do not really understand what the second batch loading does, so can you please explain that too.

sobel.cu

```<code>/* sobel.cu */

#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <time.h>
#include "mypgm.h"

#define Mask_width  3
#define Mask_radius Mask_width/2
#define TILE_WIDTH 16
#define w (TILE_WIDTH + Mask_width - 1)
#define clamp(x) (min(max((x), 0.0), 1.0))

__global__ void convolution(float *I, const float* __restrict__ M, float *P, int width, int height) {
    __shared__ float N_ds[w][w];
    int k;

    // First batch loading
    int dest = threadIdx.y * TILE_WIDTH + threadIdx.x,
        destY = dest / w, destX = dest % w,
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius,
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius,
        src = srcY * width + srcX;
    if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
        N_ds[destY][destX] = I[src];
    else
        N_ds[destY][destX] = 0;
    for (int iter = 1; iter <= (w*w) / (TILE_WIDTH*TILE_WIDTH); iter++)
    {
        // Second batch loading
        dest = threadIdx.y * TILE_WIDTH + threadIdx.x + TILE_WIDTH * TILE_WIDTH;
        destY = dest / w, destX = dest % w;
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius;
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius;
        src = srcY * width + srcX;
        if (destY < w) {
            if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
                N_ds[destY][destX] = I[src];
            else
                N_ds[destY][destX] = 0;
        }
    }
    __syncthreads();

    float accum = 0;
    int y, x;
    for (y = 0; y < Mask_width; y++)
        for (x = 0; x < Mask_width; x++)
            accum += N_ds[threadIdx.y + y][threadIdx.x + x] * M[y * Mask_width + x];

    y = blockIdx.y * TILE_WIDTH + threadIdx.y;
    x = blockIdx.x * TILE_WIDTH + threadIdx.x;
    if (y < height && x < width)
        P[y * width + x] = accum;

    __syncthreads();

}

void sobel_filtering()
/* Spatial filtering of image data */
/* Sobel filter (horizontal differentiation */
/* Input: image1[y][x] ---- Outout: image2[y][x] */

{
    /* Definition of Sobel filter in horizontal direction */
    float weight[3][3] = { { -1,  0,  1 },
              { -2,  0,  2 },
              { -1,  0,  1 } };
    float pixel_value;

    int x, y, i, j;  /* Loop variable */
    float * deviceInputImageData;
    float * deviceOutputImageData;
    float * deviceMaskData;

    cudaMalloc((void **)&deviceInputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceOutputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceMaskData, 3 * 3 * sizeof(float));

    cudaMemcpy(deviceInputImageData, image1, x_size1 * y_size1 * sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(deviceMaskData, weight, 3 * 3 * sizeof(float), cudaMemcpyHostToDevice);

    /* Maximum values calculation after filtering*/
    printf("Now, filtering of input image is performed\n\n");
    x_size2 = x_size1;
    y_size2 = y_size1;
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            image2[y][x] = 0;
        }
    }

    dim3 dimGrid(ceil((float)x_size1 / TILE_WIDTH), ceil((float)y_size1 / TILE_WIDTH));
    dim3 dimBlock(TILE_WIDTH, TILE_WIDTH);
    convolution<<<dimGrid, dimBlock>>>(deviceInputImageData, deviceMaskData, deviceOutputImageData, x_size1, y_size1);

    cudaMemcpy(image2,
        deviceOutputImageData,
        x_size2 * y_size2 * sizeof(float),
        cudaMemcpyDeviceToHost);

    cudaFree(deviceInputImageData);
    cudaFree(deviceOutputImageData);
    cudaFree(deviceMaskData);

}

int main()
{
    load_image_data();   /* Input of image1 */

    clock_t begin = clock();
    sobel_filtering();   /* Sobel filter is applied to image1 */
    clock_t end = clock();
    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("\n\nTiming result of multiplication of matrix-vector: %f\n", time_spent);
    save_image_data();   /* Output of image2 */
    return 0;
}
</code>```

mypgm.h

```<code>/* pgm file IO headerfile ------ mypgm.h */

/* Constant declaration */

//#define MAX_IMAGESIZE  1024

#define MAX_IMAGEWIDTH  3840
#define MAX_IMAGEHEIGHT  2160
#define MAX_BRIGHTNESS  255 /* Maximum gray level */
#define GRAYLEVEL       256 /* No. of gray levels */
#define MAX_FILENAME    256 /* Filename length limit */
#define MAX_BUFFERSIZE  256

/* Global constant declaration */
/* Image storage arrays */
float image1[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT],
image2[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT];
int x_size1, y_size1, /* width & height of image1*/
x_size2, y_size2; /* width & height of image2 */

/* Prototype declaration of functions */
void load_image_data( ); /* image input */
void save_image_data( ); /* image output*/
void load_image_file(char *); /* image input */
void save_image_file(char *); /* image output*/

/* Main body of functions */

void load_image_data()
/* Input of header & body information of pgm file */
/* for image1[ ][ ]，x_size1，y_size1 */
{
    char file_name[MAX_FILENAME];
    char buffer[MAX_BUFFERSIZE];
    FILE *fp; /* File pointer */
    int max_gray; /* Maximum gray level */
    int x, y; /* Loop variable */

    /* Input file open */
    printf("\n-----------------------------------------------------\n");
    printf("Monochromatic image file input routine \n");
    printf("-----------------------------------------------------\n\n");
    printf("     Only pgm binary file is acceptable\n\n");
    printf("Name of input image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "rb");
    if (NULL == fp) {
        printf("     The file doesn't exist!\n\n");
        exit(1);
    }
    /* Check of file-type ---P5 */
    fgets(buffer, MAX_BUFFERSIZE, fp);
    if (buffer[0] != 'P' || buffer[1] != '5') {
        printf("     Mistaken file format, not P5!\n\n");
        exit(1);
    }
    /* input of x_size1, y_size1 */
    x_size1 = 0;
    y_size1 = 0;
    while (x_size1 == 0 || y_size1 == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d %d", &x_size1, &y_size1);
        }
    }
    /* input of max_gray */
    max_gray = 0;
    while (max_gray == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d", &max_gray);
        }
    }
    /* Display of parameters */
    printf("\n     Image width = %d, Image height = %d\n", x_size1, y_size1);
    printf("     Maximum gray level = %d\n\n", max_gray);
    if (x_size1 > MAX_IMAGEWIDTH || y_size1 > MAX_IMAGEHEIGHT) {
        printf("     Image size exceeds %d x %d\n\n",
            MAX_IMAGEWIDTH, MAX_IMAGEHEIGHT);
        printf("     Please use smaller images!\n\n");
        exit(1);
    }
    if (max_gray != MAX_BRIGHTNESS) {
        printf("     Invalid value of maximum gray level!\n\n");
        exit(1);
    }
    /* Input of image data*/
    for (y = 0; y < y_size1; y++) {
        for (x = 0; x < x_size1; x++) {
            image1[y][x] = (unsigned char)fgetc(fp);
        }
    }
    printf("-----Image data input OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

void save_image_data()
/* Output of image2[ ][ ], x_size2, y_size2 in pgm format*/

{
    char file_name[MAX_FILENAME];
    FILE *fp; /* File pointer */
    int x, y; /* Loop variable */

    /* Output file open */
    printf("-----------------------------------------------------\n");
    printf("Monochromatic image file output routine\n");
    printf("-----------------------------------------------------\n\n");
    printf("Name of output image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "wb");
    /* output of pgm file header information */
    fputs("P5\n", fp);
    fputs("# Created by Image Processing\n", fp);
    fprintf(fp, "%d %d\n", x_size2, y_size2);
    fprintf(fp, "%d\n", MAX_BRIGHTNESS);
    /* Output of image data */
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            fputc(image2[y][x], fp);
        }
    }
    printf("\n-----Image data output OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

void load_image_file(char *filename)
/* Input of header & body information of pgm file */
/* for image1[ ][ ]，x_size1，y_size1 */
{
    char buffer[MAX_BUFFERSIZE];
    FILE *fp; /* File pointer */
    int max_gray; /* Maximum gray level */
    int x, y; /* Loop variable */

    /* Input file open */
    fp = fopen(filename, "rb");
    if (NULL == fp) {
        printf("     The file doesn't exist!\n\n");
        exit(1);
    }
    /* Check of file-type ---P5 */
    fgets(buffer, MAX_BUFFERSIZE, fp);
    if (buffer[0] != 'P' || buffer[1] != '5') {
        printf("     Mistaken file format, not P5!\n\n");
        exit(1);
    }
    /* input of x_size1, y_size1 */
    x_size1 = 0;
    y_size1 = 0;
    while (x_size1 == 0 || y_size1 == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d %d", &x_size1, &y_size1);
        }
    }
    /* input of max_gray */
    max_gray = 0;
    while (max_gray == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d", &max_gray);
        }
    }
    if (x_size1 > MAX_IMAGEWIDTH || y_size1 > MAX_IMAGEHEIGHT) {
        printf("     Image size exceeds %d x %d\n\n",
            MAX_IMAGEWIDTH, MAX_IMAGEHEIGHT);
        printf("     Please use smaller images!\n\n");
        exit(1);
    }
    if (max_gray != MAX_BRIGHTNESS) {
        printf("     Invalid value of maximum gray level!\n\n");
        exit(1);
    }
    /* Input of image data*/
    for (y = 0; y < y_size1; y++) {
        for (x = 0; x < x_size1; x++) {
            image1[y][x] = (float)fgetc(fp);
        }
    }
    fclose(fp);
}

void save_image_file(char *filename)
/* Output of image2[ ][ ], x_size2, y_size2 */
/* into pgm file with header & body information */
{
    FILE *fp; /* File pointer */
    int x, y; /* Loop variable */

    fp = fopen(filename, "wb");
    /* output of pgm file header information */
    fputs("P5\n", fp);
    fputs("# Created by Image Processing\n", fp);
    fprintf(fp, "%d %d\n", x_size2, y_size2);
    fprintf(fp, "%d\n", MAX_BRIGHTNESS);
    /* Output of image data */
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            fputc(image2[y][x], fp);
        }
    }
    fclose(fp);
}
</code>```

答:
The reason you are only seeing part of the image is because you have a mismatch between your host image buffer sizes and your device image buffer sizes.

On the host, you have the image buffers defined like this:

```<code>#define MAX_IMAGEWIDTH  3840
#define MAX_IMAGEHEIGHT  2160
...
float image1[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT],
image2[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT];
</code>```

You then proceed to load a PGM image of dimensions 1024x1024.  You then create your device storage of size 1024x1024:

```<code>cudaMalloc((void **)&deviceInputImageData, x_size1 * y_size1 * sizeof(float));
cudaMalloc((void **)&deviceOutputImageData, x_size1 * y_size1 * sizeof(float));
</code>```

where x_size and y_size1 here are defined by your PGM load routine, which will be 1024 each for a 1024x1024 image.

Then when you do a copy from host to device (a similar problem occurs on device->host copy as well):

```<code>cudaMemcpy(deviceInputImageData, image1, x_size1 * y_size1 * sizeof(float), cudaMemcpyHostToDevice);
</code>```

you will be copying contiguous bytes from your host buffer to the device buffer.  This means each host buffer line up to the full width of MAX_IMAGEWIDTH are copied to the device.  But this is not really what you want.  You only want each host buffer line copied up to x_size1 copied to the device.

There are several possible ways to fix this.  I'm pretty sure the simplest would be simply to set MAX_IMAGEWIDTH and MAX_IMAGEHEIGHT to the actual values of the image you intend to use.  When I did that, I got a plausible looking filtered result.

Since this limits you to processing a single image size, a better approach would be to dynamically define the size of your host image buffers, after you have read the PGM header data.

Or you could also use a method that involves cudaMemcpy2D, but this seems needlessly complex.

Regarding your second question, the reason for the "second batch loading" is because the first batch load only loads shared memory up to the dimensions of the threadblock, so it loads a 16x16 "patch" of shared memory, one element per thread.  However we need the full shared memory array loaded, so we must do an extra "batch" of loading to fill the halo regions associated with the filter width and height.

Here is a modified file that seems to work correctly for me, demonstrating the method of dynamically allocating the host image buffers:

```<code>#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <time.h>

#define MAX_IMAGEWIDTH  2048
#define MAX_IMAGEHEIGHT 2048
#define MAX_BRIGHTNESS  255 /* Maximum gray level */
#define GRAYLEVEL       256 /* No. of gray levels */
#define MAX_FILENAME    256 /* Filename length limit */
#define MAX_BUFFERSIZE  256

/* Global constant declaration */
/* Image storage arrays */

float *image1, *image2;
int x_size1, y_size1, /* width & height of image1*/
x_size2, y_size2; /* width & height of image2 */

/* Prototype declaration of functions */
void load_image_data( ); /* image input */
void save_image_data( ); /* image output*/
void load_image_file(char *); /* image input */
void save_image_file(char *); /* image output*/

/* Main body of functions */

void load_image_data()
/* Input of header & body information of pgm file */
/* for image1[ ][ ]ï¼Œx_size1ï¼Œy_size1 */
{
    char file_name[MAX_FILENAME];
    char buffer[MAX_BUFFERSIZE];
    FILE *fp; /* File pointer */
    int max_gray; /* Maximum gray level */
    int x, y; /* Loop variable */

    /* Input file open */
    printf("\n-----------------------------------------------------\n");
    printf("Monochromatic image file input routine \n");
    printf("-----------------------------------------------------\n\n");
    printf("     Only pgm binary file is acceptable\n\n");
    printf("Name of input image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "rb");
    if (NULL == fp) {
        printf("     The file doesn't exist!\n\n");
        exit(1);
    }
    /* Check of file-type ---P5 */
    fgets(buffer, MAX_BUFFERSIZE, fp);
    if (buffer[0] != 'P' || buffer[1] != '5') {
        printf("     Mistaken file format, not P5!\n\n");
        exit(1);
    }
    /* input of x_size1, y_size1 */
    x_size1 = 0;
    y_size1 = 0;
    while (x_size1 == 0 || y_size1 == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d %d", &x_size1, &y_size1);
        }
    }
    /* input of max_gray */
    max_gray = 0;
    while (max_gray == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d", &max_gray);
        }
    }
    /* Display of parameters */
    printf("\n     Image width = %d, Image height = %d\n", x_size1, y_size1);
    printf("     Maximum gray level = %d\n\n", max_gray);
    if (x_size1 > MAX_IMAGEWIDTH || y_size1 > MAX_IMAGEHEIGHT) {
        printf("     Image size exceeds %d x %d\n\n",
            MAX_IMAGEWIDTH, MAX_IMAGEHEIGHT);
        printf("     Please use smaller images!\n\n");
        exit(1);
    }
    if (max_gray != MAX_BRIGHTNESS) {
        printf("     Invalid value of maximum gray level!\n\n");
        exit(1);
    }
    image1 = (float *)malloc(x_size1*y_size1*sizeof(float));
    /* Input of image data*/
    for (y = 0; y < y_size1; y++) {
        for (x = 0; x < x_size1; x++) {
            image1[y*x_size1+x] = (unsigned char)fgetc(fp);
        }
    }
    printf("-----Image data input OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

void save_image_data()
/* Output of image2[ ][ ], x_size2, y_size2 in pgm format*/

{
    char file_name[MAX_FILENAME];
    FILE *fp; /* File pointer */
    int x, y; /* Loop variable */

    /* Output file open */
    printf("-----------------------------------------------------\n");
    printf("Monochromatic image file output routine\n");
    printf("-----------------------------------------------------\n\n");
    printf("Name of output image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "wb");
    /* output of pgm file header information */
    fputs("P5\n", fp);
    fputs("# Created by Image Processing\n", fp);
    fprintf(fp, "%d %d\n", x_size2, y_size2);
    fprintf(fp, "%d\n", MAX_BRIGHTNESS);
    /* Output of image data */
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            fputc(image2[y*x_size2+x], fp);
        }
    }
    printf("\n-----Image data output OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

#define Mask_width  3
#define Mask_radius Mask_width/2
#define TILE_WIDTH 16
#define w (TILE_WIDTH + Mask_width - 1)
#define clamp(x) (min(max((x), 0.0), 1.0))

__global__ void convolution(float *I, const float* __restrict__ M, float *P, int width, int height) {
    __shared__ float N_ds[w][w];

    // First batch loading
    int dest = threadIdx.y * TILE_WIDTH + threadIdx.x,
        destY = dest / w, destX = dest % w,
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius,
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius,
        src = srcY * width + srcX;
    if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
        N_ds[destY][destX] = I[src];
    else
        N_ds[destY][destX] = 0;
    for (int iter = 1; iter <= (w*w) / (TILE_WIDTH*TILE_WIDTH); iter++)
    {
        // Second batch loading
        dest = threadIdx.y * TILE_WIDTH + threadIdx.x + TILE_WIDTH * TILE_WIDTH;
        destY = dest / w, destX = dest % w;
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius;
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius;
        src = srcY * width + srcX;
        if (destY < w) {
            if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
                N_ds[destY][destX] = I[src];
            else
                N_ds[destY][destX] = 0;
        }
    }
    __syncthreads();

    float accum = 0;
    int y, x;
    for (y = 0; y < Mask_width; y++)
        for (x = 0; x < Mask_width; x++)
            accum += N_ds[threadIdx.y + y][threadIdx.x + x] * M[y * Mask_width + x];

    y = blockIdx.y * TILE_WIDTH + threadIdx.y;
    x = blockIdx.x * TILE_WIDTH + threadIdx.x;
    if (y < height && x < width)
        P[y * width + x] = accum;

}

void sobel_filtering()
/* Spatial filtering of image data */
/* Sobel filter (horizontal differentiation */
/* Input: image1[y][x] ---- Outout: image2[y][x] */

{
    /* Definition of Sobel filter in horizontal direction */
    float weight[3][3] = { { -1,  0,  1 },
              { -2,  0,  2 },
              { -1,  0,  1 } };

    int x, y;  /* Loop variable */
    float * deviceInputImageData;
    float * deviceOutputImageData;
    float * deviceMaskData;

    cudaMalloc((void **)&deviceInputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceOutputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceMaskData, 3 * 3 * sizeof(float));

    cudaMemcpy(deviceInputImageData, image1, x_size1 * y_size1 * sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(deviceMaskData, weight, 3 * 3 * sizeof(float), cudaMemcpyHostToDevice);

    /* Maximum values calculation after filtering*/
    printf("Now, filtering of input image is performed\n\n");
    x_size2 = x_size1;
    y_size2 = y_size1;
    image2 = (float *)malloc(x_size2*y_size2*sizeof(float));
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            image2[y*x_size2+x] = 0;
        }
    }

    dim3 dimGrid(ceil((float)x_size1 / TILE_WIDTH), ceil((float)y_size1 / TILE_WIDTH));
    dim3 dimBlock(TILE_WIDTH, TILE_WIDTH);
    convolution<<<dimGrid, dimBlock>>>(deviceInputImageData, deviceMaskData, deviceOutputImageData, x_size1, y_size1);

    cudaMemcpy(image2,
        deviceOutputImageData,
        x_size2 * y_size2 * sizeof(float),
        cudaMemcpyDeviceToHost);

    cudaFree(deviceInputImageData);
    cudaFree(deviceOutputImageData);
    cudaFree(deviceMaskData);

}

int main()
{
    load_image_data();   /* Input of image1 */

    clock_t begin = clock();
    sobel_filtering();   /* Sobel filter is applied to image1 */
    clock_t end = clock();
    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("\n\nTiming result of multiplication of matrix-vector: %f\n", time_spent);
    save_image_data();   /* Output of image2 */
    return 0;
}
</code>```

Note the above code (your PGM load routine) has (IMO) a defect in that it requires the x and y sizes to be specified on the same line in the PGM file, but as far as I know this is not a requirement for P5 PGM files.  If you pass it a valid P5 PGM file that has x and y sizes specified on different lines in the file, it will hang.  I didn't attempt to fix that, as it doesn't appear to be the question you are asking.

Body:
So I have implemented (or at least tried to) a Sobel filter in CUDA and my code is as follows. When I execute this file, i get half of a correctly Sobel filtered image and the other half is black. I am not able to upload the pictures because they are in .pgm format. So what the code does is read in a grayscale image which is in .pgm format and convolves Sobel filter mask with it using shared memory concept. I used a 1024 by 1024 .pgm image as input and it return a Sobel filtered image with edges that has half of it cut horizontally so it is black in the bottom half. Can someone please help me out here. Also, I am a little curious about the code, I do not really understand what the second batch loading does, so can you please explain that too.

sobel.cu

/* sobel.cu */

#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <time.h>
#include "mypgm.h"

#define Mask_width  3
#define Mask_radius Mask_width/2
#define TILE_WIDTH 16
#define w (TILE_WIDTH + Mask_width - 1)
#define clamp(x) (min(max((x), 0.0), 1.0))

__global__ void convolution(float *I, const float* __restrict__ M, float *P, int width, int height) {
    __shared__ float N_ds[w][w];
    int k;

    // First batch loading
    int dest = threadIdx.y * TILE_WIDTH + threadIdx.x,
        destY = dest / w, destX = dest % w,
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius,
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius,
        src = srcY * width + srcX;
    if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
        N_ds[destY][destX] = I[src];
    else
        N_ds[destY][destX] = 0;
    for (int iter = 1; iter <= (w*w) / (TILE_WIDTH*TILE_WIDTH); iter++)
    {
        // Second batch loading
        dest = threadIdx.y * TILE_WIDTH + threadIdx.x + TILE_WIDTH * TILE_WIDTH;
        destY = dest / w, destX = dest % w;
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius;
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius;
        src = srcY * width + srcX;
        if (destY < w) {
            if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
                N_ds[destY][destX] = I[src];
            else
                N_ds[destY][destX] = 0;
        }
    }
    __syncthreads();

    float accum = 0;
    int y, x;
    for (y = 0; y < Mask_width; y++)
        for (x = 0; x < Mask_width; x++)
            accum += N_ds[threadIdx.y + y][threadIdx.x + x] * M[y * Mask_width + x];

    y = blockIdx.y * TILE_WIDTH + threadIdx.y;
    x = blockIdx.x * TILE_WIDTH + threadIdx.x;
    if (y < height && x < width)
        P[y * width + x] = accum;

    __syncthreads();

}

void sobel_filtering()
/* Spatial filtering of image data */
/* Sobel filter (horizontal differentiation */
/* Input: image1[y][x] ---- Outout: image2[y][x] */

{
    /* Definition of Sobel filter in horizontal direction */
    float weight[3][3] = { { -1,  0,  1 },
              { -2,  0,  2 },
              { -1,  0,  1 } };
    float pixel_value;

    int x, y, i, j;  /* Loop variable */
    float * deviceInputImageData;
    float * deviceOutputImageData;
    float * deviceMaskData;

    cudaMalloc((void **)&deviceInputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceOutputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceMaskData, 3 * 3 * sizeof(float));

    cudaMemcpy(deviceInputImageData, image1, x_size1 * y_size1 * sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(deviceMaskData, weight, 3 * 3 * sizeof(float), cudaMemcpyHostToDevice);

    /* Maximum values calculation after filtering*/
    printf("Now, filtering of input image is performed\n\n");
    x_size2 = x_size1;
    y_size2 = y_size1;
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            image2[y][x] = 0;
        }
    }

    dim3 dimGrid(ceil((float)x_size1 / TILE_WIDTH), ceil((float)y_size1 / TILE_WIDTH));
    dim3 dimBlock(TILE_WIDTH, TILE_WIDTH);
    convolution<<<dimGrid, dimBlock>>>(deviceInputImageData, deviceMaskData, deviceOutputImageData, x_size1, y_size1);

    cudaMemcpy(image2,
        deviceOutputImageData,
        x_size2 * y_size2 * sizeof(float),
        cudaMemcpyDeviceToHost);

    cudaFree(deviceInputImageData);
    cudaFree(deviceOutputImageData);
    cudaFree(deviceMaskData);

}

int main()
{
    load_image_data();   /* Input of image1 */

    clock_t begin = clock();
    sobel_filtering();   /* Sobel filter is applied to image1 */
    clock_t end = clock();
    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("\n\nTiming result of multiplication of matrix-vector: %f\n", time_spent);
    save_image_data();   /* Output of image2 */
    return 0;
}

mypgm.h

/* pgm file IO headerfile ------ mypgm.h */

/* Constant declaration */

//#define MAX_IMAGESIZE  1024

#define MAX_IMAGEWIDTH  3840
#define MAX_IMAGEHEIGHT  2160
#define MAX_BRIGHTNESS  255 /* Maximum gray level */
#define GRAYLEVEL       256 /* No. of gray levels */
#define MAX_FILENAME    256 /* Filename length limit */
#define MAX_BUFFERSIZE  256

/* Global constant declaration */
/* Image storage arrays */
float image1[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT],
image2[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT];
int x_size1, y_size1, /* width & height of image1*/
x_size2, y_size2; /* width & height of image2 */

/* Prototype declaration of functions */
void load_image_data( ); /* image input */
void save_image_data( ); /* image output*/
void load_image_file(char *); /* image input */
void save_image_file(char *); /* image output*/

/* Main body of functions */

void load_image_data()
/* Input of header & body information of pgm file */
/* for image1[ ][ ]，x_size1，y_size1 */
{
    char file_name[MAX_FILENAME];
    char buffer[MAX_BUFFERSIZE];
    FILE *fp; /* File pointer */
    int max_gray; /* Maximum gray level */
    int x, y; /* Loop variable */

    /* Input file open */
    printf("\n-----------------------------------------------------\n");
    printf("Monochromatic image file input routine \n");
    printf("-----------------------------------------------------\n\n");
    printf("     Only pgm binary file is acceptable\n\n");
    printf("Name of input image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "rb");
    if (NULL == fp) {
        printf("     The file doesn't exist!\n\n");
        exit(1);
    }
    /* Check of file-type ---P5 */
    fgets(buffer, MAX_BUFFERSIZE, fp);
    if (buffer[0] != 'P' || buffer[1] != '5') {
        printf("     Mistaken file format, not P5!\n\n");
        exit(1);
    }
    /* input of x_size1, y_size1 */
    x_size1 = 0;
    y_size1 = 0;
    while (x_size1 == 0 || y_size1 == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d %d", &x_size1, &y_size1);
        }
    }
    /* input of max_gray */
    max_gray = 0;
    while (max_gray == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d", &max_gray);
        }
    }
    /* Display of parameters */
    printf("\n     Image width = %d, Image height = %d\n", x_size1, y_size1);
    printf("     Maximum gray level = %d\n\n", max_gray);
    if (x_size1 > MAX_IMAGEWIDTH || y_size1 > MAX_IMAGEHEIGHT) {
        printf("     Image size exceeds %d x %d\n\n",
            MAX_IMAGEWIDTH, MAX_IMAGEHEIGHT);
        printf("     Please use smaller images!\n\n");
        exit(1);
    }
    if (max_gray != MAX_BRIGHTNESS) {
        printf("     Invalid value of maximum gray level!\n\n");
        exit(1);
    }
    /* Input of image data*/
    for (y = 0; y < y_size1; y++) {
        for (x = 0; x < x_size1; x++) {
            image1[y][x] = (unsigned char)fgetc(fp);
        }
    }
    printf("-----Image data input OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

void save_image_data()
/* Output of image2[ ][ ], x_size2, y_size2 in pgm format*/

{
    char file_name[MAX_FILENAME];
    FILE *fp; /* File pointer */
    int x, y; /* Loop variable */

    /* Output file open */
    printf("-----------------------------------------------------\n");
    printf("Monochromatic image file output routine\n");
    printf("-----------------------------------------------------\n\n");
    printf("Name of output image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "wb");
    /* output of pgm file header information */
    fputs("P5\n", fp);
    fputs("# Created by Image Processing\n", fp);
    fprintf(fp, "%d %d\n", x_size2, y_size2);
    fprintf(fp, "%d\n", MAX_BRIGHTNESS);
    /* Output of image data */
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            fputc(image2[y][x], fp);
        }
    }
    printf("\n-----Image data output OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

void load_image_file(char *filename)
/* Input of header & body information of pgm file */
/* for image1[ ][ ]，x_size1，y_size1 */
{
    char buffer[MAX_BUFFERSIZE];
    FILE *fp; /* File pointer */
    int max_gray; /* Maximum gray level */
    int x, y; /* Loop variable */

    /* Input file open */
    fp = fopen(filename, "rb");
    if (NULL == fp) {
        printf("     The file doesn't exist!\n\n");
        exit(1);
    }
    /* Check of file-type ---P5 */
    fgets(buffer, MAX_BUFFERSIZE, fp);
    if (buffer[0] != 'P' || buffer[1] != '5') {
        printf("     Mistaken file format, not P5!\n\n");
        exit(1);
    }
    /* input of x_size1, y_size1 */
    x_size1 = 0;
    y_size1 = 0;
    while (x_size1 == 0 || y_size1 == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d %d", &x_size1, &y_size1);
        }
    }
    /* input of max_gray */
    max_gray = 0;
    while (max_gray == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d", &max_gray);
        }
    }
    if (x_size1 > MAX_IMAGEWIDTH || y_size1 > MAX_IMAGEHEIGHT) {
        printf("     Image size exceeds %d x %d\n\n",
            MAX_IMAGEWIDTH, MAX_IMAGEHEIGHT);
        printf("     Please use smaller images!\n\n");
        exit(1);
    }
    if (max_gray != MAX_BRIGHTNESS) {
        printf("     Invalid value of maximum gray level!\n\n");
        exit(1);
    }
    /* Input of image data*/
    for (y = 0; y < y_size1; y++) {
        for (x = 0; x < x_size1; x++) {
            image1[y][x] = (float)fgetc(fp);
        }
    }
    fclose(fp);
}

void save_image_file(char *filename)
/* Output of image2[ ][ ], x_size2, y_size2 */
/* into pgm file with header & body information */
{
    FILE *fp; /* File pointer */
    int x, y; /* Loop variable */

    fp = fopen(filename, "wb");
    /* output of pgm file header information */
    fputs("P5\n", fp);
    fputs("# Created by Image Processing\n", fp);
    fprintf(fp, "%d %d\n", x_size2, y_size2);
    fprintf(fp, "%d\n", MAX_BRIGHTNESS);
    /* Output of image data */
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            fputc(image2[y][x], fp);
        }
    }
    fclose(fp);
}

Body:
The reason you are only seeing part of the image is because you have a mismatch between your host image buffer sizes and your device image buffer sizes.

On the host, you have the image buffers defined like this:

#define MAX_IMAGEWIDTH  3840
#define MAX_IMAGEHEIGHT  2160
...
float image1[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT],
image2[MAX_IMAGEWIDTH][MAX_IMAGEHEIGHT];

You then proceed to load a PGM image of dimensions 1024x1024.  You then create your device storage of size 1024x1024:

cudaMalloc((void **)&deviceInputImageData, x_size1 * y_size1 * sizeof(float));
cudaMalloc((void **)&deviceOutputImageData, x_size1 * y_size1 * sizeof(float));

where x_size and y_size1 here are defined by your PGM load routine, which will be 1024 each for a 1024x1024 image.

Then when you do a copy from host to device (a similar problem occurs on device->host copy as well):

cudaMemcpy(deviceInputImageData, image1, x_size1 * y_size1 * sizeof(float), cudaMemcpyHostToDevice);

you will be copying contiguous bytes from your host buffer to the device buffer.  This means each host buffer line up to the full width of MAX_IMAGEWIDTH are copied to the device.  But this is not really what you want.  You only want each host buffer line copied up to x_size1 copied to the device.

There are several possible ways to fix this.  I'm pretty sure the simplest would be simply to set MAX_IMAGEWIDTH and MAX_IMAGEHEIGHT to the actual values of the image you intend to use.  When I did that, I got a plausible looking filtered result.

Since this limits you to processing a single image size, a better approach would be to dynamically define the size of your host image buffers, after you have read the PGM header data.

Or you could also use a method that involves cudaMemcpy2D, but this seems needlessly complex.

Regarding your second question, the reason for the "second batch loading" is because the first batch load only loads shared memory up to the dimensions of the threadblock, so it loads a 16x16 "patch" of shared memory, one element per thread.  However we need the full shared memory array loaded, so we must do an extra "batch" of loading to fill the halo regions associated with the filter width and height.

Here is a modified file that seems to work correctly for me, demonstrating the method of dynamically allocating the host image buffers:

#include <stdio.h>
#include <stdlib.h>
#include <float.h>
#include <time.h>

#define MAX_IMAGEWIDTH  2048
#define MAX_IMAGEHEIGHT 2048
#define MAX_BRIGHTNESS  255 /* Maximum gray level */
#define GRAYLEVEL       256 /* No. of gray levels */
#define MAX_FILENAME    256 /* Filename length limit */
#define MAX_BUFFERSIZE  256

/* Global constant declaration */
/* Image storage arrays */

float *image1, *image2;
int x_size1, y_size1, /* width & height of image1*/
x_size2, y_size2; /* width & height of image2 */

/* Prototype declaration of functions */
void load_image_data( ); /* image input */
void save_image_data( ); /* image output*/
void load_image_file(char *); /* image input */
void save_image_file(char *); /* image output*/

/* Main body of functions */

void load_image_data()
/* Input of header & body information of pgm file */
/* for image1[ ][ ]ï¼Œx_size1ï¼Œy_size1 */
{
    char file_name[MAX_FILENAME];
    char buffer[MAX_BUFFERSIZE];
    FILE *fp; /* File pointer */
    int max_gray; /* Maximum gray level */
    int x, y; /* Loop variable */

    /* Input file open */
    printf("\n-----------------------------------------------------\n");
    printf("Monochromatic image file input routine \n");
    printf("-----------------------------------------------------\n\n");
    printf("     Only pgm binary file is acceptable\n\n");
    printf("Name of input image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "rb");
    if (NULL == fp) {
        printf("     The file doesn't exist!\n\n");
        exit(1);
    }
    /* Check of file-type ---P5 */
    fgets(buffer, MAX_BUFFERSIZE, fp);
    if (buffer[0] != 'P' || buffer[1] != '5') {
        printf("     Mistaken file format, not P5!\n\n");
        exit(1);
    }
    /* input of x_size1, y_size1 */
    x_size1 = 0;
    y_size1 = 0;
    while (x_size1 == 0 || y_size1 == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d %d", &x_size1, &y_size1);
        }
    }
    /* input of max_gray */
    max_gray = 0;
    while (max_gray == 0) {
        fgets(buffer, MAX_BUFFERSIZE, fp);
        if (buffer[0] != '#') {
            sscanf(buffer, "%d", &max_gray);
        }
    }
    /* Display of parameters */
    printf("\n     Image width = %d, Image height = %d\n", x_size1, y_size1);
    printf("     Maximum gray level = %d\n\n", max_gray);
    if (x_size1 > MAX_IMAGEWIDTH || y_size1 > MAX_IMAGEHEIGHT) {
        printf("     Image size exceeds %d x %d\n\n",
            MAX_IMAGEWIDTH, MAX_IMAGEHEIGHT);
        printf("     Please use smaller images!\n\n");
        exit(1);
    }
    if (max_gray != MAX_BRIGHTNESS) {
        printf("     Invalid value of maximum gray level!\n\n");
        exit(1);
    }
    image1 = (float *)malloc(x_size1*y_size1*sizeof(float));
    /* Input of image data*/
    for (y = 0; y < y_size1; y++) {
        for (x = 0; x < x_size1; x++) {
            image1[y*x_size1+x] = (unsigned char)fgetc(fp);
        }
    }
    printf("-----Image data input OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

void save_image_data()
/* Output of image2[ ][ ], x_size2, y_size2 in pgm format*/

{
    char file_name[MAX_FILENAME];
    FILE *fp; /* File pointer */
    int x, y; /* Loop variable */

    /* Output file open */
    printf("-----------------------------------------------------\n");
    printf("Monochromatic image file output routine\n");
    printf("-----------------------------------------------------\n\n");
    printf("Name of output image file? (*.pgm) : ");
    scanf("%s", file_name);
    fp = fopen(file_name, "wb");
    /* output of pgm file header information */
    fputs("P5\n", fp);
    fputs("# Created by Image Processing\n", fp);
    fprintf(fp, "%d %d\n", x_size2, y_size2);
    fprintf(fp, "%d\n", MAX_BRIGHTNESS);
    /* Output of image data */
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            fputc(image2[y*x_size2+x], fp);
        }
    }
    printf("\n-----Image data output OK-----\n\n");
    printf("-----------------------------------------------------\n\n");
    fclose(fp);
}

#define Mask_width  3
#define Mask_radius Mask_width/2
#define TILE_WIDTH 16
#define w (TILE_WIDTH + Mask_width - 1)
#define clamp(x) (min(max((x), 0.0), 1.0))

__global__ void convolution(float *I, const float* __restrict__ M, float *P, int width, int height) {
    __shared__ float N_ds[w][w];

    // First batch loading
    int dest = threadIdx.y * TILE_WIDTH + threadIdx.x,
        destY = dest / w, destX = dest % w,
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius,
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius,
        src = srcY * width + srcX;
    if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
        N_ds[destY][destX] = I[src];
    else
        N_ds[destY][destX] = 0;
    for (int iter = 1; iter <= (w*w) / (TILE_WIDTH*TILE_WIDTH); iter++)
    {
        // Second batch loading
        dest = threadIdx.y * TILE_WIDTH + threadIdx.x + TILE_WIDTH * TILE_WIDTH;
        destY = dest / w, destX = dest % w;
        srcY = blockIdx.y * TILE_WIDTH + destY - Mask_radius;
        srcX = blockIdx.x * TILE_WIDTH + destX - Mask_radius;
        src = srcY * width + srcX;
        if (destY < w) {
            if (srcY >= 0 && srcY < height && srcX >= 0 && srcX < width)
                N_ds[destY][destX] = I[src];
            else
                N_ds[destY][destX] = 0;
        }
    }
    __syncthreads();

    float accum = 0;
    int y, x;
    for (y = 0; y < Mask_width; y++)
        for (x = 0; x < Mask_width; x++)
            accum += N_ds[threadIdx.y + y][threadIdx.x + x] * M[y * Mask_width + x];

    y = blockIdx.y * TILE_WIDTH + threadIdx.y;
    x = blockIdx.x * TILE_WIDTH + threadIdx.x;
    if (y < height && x < width)
        P[y * width + x] = accum;

}

void sobel_filtering()
/* Spatial filtering of image data */
/* Sobel filter (horizontal differentiation */
/* Input: image1[y][x] ---- Outout: image2[y][x] */

{
    /* Definition of Sobel filter in horizontal direction */
    float weight[3][3] = { { -1,  0,  1 },
              { -2,  0,  2 },
              { -1,  0,  1 } };

    int x, y;  /* Loop variable */
    float * deviceInputImageData;
    float * deviceOutputImageData;
    float * deviceMaskData;

    cudaMalloc((void **)&deviceInputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceOutputImageData, x_size1 * y_size1 * sizeof(float));
    cudaMalloc((void **)&deviceMaskData, 3 * 3 * sizeof(float));

    cudaMemcpy(deviceInputImageData, image1, x_size1 * y_size1 * sizeof(float), cudaMemcpyHostToDevice);
    cudaMemcpy(deviceMaskData, weight, 3 * 3 * sizeof(float), cudaMemcpyHostToDevice);

    /* Maximum values calculation after filtering*/
    printf("Now, filtering of input image is performed\n\n");
    x_size2 = x_size1;
    y_size2 = y_size1;
    image2 = (float *)malloc(x_size2*y_size2*sizeof(float));
    for (y = 0; y < y_size2; y++) {
        for (x = 0; x < x_size2; x++) {
            image2[y*x_size2+x] = 0;
        }
    }

    dim3 dimGrid(ceil((float)x_size1 / TILE_WIDTH), ceil((float)y_size1 / TILE_WIDTH));
    dim3 dimBlock(TILE_WIDTH, TILE_WIDTH);
    convolution<<<dimGrid, dimBlock>>>(deviceInputImageData, deviceMaskData, deviceOutputImageData, x_size1, y_size1);

    cudaMemcpy(image2,
        deviceOutputImageData,
        x_size2 * y_size2 * sizeof(float),
        cudaMemcpyDeviceToHost);

    cudaFree(deviceInputImageData);
    cudaFree(deviceOutputImageData);
    cudaFree(deviceMaskData);

}

int main()
{
    load_image_data();   /* Input of image1 */

    clock_t begin = clock();
    sobel_filtering();   /* Sobel filter is applied to image1 */
    clock_t end = clock();
    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("\n\nTiming result of multiplication of matrix-vector: %f\n", time_spent);
    save_image_data();   /* Output of image2 */
    return 0;
}

Note the above code (your PGM load routine) has (IMO) a defect in that it requires the x and y sizes to be specified on the same line in the PGM file, but as far as I know this is not a requirement for P5 PGM files.  If you pass it a valid P5 PGM file that has x and y sizes specified on different lines in the file, it will hang.  I didn't attempt to fix that, as it doesn't appear to be the question you are asking.


来源: stackexchange

问:
Create a hide show element based on conditional in fuse tools
I would like to create a left menu in fuse tools that would allow for a conditional based on the devices width. This should show the menu on an ipad or tablet device and hide it on a mobile device.

Just wondering if anyone knows how to do this. I cant seem to find any documentation on it, but can imagine it to be something like

```<code><StackPanel ShowWhenDeviceWidth="960">
</code>```

答:
You can use the WhileWindowSize trigger to dynamically include content based on the size of the device (the window on a device is the full screen size).

You need to always specify both an X and Y value. Your setup may look like this:

```<code><WhileWindowSize GreaterThan="959,1">
   <StackPanel>
       ....
   </StackPanel>
</WhileWindowSize>
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I would like to create a left menu in fuse tools that would allow for a conditional based on the devices width. This should show the menu on an ipad or tablet device and hide it on a mobile device.

Just wondering if anyone knows how to do this. I cant seem to find any documentation on it, but can imagine it to be something like

<StackPanel ShowWhenDeviceWidth="960">

Body:
You can use the WhileWindowSize trigger to dynamically include content based on the size of the device (the window on a device is the full screen size).

You need to always specify both an X and Y value. Your setup may look like this:

<WhileWindowSize GreaterThan="959,1">
   <StackPanel>
       ....
   </StackPanel>
</WhileWindowSize>


问:
Swift3 - Insert Relation In Core Data
I have two Entities, namely

Clinic

Department

The relationship between them is many-to-many. i.e a clinic has many departments and a department has many clinics associated.

I have setup the entities in coredata.xcdatamodeld and generated the NSManagedObject classes. PFA the graph

I have the following code which takes care of inserting departments and clinics

```<code>import Foundation
import CoreData
import SwiftyJSON
import Kingfisher

class InstallManager {

    let moc = NetworkManager.managedObjectContext
    let data: JSON!

    init(withData data: JSON) {
        self.data = data
    }

    // Install Department
    private func installDepartment() {
        for(_,jsonData):(String, JSON) in self.data["deparment"]["list"] {
            let department = NSEntityDescription.insertNewObject(forEntityName: "Department", into: moc)
            department.setValue(jsonData["id"].int32, forKey: "id")
            department.setValue(jsonData["name"].string, forKey: "name")
            department.setValue(jsonData["icon"].string, forKey: "icon")
            department.setValue(jsonData["slug"].string, forKey: "slug")
            department.setValue(jsonData["revision"].int32, forKey: "revision")
            do {
                try moc.save()
            } catch {
                fatalError("\(error)")
            }
        }
    }

    // Install Clinic
    private func installClinic() {
        let departmentList = fetchDepartmentList()
        for (_,jsonData):(String, JSON) in self.data["clinic"]["list"] {
            let coverPictureAbsolute = "\(jsonData["cover_picture"].string!)"
            let coverPictureRelative = (coverPictureAbsolute as NSString).lastPathComponent
            let clinic = NSEntityDescription.insertNewObject(forEntityName: "Clinic", into: moc)
            clinic.setValue(jsonData["id"].int32, forKey: "id")
            clinic.setValue(jsonData["name"].string, forKey: "name")
            clinic.setValue(jsonData["slogan"].string, forKey: "slogan")
            clinic.setValue(jsonData["profile"].string, forKey: "profile")
            clinic.setValue(jsonData["address"].string, forKey: "address")
            clinic.setValue(jsonData["telephone"].string, forKey: "telephone")
            clinic.setValue(jsonData["email"].string, forKey: "email")
            clinic.setValue(jsonData["website"].string, forKey: "website")
            clinic.setValue(coverPictureRelative, forKey: "cover_picture")
            clinic.setValue(jsonData["latitude"].string, forKey: "latitude")
            clinic.setValue(jsonData["longitude"].string, forKey: "longitude")
            clinic.setValue(jsonData["slug"].string, forKey: "slug")
            clinic.setValue(jsonData["revision"].int32, forKey: "revision")

            let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
            for department in departmentList {
                clinicEntity.addToDepartments(department)
                print(department.name!)
            }

            do {
                try moc.save()
            } catch {
                fatalError("\(error)")
            }
        }
    }

    private func fetchDepartmentList() -> [Department] {
        var departmentList:[Department]!
        let request: NSFetchRequest<Department> = Department.fetchRequest()
        do {
            departmentList = try moc.fetch(request)
        } catch {
            fatalError("Cannot fetch clinics list \(error)")
        }
        return departmentList
    }

    public func install() {
        self.installDepartment()
        self.installClinic()
    }
}
</code>```

My problem is while inserting relations between clinic and departments, I have the list of department ids which I want to set relation with the clinic. As you can see in the above code, I tried the following code

```<code>let departmentList = fetchDepartmentList()
let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
for department in departmentList {
    clinicEntity.addToDepartments(department)
    print(department.name!)
}
</code>```

But the line clinicEntity throws me the following error

```<code>Could not cast value of type '_NSFaultingMutableSet' to 'APP.Clinic'
</code>```

What is the issue here? How can I set the relation?

UPDATE:

Here is the auto-generated classes from core-data (NSManagedObject SubClass)

```<code>// filename: Clinic.swift
import Foundation
import CoreData

@objc(Clinic)
public class Clinic: NSManagedObject {

}

// filename: Clinic+CoreDataProperties
import Foundation
import CoreData

extension Clinic {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Clinic> {
        return NSFetchRequest<Clinic>(entityName: "Clinic");
    }

    @NSManaged public var address: String?
    @NSManaged public var cover_picture: String?
    @NSManaged public var email: String?
    @NSManaged public var id: Int32
    @NSManaged public var latitude: NSDecimalNumber?
    @NSManaged public var longitude: NSDecimalNumber?
    @NSManaged public var name: String?
    @NSManaged public var profile: String?
    @NSManaged public var revision: Int32
    @NSManaged public var slogan: String?
    @NSManaged public var slug: String?
    @NSManaged public var telephone: String?
    @NSManaged public var website: String?
    @NSManaged public var departments: NSSet?

}

// MARK: Generated accessors for departments
extension Clinic {

    @objc(addDepartmentsObject:)
    @NSManaged public func addToDepartments(_ value: Department)

    @objc(removeDepartmentsObject:)
    @NSManaged public func removeFromDepartments(_ value: Department)

    @objc(addDepartments:)
    @NSManaged public func addToDepartments(_ values: NSSet)

    @objc(removeDepartments:)
    @NSManaged public func removeFromDepartments(_ values: NSSet)

}
</code>```

答:
For a to-many relationship you need to get the mutableSetValueForKey because the type is NSSet rather than Clinic.

```<code>let clinicEntity = clinic.mutableSetValue(forKey: "departments")
for department in departmentList {
    clinicEntity.add(department)
    print(department.name!)
}
</code>```

or simpler

```<code>let clinicEntity = clinic.mutableSetValue(forKey: "departments")
clinicEntity.addObjects(from: departmentList)
</code>```

To use the autogenerated method you can replace

```<code>let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
   for department in departmentList {
   clinicEntity.addToDepartments(department)
      print(department.name!)
   }
</code>```

with

```<code>clinic.addToDepartments(NSSet(array: departmentList))
</code>```

PS: I'd recommend to use the more convenient dot notation, for example

```<code>department.id = jsonData["id"].int32
department.name = jsonData["name"].string
department.icon = jsonData["icon"].string
department.slug = jsonData["slug"].string
department.revision = jsonData["revision"].int32
</code>```

Title: Swift3 - Insert Relation In Core Data

Body:
I have two Entities, namely

Clinic

Department

The relationship between them is many-to-many. i.e a clinic has many departments and a department has many clinics associated.

I have setup the entities in coredata.xcdatamodeld and generated the NSManagedObject classes. PFA the graph

I have the following code which takes care of inserting departments and clinics

import Foundation
import CoreData
import SwiftyJSON
import Kingfisher

class InstallManager {

    let moc = NetworkManager.managedObjectContext
    let data: JSON!

    init(withData data: JSON) {
        self.data = data
    }

    // Install Department
    private func installDepartment() {
        for(_,jsonData):(String, JSON) in self.data["deparment"]["list"] {
            let department = NSEntityDescription.insertNewObject(forEntityName: "Department", into: moc)
            department.setValue(jsonData["id"].int32, forKey: "id")
            department.setValue(jsonData["name"].string, forKey: "name")
            department.setValue(jsonData["icon"].string, forKey: "icon")
            department.setValue(jsonData["slug"].string, forKey: "slug")
            department.setValue(jsonData["revision"].int32, forKey: "revision")
            do {
                try moc.save()
            } catch {
                fatalError("\(error)")
            }
        }
    }

    // Install Clinic
    private func installClinic() {
        let departmentList = fetchDepartmentList()
        for (_,jsonData):(String, JSON) in self.data["clinic"]["list"] {
            let coverPictureAbsolute = "\(jsonData["cover_picture"].string!)"
            let coverPictureRelative = (coverPictureAbsolute as NSString).lastPathComponent
            let clinic = NSEntityDescription.insertNewObject(forEntityName: "Clinic", into: moc)
            clinic.setValue(jsonData["id"].int32, forKey: "id")
            clinic.setValue(jsonData["name"].string, forKey: "name")
            clinic.setValue(jsonData["slogan"].string, forKey: "slogan")
            clinic.setValue(jsonData["profile"].string, forKey: "profile")
            clinic.setValue(jsonData["address"].string, forKey: "address")
            clinic.setValue(jsonData["telephone"].string, forKey: "telephone")
            clinic.setValue(jsonData["email"].string, forKey: "email")
            clinic.setValue(jsonData["website"].string, forKey: "website")
            clinic.setValue(coverPictureRelative, forKey: "cover_picture")
            clinic.setValue(jsonData["latitude"].string, forKey: "latitude")
            clinic.setValue(jsonData["longitude"].string, forKey: "longitude")
            clinic.setValue(jsonData["slug"].string, forKey: "slug")
            clinic.setValue(jsonData["revision"].int32, forKey: "revision")

            let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
            for department in departmentList {
                clinicEntity.addToDepartments(department)
                print(department.name!)
            }

            do {
                try moc.save()
            } catch {
                fatalError("\(error)")
            }
        }
    }

    private func fetchDepartmentList() -> [Department] {
        var departmentList:[Department]!
        let request: NSFetchRequest<Department> = Department.fetchRequest()
        do {
            departmentList = try moc.fetch(request)
        } catch {
            fatalError("Cannot fetch clinics list \(error)")
        }
        return departmentList
    }

    public func install() {
        self.installDepartment()
        self.installClinic()
    }
}

My problem is while inserting relations between clinic and departments, I have the list of department ids which I want to set relation with the clinic. As you can see in the above code, I tried the following code

let departmentList = fetchDepartmentList()
let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
for department in departmentList {
    clinicEntity.addToDepartments(department)
    print(department.name!)
}

But the line clinicEntity throws me the following error

Could not cast value of type '_NSFaultingMutableSet' to 'APP.Clinic'

What is the issue here? How can I set the relation?

UPDATE:

Here is the auto-generated classes from core-data (NSManagedObject SubClass)

// filename: Clinic.swift
import Foundation
import CoreData

@objc(Clinic)
public class Clinic: NSManagedObject {

}

// filename: Clinic+CoreDataProperties
import Foundation
import CoreData

extension Clinic {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Clinic> {
        return NSFetchRequest<Clinic>(entityName: "Clinic");
    }

    @NSManaged public var address: String?
    @NSManaged public var cover_picture: String?
    @NSManaged public var email: String?
    @NSManaged public var id: Int32
    @NSManaged public var latitude: NSDecimalNumber?
    @NSManaged public var longitude: NSDecimalNumber?
    @NSManaged public var name: String?
    @NSManaged public var profile: String?
    @NSManaged public var revision: Int32
    @NSManaged public var slogan: String?
    @NSManaged public var slug: String?
    @NSManaged public var telephone: String?
    @NSManaged public var website: String?
    @NSManaged public var departments: NSSet?

}

// MARK: Generated accessors for departments
extension Clinic {

    @objc(addDepartmentsObject:)
    @NSManaged public func addToDepartments(_ value: Department)

    @objc(removeDepartmentsObject:)
    @NSManaged public func removeFromDepartments(_ value: Department)

    @objc(addDepartments:)
    @NSManaged public func addToDepartments(_ values: NSSet)

    @objc(removeDepartments:)
    @NSManaged public func removeFromDepartments(_ values: NSSet)

}

Body:
For a to-many relationship you need to get the mutableSetValueForKey because the type is NSSet rather than Clinic.

let clinicEntity = clinic.mutableSetValue(forKey: "departments")
for department in departmentList {
    clinicEntity.add(department)
    print(department.name!)
}

or simpler

let clinicEntity = clinic.mutableSetValue(forKey: "departments")
clinicEntity.addObjects(from: departmentList)

To use the autogenerated method you can replace

let clinicEntity = clinic.value(forKeyPath: "departments") as! Clinic
   for department in departmentList {
   clinicEntity.addToDepartments(department)
      print(department.name!)
   }

with

clinic.addToDepartments(NSSet(array: departmentList))

PS: I'd recommend to use the more convenient dot notation, for example

department.id = jsonData["id"].int32
department.name = jsonData["name"].string
department.icon = jsonData["icon"].string
department.slug = jsonData["slug"].string
department.revision = jsonData["revision"].int32


问:
Substring IP-Address with adding a string generates error but works
I have following command:

```<code>$IP_start = $First.Substring(0, $First.LastIndexOf('.'))+ ".200"
</code>```

$First is an IP-Address, for example 192.168.0.1

I want to change the 1 in the fourth octect into a 200.

```<code>Write-Output $IP_start
</code>```

gives me the correct IP-Address 192.168.0.200, but at the same time I get the following Error:

Ausnahme beim Aufrufen von "Substring" mit 2 Argument(en):  "Die Länge
  darf nicht kleiner als 0 (null) sein. Parametername: length" In
  *ps1:31 Zeichen:3
  +   $IP_start = $First.Substring(0, $First.LastIndexOf('.'))+ ".200"
  +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : ArgumentOutOfRangeException

English translation

Exception when calling "substring" with 2 arguments: "The length can not be less than zero. Parameter name: length" In * ps1: 31 characters: 3...

I think everything is working fine, but that error messages bothers me.

//edit:

There's an ip.txt, where each line is like "192.168.0.1; ABCDEF"

```<code>$txt = Get-Content ip.txt
$editline = foreach ($Data in $txt) {
  $First, $Second = $Data -split ';' -replace '^\s*|\s*$'

$IP_start = $First.Substring(0, $First.LastIndexOf('.'))+ ".200"
Write-Output "modify ipaddr_first $IP_start"
}

$editline | Out-File "$output"
</code>```

$first is therefore "192.168.0.1" and $second is "ABCDEF".

答:
Creating a Synthetic Method for an IPAddress Object , a fun way of doing this...  </p>

```<code>$Method = {
Param(
[Int]$Number,

[ValidateSet(1,2,3,4)]
[Int]$Position
)

$OctetPosition = $Position - 1
$CurrentIpAddress = New-Object -TypeName System.Collections.ArrayList
$This.IpAddressToString -Split '\.' | ForEach-Object -Process {
    $CurrentIpAddress.Add($_) | Out-Null
}

$ChangedOctet = [Int]($CurrentIpAddress[$OctetPosition]) + $Number

if( $ChangedOctet -gt 255 ){
    throw "Resulting octet is $ChangedOctet which is greater than 255"
}

$CurrentIpAddress.Item($OctetPosition) = $ChangedOctet

return ($CurrentIpAddress -join '.')

}

$IPAddress = [System.Net.IpAddress]'192.168.1.1'
$IPAddress | Add-Member -MemberType ScriptMethod -Name Add -Value $Method

#$IPaddress.Add($Number,$OctetPosition)
$IPAddress.Add(200,4)
</code>```

Body:
I have following command:

$IP_start = $First.Substring(0, $First.LastIndexOf('.'))+ ".200"

$First is an IP-Address, for example 192.168.0.1

I want to change the 1 in the fourth octect into a 200.

Write-Output $IP_start

gives me the correct IP-Address 192.168.0.200, but at the same time I get the following Error:

Ausnahme beim Aufrufen von "Substring" mit 2 Argument(en):  "Die Länge
  darf nicht kleiner als 0 (null) sein. Parametername: length" In
  *ps1:31 Zeichen:3
  +   $IP_start = $First.Substring(0, $First.LastIndexOf('.'))+ ".200"
  +   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
      + FullyQualifiedErrorId : ArgumentOutOfRangeException

English translation

Exception when calling "substring" with 2 arguments: "The length can not be less than zero. Parameter name: length" In * ps1: 31 characters: 3...

I think everything is working fine, but that error messages bothers me.

//edit:

There's an ip.txt, where each line is like "192.168.0.1; ABCDEF"

$txt = Get-Content ip.txt
$editline = foreach ($Data in $txt) {
  $First, $Second = $Data -split ';' -replace '^\s*|\s*$'

$IP_start = $First.Substring(0, $First.LastIndexOf('.'))+ ".200"
Write-Output "modify ipaddr_first $IP_start"
}

$editline | Out-File "$output"

$first is therefore "192.168.0.1" and $second is "ABCDEF".

Body:
Creating a Synthetic Method for an IPAddress Object , a fun way of doing this...

$Method = {
Param(
[Int]$Number,

[ValidateSet(1,2,3,4)]
[Int]$Position
)

$OctetPosition = $Position - 1
$CurrentIpAddress = New-Object -TypeName System.Collections.ArrayList
$This.IpAddressToString -Split '\.' | ForEach-Object -Process {
    $CurrentIpAddress.Add($_) | Out-Null
}

$ChangedOctet = [Int]($CurrentIpAddress[$OctetPosition]) + $Number

if( $ChangedOctet -gt 255 ){
    throw "Resulting octet is $ChangedOctet which is greater than 255"
}

$CurrentIpAddress.Item($OctetPosition) = $ChangedOctet

return ($CurrentIpAddress -join '.')

}

$IPAddress = [System.Net.IpAddress]'192.168.1.1'
$IPAddress | Add-Member -MemberType ScriptMethod -Name Add -Value $Method

#$IPaddress.Add($Number,$OctetPosition)
$IPAddress.Add(200,4)


问:
How to split this String using mysql Query?
I have a table called "article"

```<code>ID       Date
1        3rd June 2017
2        2nd April 2016
3        21st June 2017
4        31st December 2015
</code>```

and I want to find all the ID's where Date has June in it ,Therefore Result should be

```<code>ID
1
3
</code>```

P.S -I tried doing this but I am stuck at this point , here is my Query

```<code>SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(Date, ' ', 2), ' ', -1) as month
from article
where article.month='June'
</code>```

答:
Why would you split the string to do that?

Just do:

```<code>where date like '%June%'
</code>```

Body:
I have a table called "article"

ID       Date
1        3rd June 2017
2        2nd April 2016
3        21st June 2017
4        31st December 2015

and I want to find all the ID's where Date has June in it ,Therefore Result should be

ID
1
3

P.S -I tried doing this but I am stuck at this point , here is my Query

SELECT SUBSTRING_INDEX(SUBSTRING_INDEX(Date, ' ', 2), ' ', -1) as month
from article
where article.month='June'

Body:
Why would you split the string to do that?

Just do:

where date like '%June%'


问:
Displaying multiple results with 1 button
The issue I am having with my code is trying to only display 1 button for multiple results with the same name field in my search_db table. The name field has different ids. I need to gather all the fullnames that are the same. It's a very complicated topic to explain and that is the best way I can explain it.

Here is my source code:

```<code><?php
    include('connect.php');
?>
<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <title>Example</title>
    </head>
    <body>
        <form action="test.php" method="POST">
            <input type="text" name="value" placeholder="Hello" />
            <input type="submit" name="submit" value="Search" />
        </form><br />
        <?php
            if(isset($_POST['submit']))
            {
                $value = htmlspecialchars($_POST['value']);
                $stmt = $pdo->prepare("SELECT * FROM search_db WHERE fullname = :fullname");
                $stmt -> execute(array(':fullname' => $value));
                $result = $stmt -> fetchAll();
                foreach($result as $row)
                {
                    $id = $row['id'];
                    $db_name = $row['name'];
                    $name = $row['fullname'];
                    $username = $row['username'];
                    $password = $row['password'];
                    $dob = $row['date'];
                    $email = $row['email'];

                    $test =  '<p >'.$name. ' ' . $password . '</p>';
                }
                echo '<button data-toggle="collapse" data-target="#test">'. count($result) .' Results Found</button><br />';
                echo '<div id="test" class="collapse">'. $test . '</div>';
            }
        ?>
    </body>
</html>
</code>```

答:
There are some useful PHP array functions that can help with counting values and removing duplicates.

http://php.net/manual/en/function.array-count-values.php

http://php.net/manual/en/function.array-unique.php

```<code><?php
    if(isset($_POST['submit']))
    {
        $value = htmlspecialchars($_POST['value']);
        $stmt = $pdo->prepare("SELECT * FROM search_db WHERE fullname = :fullname");
        $stmt -> execute(array(':fullname' => $value));
        $result = $stmt -> fetchAll();

        $namesArr = array(); //create empty array

        foreach($result as $row)
        {
            $id = $row['id'];
            $db_name = $row['name'];
            $name = $row['fullname'];
            $username = $row['username'];
            $password = $row['password'];
            $dob = $row['date'];
            $email = $row['email'];

            $test =  '<p >'.$name. ' ' . $password . '</p>';
            array_push($namesArr, $name);   //push each name into new array
        }
        $uniqueNamesArr = array_unique($namesArr);    //http://php.net/manual/en/function.array-unique.php
        $nameCounts = array_count_values($namesArr);  //http://php.net/manual/en/function.array-count-values.php
        foreach( $uniqueNamesArr as $uniqueName ) {
            echo '<div id="' . $uniqueName . '" class="collapse">'. $uniqueName . '</div>';
            echo '<button data-toggle="collapse" data-target="#' . $uniqueName . '">'. $nameCounts[$uniqueName] .' Results Found</button><br />';
        }
    }
?>
</code>```

Body:
The issue I am having with my code is trying to only display 1 button for multiple results with the same name field in my search_db table. The name field has different ids. I need to gather all the fullnames that are the same. It's a very complicated topic to explain and that is the best way I can explain it.

Here is my source code:

<?php
    include('connect.php');
?>
<!DOCTYPE html>

        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

        <title>Example</title>

        <form action="test.php" method="POST">
            <input type="text" name="value" placeholder="Hello" />
            <input type="submit" name="submit" value="Search" />
        </form>

        <?php
            if(isset($_POST['submit']))
            {
                $value = htmlspecialchars($_POST['value']);
                $stmt = $pdo->prepare("SELECT * FROM search_db WHERE fullname = :fullname");
                $stmt -> execute(array(':fullname' => $value));
                $result = $stmt -> fetchAll();
                foreach($result as $row)
                {
                    $id = $row['id'];
                    $db_name = $row['name'];
                    $name = $row['fullname'];
                    $username = $row['username'];
                    $password = $row['password'];
                    $dob = $row['date'];
                    $email = $row['email'];

                    $test =  '
'.$name. ' ' . $password . '
';
                }
                echo '<button data-toggle="collapse" data-target="#test">'. count($result) .' Results Found</button>
';
                echo '
'. $test . '
';
            }
        ?>

Body:
There are some useful PHP array functions that can help with counting values and removing duplicates.

http://php.net/manual/en/function.array-count-values.php

http://php.net/manual/en/function.array-unique.php

<?php
    if(isset($_POST['submit']))
    {
        $value = htmlspecialchars($_POST['value']);
        $stmt = $pdo->prepare("SELECT * FROM search_db WHERE fullname = :fullname");
        $stmt -> execute(array(':fullname' => $value));
        $result = $stmt -> fetchAll();

        $namesArr = array(); //create empty array

        foreach($result as $row)
        {
            $id = $row['id'];
            $db_name = $row['name'];
            $name = $row['fullname'];
            $username = $row['username'];
            $password = $row['password'];
            $dob = $row['date'];
            $email = $row['email'];

            $test =  '<p >'.$name. ' ' . $password . '</p>';
            array_push($namesArr, $name);   //push each name into new array
        }
        $uniqueNamesArr = array_unique($namesArr);    //http://php.net/manual/en/function.array-unique.php
        $nameCounts = array_count_values($namesArr);  //http://php.net/manual/en/function.array-count-values.php
        foreach( $uniqueNamesArr as $uniqueName ) {
            echo '<div id="' . $uniqueName . '" class="collapse">'. $uniqueName . '</div>';
            echo '<button data-toggle="collapse" data-target="#' . $uniqueName . '">'. $nameCounts[$uniqueName] .' Results Found</button><br />';
        }
    }
?>


问:
Capture search engine keywords in php
In awstats I get a table with all the key words and phrases used to find my website.  I would like to capture this myself however each search engine url is in a different format.  When google is the referer I can use the variable q from the querystring as the search term (e.g. google.com?q=my+keywords) however another search engine may have the format searchengine.com?search=my+keywords

Is there a generic way of identifying search keywords?  Or am I going to have to create a regex/filter for each search engine?

答:
I am having to add to it all the time, but here is a REGEX that should strip out the keywords from google, yahoo, bing, ask, and MSN (same as Bing). It leaves the + in between, but it should be a good place for you to start:</p>

```<code>.*(\?p=|\?q=|&q=|\?s=)([a-zA-Z0-9 +]*)(&toggle=|&ie=utf-8|&FORM=|&aq=|&x=|&gwp).
</code>```

ContentLicense: CC BY-SA 2.5

Title: Capture search engine keywords in php

Body:
I am having to add to it all the time, but here is a REGEX that should strip out the keywords from google, yahoo, bing, ask, and MSN (same as Bing). It leaves the + in between, but it should be a good place for you to start:

.*(\?p=|\?q=|&q=|\?s=)([a-zA-Z0-9 +]*)(&toggle=|&ie=utf-8|&FORM=|&aq=|&x=|&gwp).


问:
Test case failed with org.junit.ComparisonFailure
While having the unit test case writing for French and Czech localization, on doing

```<code>  assertThat(formattedDecimal).isEqualTo("8 771,23");
</code>```

where formattedDecimal is a string ,
had a result

```<code>org.junit.ComparisonFailure:
Expected :"8 771,23"
Actual   :"8 771,23"
</code>```

why it failed? did not understand, please guide what i am doing wrong here!!

答:
maybe your formattedDecimal including some control letters that can't see in the console. have you tried this?

```<code>assertThat("foo\bo").isNotEqualTo("foo");// ok
          //   ^--- it print "foo"

assertThat(formattedDecimal.getBytes()).isEqualTo("8 771,23".getBytes())
</code>```

Body:
While having the unit test case writing for French and Czech localization, on doing

  assertThat(formattedDecimal).isEqualTo("8 771,23");

where formattedDecimal is a string ,
had a result

org.junit.ComparisonFailure:
Expected :"8 771,23"
Actual   :"8 771,23"

why it failed? did not understand, please guide what i am doing wrong here!!

Body:
maybe your formattedDecimal including some control letters that can't see in the console. have you tried this?

assertThat("foo\bo").isNotEqualTo("foo");// ok
          //   ^--- it print "foo"

assertThat(formattedDecimal.getBytes()).isEqualTo("8 771,23".getBytes())


问:
How can I create my own file type on Node?
I am wondering if I can change the mime-type of a file on Node. I have checked many mime-type modules, but all of them are just to get information from the files and from the system.

What I would like to achieve is to zip some files in one single file and then, change the mime-type. On this way I could check if the file type is suited for my application.

I know there are differences between operating systems:

Windows. I change the extension and it is done

Ubuntu. I must deal with mime-types. This is what I would like to change

Mac. They have a system similar to Ubuntu.

How to achieve this on Ubuntu or Mac?

Assuming that I can do it and I have just changed the mime-type of a zip file on Ubuntu, is it still going to detect the file as a zip file by the system?

If all of this is not possible. How can I create my own file built with different files?

For example I would like to include all these files compressed inside the packaged file called filename.foo:

An XML file with metadata

A text file

A CSV file

An image

答:
Finally I have changed the file extension and added a new MIME-TYPE to the system. In this way Nautilus (Ubuntu) and the Windows explorer recognise the file with the new type.

When I use the command file --mime-type I still detect the zip mime-type. But that's not bad because I can use this detection to avoid errors in my app.

Create your own MIME-TYPE for Nautilus

Create a new XML in /usr/share/mime/packages/ with this content:

```<code><?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
  <mime-type type="application/todo">
    <comment>Todos Text file</comment>
    <glob pattern="*.TODO"/>
    <glob pattern="*.todo"/>
  </mime-type>
</mime-info>
</code>```

Execute the following command to update mime database

```<code>sudo update-mime-database /usr/share/mime
</code>```

Assign an icon to the new extension

First step is renaming the icon to application-todo and it must be in svg extension.

If you're using gnome you have move the icon to /usr/share/icons/gnome/scalable then update the cache with

```<code>$ sudo gtk-update-icon-cache /usr/share/icons/gnome -f
</code>```

If you're using unity move it to /usr/share/icons/Humanity/mimes/ then update the cache

```<code>$ sudo gtk-update-icon-cache /usr/share/icons/Humanity -f
</code>```

Give your nautilus a refresh and you'll have a new mime-type with icon

Body:
Finally I have changed the file extension and added a new MIME-TYPE to the system. In this way Nautilus (Ubuntu) and the Windows explorer recognise the file with the new type.

When I use the command file --mime-type I still detect the zip mime-type. But that's not bad because I can use this detection to avoid errors in my app.

Create your own MIME-TYPE for Nautilus

Create a new XML in /usr/share/mime/packages/ with this content:

<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
  <mime-type type="application/todo">
    <comment>Todos Text file</comment>
    <glob pattern="*.TODO"/>
    <glob pattern="*.todo"/>
  </mime-type>
</mime-info>

Execute the following command to update mime database

sudo update-mime-database /usr/share/mime

Assign an icon to the new extension

First step is renaming the icon to application-todo and it must be in svg extension.

If you're using gnome you have move the icon to /usr/share/icons/gnome/scalable then update the cache with

$ sudo gtk-update-icon-cache /usr/share/icons/gnome -f

If you're using unity move it to /usr/share/icons/Humanity/mimes/ then update the cache

$ sudo gtk-update-icon-cache /usr/share/icons/Humanity -f

Give your nautilus a refresh and you'll have a new mime-type with icon


问:
Chrome extension Secure Shell socket access
I'd like to make an SSH-based extension for Chrome, but I can't figure out how the secure shell extension is able to access raw sockets in Chrome.

It only has these permissions:

Yet I'm able to connect on port 22 via SSH.  I know it uses PNaCl through Enscripten, but how do these provide raw socket access?
Has Google hard-coded whitelabel permission to the sockets API just for this extension?

答:
if you check the manifest, you will see that it has this permission "terminalPrivate".

Then if you poke alittle bit around you will find those posts:

http://chromium.2324630.n4.nabble.com/crx-Use-chrome-terminalPrivate-API-in-chromeOS-extension-app-td17265.html

https://groups.google.com/a/chromium.org/forum/#!topic/chromium-hterm/PtR2q2p_vss

The "good" comments you find on those sites are:

chrome.terminalPrivate exists, but it's native code only available to
  the Secure Shell chrome extension, and only on Chrome OS.

Or this one:

chrome.xPrivate APIs are, well, private APIs that are only used by
  certain Chrome or Google extensions and applications.


问:
ZipFile module in Python - Runtime problems
I'm doing a little script to zip multiple folders in multiple zip files following a certain structure. I've built the structure as a list. Here are some entries:

```<code>['E:\Documents\UFSCar\Primeiro Ano\Primeiro Semestre\Cálculo 1',
'E:\Documents\UFSCar\Primeiro Ano\Segundo Semestre\Estatistica',
'E:\Documents\UFSCar\Primeiro Ano\Segundo Semestre\Estruturas Discretas',
'E:\Documents\UFSCar\Primeiro Ano\Segundo Semestre\Introdução à Engenharia']
</code>```

Down here are the 2 methods resposible for zipping the files together.

```<code>def zipit (path, archname):
    # Create a ZipFile Object primed to write
    archive = ZipFile(archname, "w", ZIP_DEFLATED) # "a" to append, "r" to read
    # Recurse or not, depending on what path is
    if os.path.isdir(path):
        zippy(path, archive)
    else:
        archive.write(path)
    archive.close()
    return "Compression of \""+path+"\" was successful!"

def zippy(path,archive):
    paths = os.listdir(path)
    for p in paths:
        p = os.path.join(path,p)
        if os.path.isdir(p):
            zippy(p,archive)
        else:
            archive.write(p)
    return
</code>```

The main part os the script is like this:

```<code>for i in range(len(myList)):
    zipit(myList[i],os.path.split(myList[i])[1])
</code>```

I've used numerical indexes because this made the script run well for a larger number of files. Before that, only 2 zipfiles we're written. This way, about 8 make its way to the end. No clue why.

The script simply iterates over the list and compresses each one as a separated zipfile. The problem happens when the size of the list is bigger. I get the following error message.

```<code>Traceback (most recent call last):
  File "E:\Documents\UFSCar\zipit.py", line 76, in <module>
    zipit(listaDisciplinas[i],os.path.split(listaDisciplinas[i])[1])
  File "E:\Documents\UFSCar\zipit.py", line 22, in zipit
    zippy(path, archive)
  File "E:\Documents\UFSCar\zipit.py", line 11, in zippy
    zippy(p,archive)
  File "E:\Documents\UFSCar\zipit.py", line 11, in zippy
    zippy(p,archive)
  File "E:\Documents\UFSCar\zipit.py", line 13, in zippy
    archive.write(p)
  File "C:\Python27\lib\zipfile.py", line 994, in write
    mtime = time.localtime(st.st_mtime)
ValueError: (22, 'Invalid argument')
</code>```

Do anyone knows what may cause this error?
thanks!

EDIT:

I've used the code provided below to teste the files, the problem were the files with problems with their "last modified" timestamp. For some reason unknown, some of them had the the last modification in the 2049 year.

In that case, the Python zipfile module failed in compressing the files as a ValueError was thrown.

My solution: edit the problematic files to chance their timestamp. Maybe someday I verify is there is a better solution.

Thanks for the help of everyone.

答: mtime is a timestamp for when your file was last modified. So, it's probably invalid in some way for one file. Work out what file causes it, then call os.stat(filename).st_mtime to check it.

Body:
I'm doing a little script to zip multiple folders in multiple zip files following a certain structure. I've built the structure as a list. Here are some entries:

['E:\Documents\UFSCar\Primeiro Ano\Primeiro Semestre\Cálculo 1',
'E:\Documents\UFSCar\Primeiro Ano\Segundo Semestre\Estatistica',
'E:\Documents\UFSCar\Primeiro Ano\Segundo Semestre\Estruturas Discretas',
'E:\Documents\UFSCar\Primeiro Ano\Segundo Semestre\Introdução à Engenharia']

Down here are the 2 methods resposible for zipping the files together.

def zipit (path, archname):
    # Create a ZipFile Object primed to write
    archive = ZipFile(archname, "w", ZIP_DEFLATED) # "a" to append, "r" to read
    # Recurse or not, depending on what path is
    if os.path.isdir(path):
        zippy(path, archive)
    else:
        archive.write(path)
    archive.close()
    return "Compression of \""+path+"\" was successful!"

def zippy(path,archive):
    paths = os.listdir(path)
    for p in paths:
        p = os.path.join(path,p)
        if os.path.isdir(p):
            zippy(p,archive)
        else:
            archive.write(p)
    return

The main part os the script is like this:

for i in range(len(myList)):
    zipit(myList[i],os.path.split(myList[i])[1])

I've used numerical indexes because this made the script run well for a larger number of files. Before that, only 2 zipfiles we're written. This way, about 8 make its way to the end. No clue why.

The script simply iterates over the list and compresses each one as a separated zipfile. The problem happens when the size of the list is bigger. I get the following error message.

Traceback (most recent call last):
  File "E:\Documents\UFSCar\zipit.py", line 76, in <module>
    zipit(listaDisciplinas[i],os.path.split(listaDisciplinas[i])[1])
  File "E:\Documents\UFSCar\zipit.py", line 22, in zipit
    zippy(path, archive)
  File "E:\Documents\UFSCar\zipit.py", line 11, in zippy
    zippy(p,archive)
  File "E:\Documents\UFSCar\zipit.py", line 11, in zippy
    zippy(p,archive)
  File "E:\Documents\UFSCar\zipit.py", line 13, in zippy
    archive.write(p)
  File "C:\Python27\lib\zipfile.py", line 994, in write
    mtime = time.localtime(st.st_mtime)
ValueError: (22, 'Invalid argument')

Do anyone knows what may cause this error?
thanks!

EDIT:

I've used the code provided below to teste the files, the problem were the files with problems with their "last modified" timestamp. For some reason unknown, some of them had the the last modification in the 2049 year.

In that case, the Python zipfile module failed in compressing the files as a ValueError was thrown.

My solution: edit the problematic files to chance their timestamp. Maybe someday I verify is there is a better solution.

Thanks for the help of everyone.


问:
Reload data from database without refreshing page
My Ajax successfully update some information in database and as a result he should update one element, which shows this information. But it doesn't. However, after refreshing page, which cause reconnecting to db, information updating. Here is the function:

```<code>function topUpTheBalance(){
        var d = document.getElementById("numberForm").value;
        $.ajax({
        type: 'POST',
        url: 'handler.php',
        data: {
            'topUpBalance':d,
        },
        success: function () {
            var k = document.getElementById("balanceNumber");
            k.innerHTML ="Your balance: "+ <?php echo $userRow['userBalance']; ?>;
        }
        }
        );
    }
</code>```

and the handler.php

```<code><?php
    ob_start();
    session_start();
    require_once 'dbconnect.php';

    if( !isset($_SESSION['user']) ) {
    header("Location: index.php");
     exit;
    }
    $res=mysqli_query($link, "SELECT * FROM users WHERE userId=".$_SESSION['user']);
    $userRow=mysqli_fetch_array($res);
    //$link =  mysqli_connect("localhost","username","password", "users");
    $bal = $userRow['userBalance']+$_POST['topUpBalance'];
    if($stmt = mysqli_prepare($link, "UPDATE users SET userBalance = ? WHERE userId = ?")){
            mysqli_stmt_bind_param($stmt, "di", $bal, $userRow['userId']);
            mysqli_stmt_execute($stmt);
            mysqli_stmt_bind_result($stmt, $result);
            mysqli_stmt_fetch($stmt);
            mysqli_stmt_close($stmt);
    }
    mysqli_close($link);
?>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
</body>
</html>
<?php ob_end_flush(); ?>
</code>```

Can anyone suggest me how to update this information without refreshing the page?

答:
The issue is that you are trying to run php in the client side when you wrote k.innerHTML="string"+php code
You should instead produce an output in the php file you request to and retrieve that output and put it in here.

https://www.w3schools.com/jquery/jquery_ajax_get_post.asp
The link explains how to send data to server through POST and get data from server through GET.

Body:
My Ajax successfully update some information in database and as a result he should update one element, which shows this information. But it doesn't. However, after refreshing page, which cause reconnecting to db, information updating. Here is the function:

function topUpTheBalance(){
        var d = document.getElementById("numberForm").value;
        $.ajax({
        type: 'POST',
        url: 'handler.php',
        data: {
            'topUpBalance':d,
        },
        success: function () {
            var k = document.getElementById("balanceNumber");
            k.innerHTML ="Your balance: "+ <?php echo $userRow['userBalance']; ?>;
        }
        }
        );
    }

and the handler.php

<?php
    ob_start();
    session_start();
    require_once 'dbconnect.php';

    if( !isset($_SESSION['user']) ) {
    header("Location: index.php");
     exit;
    }
    $res=mysqli_query($link, "SELECT * FROM users WHERE userId=".$_SESSION['user']);
    $userRow=mysqli_fetch_array($res);
    //$link =  mysqli_connect("localhost","username","password", "users");
    $bal = $userRow['userBalance']+$_POST['topUpBalance'];
    if($stmt = mysqli_prepare($link, "UPDATE users SET userBalance = ? WHERE userId = ?")){
            mysqli_stmt_bind_param($stmt, "di", $bal, $userRow['userId']);
            mysqli_stmt_execute($stmt);
            mysqli_stmt_bind_result($stmt, $result);
            mysqli_stmt_fetch($stmt);
            mysqli_stmt_close($stmt);
    }
    mysqli_close($link);
?>
<!DOCTYPE html>

<?php ob_end_flush(); ?>

Can anyone suggest me how to update this information without refreshing the page?


问:
When does a mapper store its output to its local hard disk?
I know that

The output of the Mapper (intermediate data) is stored on the Local file system (not HDFS) of each individual mapper data nodes. This is typically a temporary directory which can be setup in config by the Hadoop administrator. Once the Mapper job completed or the data transferred to the Reducer, these intermediate data is cleaned up and no more accessible.

But, I wanted to know when does a mapper store its output to its local hard disk? Is it because the data is too large for it to be in memory? And only the data which is being processed remains in the memory? If the data is small and the whole data can fit in memory, then no disk involvement is there?

Can we not directly move the data, once it is processed in the mapper, from the mapper to reducer without the involvement of the hard disk of the mapper m/c. I mean as the data is being processed in the mapper, and it is in memory, once it is computed, it is directly transferred to the reducer and the mapper could pass on the next chunk of data similarly with no disk involvement.

In spark, it is said there is in-memory computation, How different is that from above? What makes spark compute in-memory better than map reduce? Also, in spark there would have to be disk involvement, if data is too huge?

Please explain

答:
Lot of questions here. I shall try to explain each one.

when does a mapper store it's output to its local hard disk?

The mapper stores the data in the configured memory. When the memory is 80% full(again configurable), it runs combiner on the data which is present in memory to reduce the data. But when the combined data also surpasses this memory limit, its spilled to disk. The files are known as spill files. During the whole operation, multiple spilled files are written. While writing spill files, mapper sorts and partitions the data according to the reducer. At the end of the map operations, these spill files needs to be merged.

Can we not directly move the data, once it is processed in the mapper, from the mapper to reducer without the involvement of the hard disk of the mapper m/c.

The costliest operation in any processing is the 'data transfer' between machines. The whole paradigm of map reduce is to take processing near to data rather than moving data around. So if its done the way you are suggesting, there shall be a lot of data movement. Its faster to write into local disk as compared to writing on network. This data can be reduced down by merging of the spill files.
Sorting is done while spilling the files because its easier(faster) to merge sorted data. Partition is done, because you only need to merge same partitions( the data going to same reducer). In the process of merging, combiners are run again to reduce the data. This reduced data is then sent to reducers.

In spark, it is said there is in-memory computation, How different is that from above?

There is no difference in a spark and map reduce program where you just read from some data set, perform one map function and one reduce function. It will do the same reads and writes in disk as a mapreduce code. Difference comes when you need to run few operations on the same data set. In map reduce it will read from disk for each operation but in spark you have an option to use memory to store it in which case it will read from disk only once and later operations shall run on stored data in memory which is obviously way faster.
Or in case when there are chains of operation where output of 1st operation is input to second. In Mapreduce, the output of 1st operation will be written to disk and be read from disk in 2nd operation, whereas in spark you can persist the output of 1st operation in memory so that 2nd operation reads from memory and shall be faster.


问:
How to make an if function work in a tkinter output box
The premise of my code is to ask for a password and the tkinter gui will return whether it thinks that it is secure or not. However, I cannot seem to get the if function displayed in the output box. Here is the code. (This has been updated to include more code and a further more detailed explanation of my problem.)

```<code>from tkinter import *

password = Tk()
password.title('Password tester')

label = Label(password, text="Password:").grid(row=1, column=0, sticky=W)
entry= Entry(width=20, bg='light blue')
entry.grid(row=2, column=0, sticky=W)        #Input box

def click():
  entered_text = entry.get()
  print("click")
  Button(password, text='SUBMIT',width=5, command=click).grid(row=3,column=0, sticky=W)    #Submit button ('Click' is also returned in the shell)

  label = Label(password, text='\n\nPassword strength:')
  label.grid(row=4, column=0, sticky=W)

  output = Text(password, width=75, height=6, wrap=WORD, background='light blue')
output.grid(row=5, column=0, columnspan=2, sticky=W)    #Output box

if label['text'] =='password':
   output.insert(END, label['text'])#'Cool = output if 'password' entered
   print('Cool')
</code>```

The code now returns 'click,' if 'password' is entered into the'Password:.' box. However, 'click' appears in the shell instead of the GUI, and is supposed to print 'cool' in the 'Password strength:' box, if 'password' is entered.

答:
Do not use an if function. Instead, assign 'password' to a dictionary.

Def click():
Is in the wrong position. Assigning 'password' to a dictionary makes it a lot easier to get an answer in the output. Here is the code:

```<code>from tkinter import *

def click():
  entered_text = entry.get()
  output.delete(0.0, END)
  strength = pass_Type[entered_text]    #Key press function
  output.insert(END, strength)

Password = Tk()
Password.title('Password tester')

label = Label(Password, text="Password:")
label.grid(row=0, column=0, sticky=W)    #Entry label

entry = Entry(width=20, bg='light blue')
entry.grid(row=1, column=0, sticky=W)     #Entry box

Button(Password, text='SUBMIT',width=5, command=click).grid(row=2,column=0, sticky=W)  #Button

label = Label(Password, text='Strength:')
label.grid(row=4, column=0, sticky=W)          #Output label

output = Text(Password, width=75, height=6, wrap=WORD, background='light blue')
output.grid(row=5, column=0, columnspan=2, sticky=W)                              #Output box

pass_Type = {
  'password': 'This is a very predicatable password. You should incorporate numbers'
}

password.mainloop()
</code>```

Body:
The premise of my code is to ask for a password and the tkinter gui will return whether it thinks that it is secure or not. However, I cannot seem to get the if function displayed in the output box. Here is the code. (This has been updated to include more code and a further more detailed explanation of my problem.)

from tkinter import *

password = Tk()
password.title('Password tester')

label = Label(password, text="Password:").grid(row=1, column=0, sticky=W)
entry= Entry(width=20, bg='light blue')
entry.grid(row=2, column=0, sticky=W)        #Input box

def click():
  entered_text = entry.get()
  print("click")
  Button(password, text='SUBMIT',width=5, command=click).grid(row=3,column=0, sticky=W)    #Submit button ('Click' is also returned in the shell)

  label = Label(password, text='\n\nPassword strength:')
  label.grid(row=4, column=0, sticky=W)

  output = Text(password, width=75, height=6, wrap=WORD, background='light blue')
output.grid(row=5, column=0, columnspan=2, sticky=W)    #Output box

if label['text'] =='password':
   output.insert(END, label['text'])#'Cool = output if 'password' entered
   print('Cool')

The code now returns 'click,' if 'password' is entered into the'Password:.' box. However, 'click' appears in the shell instead of the GUI, and is supposed to print 'cool' in the 'Password strength:' box, if 'password' is entered.

Body:
Do not use an if function. Instead, assign 'password' to a dictionary.

Def click():
Is in the wrong position. Assigning 'password' to a dictionary makes it a lot easier to get an answer in the output. Here is the code:

from tkinter import *

def click():
  entered_text = entry.get()
  output.delete(0.0, END)
  strength = pass_Type[entered_text]    #Key press function
  output.insert(END, strength)

Password = Tk()
Password.title('Password tester')

label = Label(Password, text="Password:")
label.grid(row=0, column=0, sticky=W)    #Entry label

entry = Entry(width=20, bg='light blue')
entry.grid(row=1, column=0, sticky=W)     #Entry box

Button(Password, text='SUBMIT',width=5, command=click).grid(row=2,column=0, sticky=W)  #Button

label = Label(Password, text='Strength:')
label.grid(row=4, column=0, sticky=W)          #Output label

output = Text(Password, width=75, height=6, wrap=WORD, background='light blue')
output.grid(row=5, column=0, columnspan=2, sticky=W)                              #Output box

pass_Type = {
  'password': 'This is a very predicatable password. You should incorporate numbers'
}

password.mainloop()