问:
org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 75 using Selenium
I want to open the Chrome browser it displays error.

```<code>import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class Homepage {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //Create Driver object
        System.setProperty("webdriver.chrome.driver", "C:\\Workdirectory\\chromedriver.exe");
        WebDriver driver = new ChromeDriver();
    }
}
</code>```

Here I am expecting My Chrome Browser but it throws an error like

```<code>Starting ChromeDriver 75.0.3770.8 (681f24ea911fe754973dda2fdc6d2a2e159dd300-refs/branch-heads/3770@{#40}) on port 21714
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
Exception in thread "main" org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 75
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:25:48'
System info: host: 'DESKTOP-3JIP3OF', ip: '192.168.1.73', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_101'
Driver info: driver.version: ChromeDriver
</code>```

答:
This error message...

```<code>org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 75
</code>```

...implies that the ChromeDriver v75 supports Chrome Browser v75 only which wasn't available within your system.

Your main issue is the incompatibility between the version of the binaries you are using as follows:

You are using chromedriver=75.0.3770.8

Release Notes of chromedriver=75.0.3770.8 clearly mentions the following :

Supports Chrome version 75

The latest released Chrome version is chrome=74.0 which you are currently using.

So there is a clear mismatch between the ChromeDriver v75.0 and the Chrome Browser v74.0

Solution

Downgrade ChromeDriver to  ChromeDriver v74.0 level.

Keep Chrome version at Chrome v74.0 level. (as per ChromeDriver v74.0 release notes)

Execute your @Test.

Reference

You can find a relevant detailed discussion in:

How to work with a specific version of ChromeDriver while Chrome Browser gets updated automatically through Python selenium

Body:
I want to open the Chrome browser it displays error.

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;

public class Homepage {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //Create Driver object
        System.setProperty("webdriver.chrome.driver", "C:\\Workdirectory\\chromedriver.exe");
        WebDriver driver = new ChromeDriver();
    }
}

Here I am expecting My Chrome Browser but it throws an error like

Starting ChromeDriver 75.0.3770.8 (681f24ea911fe754973dda2fdc6d2a2e159dd300-refs/branch-heads/3770@{#40}) on port 21714
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.
Exception in thread "main" org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 75
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:25:48'
System info: host: 'DESKTOP-3JIP3OF', ip: '192.168.1.73', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_101'
Driver info: driver.version: ChromeDriver

Body:
This error message...

org.openqa.selenium.SessionNotCreatedException: session not created: This version of ChromeDriver only supports Chrome version 75

...implies that the ChromeDriver v75 supports Chrome Browser v75 only which wasn't available within your system.

Your main issue is the incompatibility between the version of the binaries you are using as follows:

You are using chromedriver=75.0.3770.8

Release Notes of chromedriver=75.0.3770.8 clearly mentions the following :

Supports Chrome version 75

The latest released Chrome version is chrome=74.0 which you are currently using.

So there is a clear mismatch between the ChromeDriver v75.0 and the Chrome Browser v74.0

Solution

Downgrade ChromeDriver to  ChromeDriver v74.0 level.

Keep Chrome version at Chrome v74.0 level. (as per ChromeDriver v74.0 release notes)

Execute your @Test.

Reference

You can find a relevant detailed discussion in:

How to work with a specific version of ChromeDriver while Chrome Browser gets updated automatically through Python selenium


来源: stackexchange

问:
Differentiating between an Activity launch from home screen or from another activity from App
I need to know a generic way to distinguish between a call of activity from launcher and a call from another activity from inside my app, or a BACK on the activity stack

Anyone? this is bugging me for quite a while now and i need to put it to rest...

Thanks in advance
JQCorreia

答:
In the onCreate of your Activity, call getIntent(). If the Activity is started from the launcher (home screen) the values for getAction() will be android.intent.action.MAIN and the getCategories() will return a set which will contain the android.intent.category.LAUNCHER category.
If the activity is started from elsewhere these values may be null.

ContentLicense: CC BY-SA 3.0


问:
How to validate parameters sent to an Azure function?
I m new to Azure Function. I m used to code with WebApi where I have an ActionExecutingContext which helps to validate the ModelState.
I created an ActionFilterAttribute which do it automatically:

```<code>[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class ValidateModelStateAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            //Do something
        }
    }
}
</code>```

How can I do that or something similar with Azure function?

For example with this DTO with a name property set as Required:

```<code>public class TestDto
{
    [Required]
    public string Name { get; set; }
}
</code>```

答:
I created an easy extension which validate the object and set an out parameter with the collection of errors.

```<code>public static class ObjectExtensions
{
    public static bool IsValid(this object o, out ICollection<ValidationResult> validationResults)
    {
        validationResults = new List<ValidationResult>();
        return Validator.TryValidateObject(o, new ValidationContext(o, null, null), validationResults, true);
    }
}
</code>```

So in my Azure function, here is what I have:

```<code>    [FunctionName("Create")]
    public async Task<IActionResult> CreateAsync(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "test/")] TestDto dto,
        CancellationToken cts,
        ILogger log)
    {
        if (!dto.IsValid(validationResults: out var validationResults))
        {
            return new BadRequestObjectResult($"{nameof(TestDto)} is invalid: {string.Join(", ", validationResults.Select(s => s.ErrorMessage))}");
        }
        var result = await _testManager.CreateAsync(new Test() { Name = dto.Name }, cts);
        return new OkObjectResult(result);
    }
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I m new to Azure Function. I m used to code with WebApi where I have an ActionExecutingContext which helps to validate the ModelState.
I created an ActionFilterAttribute which do it automatically:

[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class ValidateModelStateAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.ModelState.IsValid)
        {
            //Do something
        }
    }
}

How can I do that or something similar with Azure function?

For example with this DTO with a name property set as Required:

public class TestDto
{
    [Required]
    public string Name { get; set; }
}

Body:
I created an easy extension which validate the object and set an out parameter with the collection of errors.

public static class ObjectExtensions
{
    public static bool IsValid(this object o, out ICollection<ValidationResult> validationResults)
    {
        validationResults = new List<ValidationResult>();
        return Validator.TryValidateObject(o, new ValidationContext(o, null, null), validationResults, true);
    }
}

So in my Azure function, here is what I have:

    [FunctionName("Create")]
    public async Task<IActionResult> CreateAsync(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "test/")] TestDto dto,
        CancellationToken cts,
        ILogger log)
    {
        if (!dto.IsValid(validationResults: out var validationResults))
        {
            return new BadRequestObjectResult($"{nameof(TestDto)} is invalid: {string.Join(", ", validationResults.Select(s => s.ErrorMessage))}");
        }
        var result = await _testManager.CreateAsync(new Test() { Name = dto.Name }, cts);
        return new OkObjectResult(result);
    }


问:
How to fix "List Index Our of Range" error
I'm scraping a webpage, and writing the output to a .csv. I'm getting a "list index out of range" error. I think I understand what the error means, but I'm uncertain how to fix it.

The HTML code that houses the containers over which I want to iterate looks like this:

```<code><tr class="featured even" role="row"><td class="sorting_1 dcLogo">
    <a href="company/company">
    <img src="URL" alt="Company Name" width="50">
    </a>
    </td><td class="dcCompanyName"><a href="URL">Company Name</a></td><td class="dcBoothLabel">9999</td><td class="dcCategories">Widget 1, Widget 2, Widget 3</td><td class="dcCityState">CITY, STATE<br/></td><td class="dcCountry">US</td><td style="visibility:hidden;display:none;">4</td></tr>
</code>```

My code looks like this:

```<code>
page_soup = soup(page_html, "html.parser")

containers = page_soup.findAll('tr')
del containers[8]

company_names = []
booth_numbers = []
categories = []
countries = []

print("generating csv")
with open('CompanyList.csv','w') as f:
    csv_out = csv.writer(f)
    csv_out.writerow(["company_name", "booth_number", "category", "country"])
    for container in containers:
            cols = container.findAll("td")
            company_name = cols[1].find("a").text
            booth_number = cols[2].text
            category = cols[3].text.strip()
            country = cols[5].text

            company_names.append(company_name)
            booth_numbers.append(booth_number)
            categories.append(category)
            countries.append(country)

            csv_out.writerow([company_name, booth_number, category, country])

f.close
print('Done Writing to File')
</code>```

When I run this, I get an "IndexError: list index out of range" error pointing at the:

```<code>booth_number = cols[3].text
</code>```

Any help would be greatly appreciated.

答:
The problem is that the cols array has a length of less than the element you are trying to access. In the example

```<code>booth_number = cols[3].text
</code>```

the cols array has a length of 3 or less because the array indexing is zero-based (element 1 has index of 0). When you try to access the fourth element with an index of 3, you are accessing an element outside of the range.

You can remedy this with a check for the length before accessing the element.

```<code>if len(cols) > 3:
     booth_number = cols[3].text
</code>```

that way, if the booth number is not in the cols, your program does not fail and stop.

Body:
I'm scraping a webpage, and writing the output to a .csv. I'm getting a "list index out of range" error. I think I understand what the error means, but I'm uncertain how to fix it.

The HTML code that houses the containers over which I want to iterate looks like this:

    	Company Name	9999	Widget 1, Widget 2, Widget 3	CITY, STATE
	US	4

My code looks like this:

page_soup = soup(page_html, "html.parser")

containers = page_soup.findAll('tr')
del containers[8]

company_names = []
booth_numbers = []
categories = []
countries = []

print("generating csv")
with open('CompanyList.csv','w') as f:
    csv_out = csv.writer(f)
    csv_out.writerow(["company_name", "booth_number", "category", "country"])
    for container in containers:
            cols = container.findAll("td")
            company_name = cols[1].find("a").text
            booth_number = cols[2].text
            category = cols[3].text.strip()
            country = cols[5].text

            company_names.append(company_name)
            booth_numbers.append(booth_number)
            categories.append(category)
            countries.append(country)

            csv_out.writerow([company_name, booth_number, category, country])

f.close
print('Done Writing to File')

When I run this, I get an "IndexError: list index out of range" error pointing at the:

booth_number = cols[3].text

Any help would be greatly appreciated.

Body:
The problem is that the cols array has a length of less than the element you are trying to access. In the example

booth_number = cols[3].text

the cols array has a length of 3 or less because the array indexing is zero-based (element 1 has index of 0). When you try to access the fourth element with an index of 3, you are accessing an element outside of the range.

You can remedy this with a check for the length before accessing the element.

if len(cols) > 3:
     booth_number = cols[3].text

that way, if the booth number is not in the cols, your program does not fail and stop.


问:
Add fds in the GLIB mainloop
I need to attach file descriptors to the GLIB mainloop. My issue is that the list of file descriptors is not fixed during execution.

According to GLIB documentation, I can:

create a GIOChannel for each FD using g_io_channel_unix_new and attach it to the context with g_io_add_watch

Use a Gsource created with g_io_create_watch and set a callback g_source_set_callback

My question is : is it possible to modify dynamically a source or a context. And how can I do it ? I find the GSourceFuncs ability, but that doesn't fit my issue.

Thanks for your help.

答:
Have you read the Main Event Loop documentation? The description section has a pretty good explanation of how things work.

Have you looked at the Custom GSource tutorial? This allows you to extend a GSource object to include your own state. You also can write your own prepare, dispatch, query, and check functions.

Whenever I really want to see how something should be done with GLib, GTK, etc  the first place I look is the test code that lives in their git repository. Be sure to checkout the proper tag for the version of that you are targeting.

For example I currently target 2.48.2

Here are two pretty good examples
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/tests/mainloop-test.c
https://gitlab.gnome.org/GNOME/glib/blob/2.48.2/glib/tests/mainloop.c

The other nice feature is it's a git repository so you can search it very easily.

Title: Add fds in the GLIB mainloop


问:
Why does this sequence of MOV and ADD with memory produce AX=90FFh?
I actually have a problem with MOV AX,[SI]. I don't understand why the final result is AH=90h AL=FFh.

```<code>ORG 100h
MOV [110h],80h
MOV SI,110h
ADD [SI], 7Fh
MOV AX, [SI]
</code>```

答:
Instructions like mov [110h], 80h and add [si], 7Fh are ambiguous because the assembler does not know what size you desire them to have. Do you want to process bytes (1 byte) or do you want to deal with words (2 bytes)?

Apparently emu8086 chooses the byte size by default!

The byte at address 110h was filled with 80h, later raised by 7Fh which produced FFh, but then you started reading a whole word at address 110h. You received the correct sum in AL and AH got whatever garbage was in the memory at address 111h.

Better always specify the size you need:

words

```<code>ORG     100h
mov     word ptr [0110h], 0080h
mov     si, 0110h
add     word ptr [si], 007Fh
mov     ax, [si]        >>>> AX=01FFh  AH=01h AL=FFh
</code>```

bytes

```<code>ORG     100h
mov     byte ptr [0110h], 80h
mov     si, 0110h
add     byte ptr [si], 7Fh
mov     ax, [si]        >>>> AX=??FFh  AH=??h AL=FFh
</code>```

Maybe using mov al, [si] would be more appropriate in this case.

Pay attention to the program length.

Depending on the version this little program has 13 or 14 bytes. This means it doesn't run into the memory at address 110h. If it were then the instructions would corrupt the program and maybe crash the computer.

You could store the numbers elsewhere to be safe, e.g. address 1000h, leaving more room to experiment with the instruction set...

Body:
I actually have a problem with MOV AX,[SI]. I don't understand why the final result is AH=90h AL=FFh.

ORG 100h
MOV [110h],80h
MOV SI,110h
ADD [SI], 7Fh
MOV AX, [SI]

Body:
Instructions like mov [110h], 80h and add [si], 7Fh are ambiguous because the assembler does not know what size you desire them to have. Do you want to process bytes (1 byte) or do you want to deal with words (2 bytes)?

Apparently emu8086 chooses the byte size by default!

The byte at address 110h was filled with 80h, later raised by 7Fh which produced FFh, but then you started reading a whole word at address 110h. You received the correct sum in AL and AH got whatever garbage was in the memory at address 111h.

Better always specify the size you need:

words

ORG     100h
mov     word ptr [0110h], 0080h
mov     si, 0110h
add     word ptr [si], 007Fh
mov     ax, [si]        >>>> AX=01FFh  AH=01h AL=FFh

bytes

ORG     100h
mov     byte ptr [0110h], 80h
mov     si, 0110h
add     byte ptr [si], 7Fh
mov     ax, [si]        >>>> AX=??FFh  AH=??h AL=FFh

Maybe using mov al, [si] would be more appropriate in this case.

Pay attention to the program length.

Depending on the version this little program has 13 or 14 bytes. This means it doesn't run into the memory at address 110h. If it were then the instructions would corrupt the program and maybe crash the computer.

You could store the numbers elsewhere to be safe, e.g. address 1000h, leaving more room to experiment with the instruction set...


问:
Read file and write file
Can't seem to get my data to be read as an integer and print out the data. plus there is a close stream (IOError) for count = aFile.gets in def read (afile) function.
This program includes Array, files and loops. The purpose of this program is to take a number 10 and write the number to a file then on each line increment from zero to 10 that is passed.</p>

```<code># takes a number and writes that number to a file then on each line
# increments from zero to the number passed
def write(aFile, number)
  # You might need to fix this next line:
  aFile.puts("number")
  index = 0
  while (index < number)
   aFile.puts(number.to_s)
   index += 1
  end
end

# Read the data from the file and print out each line
def read(aFile)

  # Defensive programming:
  count = aFile.gets
  if (is_numeric(count))
    count = count.to_i
  else
    count = 0
    puts "Error: first line of file is not a number"
  end

  index = 0
  while (count < index)
    line = aFile.gets
    puts "Line read: " + line
  end
end

# Write data to a file then read it in and print it out
def main
  aFile = File.new("mydata.txt", "w") # open for writing
  if aFile  # if nil this test will be false
    write(aFile, 10)
  else
    puts "Unable to open file to write!"
  end

  if aFile
    read(aFile)
  end
  aFile.close
end

# returns true if a string contains only digits
def is_numeric?(obj)
  if /[^0-9]/.match(obj) == nil
    true
  end
  false
end

main

</code>```

答:
If you want to make your code work, change:

```<code>aFile = File.new("mydata.txt", "w")
</code>```

to:

```<code>aFile = File.new("mydata.txt", "r+")
</code>```

You can change:

```<code> count = aFile.gets
 if (is_numeric(count))
</code>```

to:

```<code>  count = aFile.gets.to_i
 if (count.is_a?(Fixnum))
</code>```

and then get rid of the is_numeric?(obj) method.

Also you're not incrementing the counter, you can fix that as well.

Title: Read file and write file

Body:
Can't seem to get my data to be read as an integer and print out the data. plus there is a close stream (IOError) for count = aFile.gets in def read (afile) function.
This program includes Array, files and loops. The purpose of this program is to take a number 10 and write the number to a file then on each line increment from zero to 10 that is passed.

# takes a number and writes that number to a file then on each line
# increments from zero to the number passed
def write(aFile, number)
  # You might need to fix this next line:
  aFile.puts("number")
  index = 0
  while (index < number)
   aFile.puts(number.to_s)
   index += 1
  end
end

# Read the data from the file and print out each line
def read(aFile)

  # Defensive programming:
  count = aFile.gets
  if (is_numeric(count))
    count = count.to_i
  else
    count = 0
    puts "Error: first line of file is not a number"
  end

  index = 0
  while (count < index)
    line = aFile.gets
    puts "Line read: " + line
  end
end

# Write data to a file then read it in and print it out
def main
  aFile = File.new("mydata.txt", "w") # open for writing
  if aFile  # if nil this test will be false
    write(aFile, 10)
  else
    puts "Unable to open file to write!"
  end

  if aFile
    read(aFile)
  end
  aFile.close
end

# returns true if a string contains only digits
def is_numeric?(obj)
  if /[^0-9]/.match(obj) == nil
    true
  end
  false
end

main

Body:
If you want to make your code work, change:

aFile = File.new("mydata.txt", "w")

to:

aFile = File.new("mydata.txt", "r+")

You can change:

 count = aFile.gets
 if (is_numeric(count))

to:

  count = aFile.gets.to_i
 if (count.is_a?(Fixnum))

and then get rid of the is_numeric?(obj) method.

Also you're not incrementing the counter, you can fix that as well.


问:
Drag-and-drop Javascript if Statement Problem
I'm currently developing a javascript game utilising the drag and drop feature of HTML.
What I'm trying to do here is to allow randomly generated fruit images to be draggable and droppable onto the jelly image. Then if the dragged image is matching condition set (which is when number image array index == x, and fruit image index is == y), allow it to drop.
And in order to declare this if statement, I'm grabbing the value from background image. (If the background image of number is x, and background image of fruit is y)
My code was executing fine until I tried to set a condition to it. And logically I don't understand why it won't work when there's an if statement to it, it even won't display images.

Edit: tried using === instead of =, still not responsive

Edit: after removing the semicolon as in comment, the rest of the code executes fine. However drag and drop won't respond.

Edit: declared variables of image urls instead of using urls directly in on drop function. Drag and drop still doesn't work.

var myNumber = new Array(9);

myNumber[0] = '1.png';
myNumber[1] = '2.png';
myNumber[2] = '3.png';
myNumber[3] = '4.png';
myNumber[4] = '5.png';
myNumber[5] = '6.png';
myNumber[6] = '7.png';
myNumber[7] = '8.png';
myNumber[8] = '9.png';

var numberImage1 =  "url(" + numberAddress + myNumber[0] + ")";
var numberImage2 =  "url(" + numberAddress + myNumber[1] + ")";
var numberImage3 =  "url(" + numberAddress + myNumber[2] + ")";
var numberImage4 =  "url(" + numberAddress + myNumber[3] + ")";
var numberImage5 =  "url(" + numberAddress + myNumber[4] + ")";
var numberImage6 =  "url(" + numberAddress + myNumber[5] + ")";
var numberImage7 =  "url(" + numberAddress + myNumber[6] + ")";
var numberImage8 =  "url(" + numberAddress + myNumber[7] + ")";
var numberImage9 =  "url(" + numberAddress + myNumber[8] + ")";

var fruitCloudOne = new Array(15);

fruitCloudOne[0] = '3apple.png';
fruitCloudOne[1] = '3banana.png';
fruitCloudOne[2] = '3blueberry.png';
fruitCloudOne[3] = '3plum.png';
fruitCloudOne[4] = '3strawberry.png';

fruitCloudOne[5] = '5apple.png';
fruitCloudOne[6] = '5banana.png';
fruitCloudOne[7] = '5blueberry.png';
fruitCloudOne[8] = '5plum.png';
fruitCloudOne[9] = '5strawberry.png';

fruitCloudOne[10] = '8apple.png';
fruitCloudOne[11] = '8banana.png';
fruitCloudOne[12] = '8blueberry.png';
fruitCloudOne[13] = '8plum.png';
fruitCloudOne[14] = '8strawberry.png';

var apple3 = "url(" + fruit1Address + fruitCloudOne[0] + ")";
var banana3 = "url(" + fruit1Address + fruitCloudOne[1] + ")";
var blueberry3 = "url(" + fruit1Address + fruitCloudOne[2] + ")";
var plum3 = "url(" + fruit1Address + fruitCloudOne[3] + ")";
var strawberry3 = "url(" + fruit1Address + fruitCloudOne[4] + ")";

var apple5 = "url(" + fruit1Address + fruitCloudOne[5] + ")";
var banana5 = "url(" + fruit1Address + fruitCloudOne[6] + ")";
var blueberry5 = "url(" + fruit1Address + fruitCloudOne[7] + ")";
var plum5 = "url(" + fruit1Address + fruitCloudOne[8] + ")";
var strawberry5 = "url(" + fruit1Address + fruitCloudOne[9] + ")";

var apple8 = "url(" + fruit1Address + fruitCloudOne[10] + ")";
var banana8 = "url(" + fruit1Address + fruitCloudOne[11] + ")";
var blueberry8 = "url(" + fruit1Address + fruitCloudOne[12] + ")";
var plum8 = "url(" + fruit1Address + fruitCloudOne[13] + ")";
var strawberry8 = "url(" + fruit1Address + fruitCloudOne[14] + ")";

var fruitCloudTwo = new Array(15);

fruitCloudTwo[0] = '1apple.png';
fruitCloudTwo[1] = '1banana.png';
fruitCloudTwo[2] = '1blueberry.png';
fruitCloudTwo[3] = '1plum.png';
fruitCloudTwo[4] = '1strawberry.png';

fruitCloudTwo[5] = '2apple.png';
fruitCloudTwo[6] = '2banana.png';
fruitCloudTwo[7] = '2blueberry.png';
fruitCloudTwo[8] = '2plum.png';
fruitCloudTwo[9] = '2strawberry.png';

fruitCloudTwo[10] = '4apple.png';
fruitCloudTwo[11] = '4banana.png';
fruitCloudTwo[12] = '4blueberry.png';
fruitCloudTwo[13] = '4plum.png';
fruitCloudTwo[14] = '4strawberry.png';

var apple1 = "url(" + fruit2Address + fruitCloudTwo[0] + ")";
var banana1 = "url(" + fruit2Address + fruitCloudTwo[1] + ")";
var blueberry1 = "url(" + fruit2Address + fruitCloudTwo[2] + ")";
var plum1 = "url(" + fruit2Address + fruitCloudTwo[3] + ")";
var strawberry1 = "url(" + fruit2Address + fruitCloudTwo[4] + ")";

var apple2 = "url(" + fruit2Address + fruitCloudTwo[5] + ")";
var banana2 = "url(" + fruit2Address + fruitCloudTwo[6] + ")";
var blueberry2 = "url(" + fruit2Address + fruitCloudTwo[7] + ")";
var plum2 = "url(" + fruit2Address + fruitCloudTwo[8] + ")";
var strawberry2 = "url(" + fruit2Address + fruitCloudTwo[9] + ")";

var apple4 = "url(" + fruit2Address + fruitCloudTwo[10] + ")";
var banana4 = "url(" + fruit2Address + fruitCloudTwo[11] + ")";
var blueberry4 = "url(" + fruit2Address + fruitCloudTwo[12] + ")";
var plum4 = "url(" + fruit2Address + fruitCloudTwo[13] + ")";
var strawberry4 = "url(" + fruit2Address + fruitCloudTwo[14] + ")";

var fruitCloudThree = new Array(15);

fruitCloudThree[0] = '6apple.png';
fruitCloudThree[1] = '6banana.png';
fruitCloudThree[2] = '6blueberry.png';
fruitCloudThree[3] = '6plum.png';
fruitCloudThree[4] = '6strawberry.png';

fruitCloudThree[5] = '7apple.png';
fruitCloudThree[6] = '7banana.png';
fruitCloudThree[7] = '7blueberry.png';
fruitCloudThree[8] = '7plum.png';
fruitCloudThree[9] = '7strawberry.png';

fruitCloudThree[10] = '9apple.png';
fruitCloudThree[11] = '9banana.png';
fruitCloudThree[12] = '9blueberry.png';
fruitCloudThree[13] = '9plum.png';
fruitCloudThree[14] = '9strawberry.png';

var apple6 = "url(" + fruit3Address + fruitCloudThree[0] + ")";
var banana6 = "url(" + fruit3Address + fruitCloudThree[1] + ")";
var blueberry6 = "url(" + fruit3Address + fruitCloudThree[2] + ")";
var plum6 = "url(" + fruit3Address + fruitCloudThree[3] + ")";
var strawberry6 = "url(" + fruit3Address + fruitCloudThree[4] + ")";

var apple7 = "url(" + fruit3Address + fruitCloudThree[5] + ")";
var banana7 = "url(" + fruit3Address + fruitCloudThree[6] + ")";
var blueberry7 = "url(" + fruit3Address + fruitCloudThree[7] + ")";
var plum7 = "url(" + fruit3Address + fruitCloudThree[8] + ")";
var strawberry7 = "url(" + fruit3Address + fruitCloudThree[9] + ")";

var apple9 = "url(" + fruit3Address + fruitCloudThree[10] + ")";
var banana9 = "url(" + fruit3Address + fruitCloudThree[11] + ")";
var blueberry9 = "url(" + fruit3Address + fruitCloudThree[12] + ")";
var plum9 = "url(" + fruit3Address + fruitCloudThree[13] + ")";
var strawberry9 = "url(" + fruit3Address + fruitCloudThree[14] + ")";

//random generation of number and fruits & display
var numberAddress = 'Assets/Numbers/';

var fruit1Address = 'Assets/FruitCloud1/';
var randFruit1 = Math.floor(Math.random() * (fruitCloudOne.length));
var randFruit1Image = "url(" + fruit1Address + fruitCloudOne[randFruit1] + ")";

var fruit2Address = 'Assets/FruitCloud2/';
var randFruit2 = Math.floor(Math.random() * (fruitCloudTwo.length));
var randFruit2Image = "url(" + fruit2Address + fruitCloudTwo[randFruit2] + ")";

var fruit3Address = 'Assets/FruitCloud3/';
var randFruit3 = Math.floor(Math.random() * (fruitCloudThree.length));
var randFruit3Image = "url(" + fruit3Address + fruitCloudThree[randFruit3] + ")";

//refresh fruit images
function refreshFruits() {
    var fruit1Address = 'Assets/FruitCloud1/';
    var randFruit1 = Math.floor(Math.random() * (fruitCloudOne.length));
    var randFruit1Image = "url(" + fruit1Address + fruitCloudOne[randFruit1] + ")";
    document.getElementById("fruit1").style.backgroundImage = randFruit1Image;

    var fruit2Address = 'Assets/FruitCloud2/';
    var randFruit2 = Math.floor(Math.random() * (fruitCloudTwo.length));
    var randFruit2Image = "url(" + fruit2Address + fruitCloudTwo[randFruit2] + ")";
    document.getElementById("fruit2").style.backgroundImage = randFruit2Image;

    var fruit3Address = 'Assets/FruitCloud3/';
    var randFruit3 = Math.floor(Math.random() * (fruitCloudThree.length));
    var randFruit3Image = "url(" + fruit3Address + fruitCloudThree[randFruit3] + ")";
    document.getElementById("fruit3").style.backgroundImage = randFruit3Image;
}

//display number and three fruit images
function startGame() {
    var numberImage1 =  "url(" + numberAddress + myNumber[0] + ")";
    document.getElementById("number").style.backgroundImage = numberImage1;

    document.getElementById("fruit1").style.backgroundImage = randFruit1Image;

    document.getElementById("fruit2").style.backgroundImage = randFruit2Image;

    document.getElementById("fruit3").style.backgroundImage = randFruit3Image;
}

function dragOver(ev) {
    ev.preventDefault();
}

function dragStart(ev) {
    ev.dataTransfer.setData("fruit", ev.target.id);
}

function onDrop(ev) {
    var numberImage1 =  "url(" + numberAddress + myNumber[0] + ")";
    var apple1 = "url(" + fruit2Address + fruitCloudTwo[0] + ")";
    var banana1 = "url(" + fruit2Address + fruitCloudTwo[1] + ")";
    var blueberry1 = "url(" + fruit2Address + fruitCloudTwo[2] + ")";
    var plum1 = "url(" + fruit2Address + fruitCloudTwo[3] + ")";
    var strawberry1 = "url(" + fruit2Address + fruitCloudTwo[4] + ")";

    ev.preventDefault();
    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == apple1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == banana1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == blueberry1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == plum1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == strawberry1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }
}```
<pre class="snippet-code-css lang-css prettyprint-override"><code>body {
    width: 100%;
    max-width: 100%;
    margin: 0;
    overflow: hidden;
    padding: 0;
    background-color: black;
}

#background {
    position: absolute;
    background-image: url(Assets/Background_cloudPosition.png);
    background-size: cover;
    background-repeat: no-repeat;
    width: 100%;
    height: 100%;
    bottom: 0%;
    z-index: -10;
}

#startGame {
    position: absolute;
    left: 90px;
    width: 80px;
    height: 80px;
    background-color: green;
}

#refreshFruits {
    position: absolute;
    left: 180px;
    width: 80px;
    height: 80px;
    background-color: blue;
}

#number {
    position: absolute;
    width: 230px;
    height: 230px;
    left: 450px;
    bottom: 415px;
    background-size: contain;
    background-repeat: no-repeat;
    z-index: 15;
}

#fruitCloud1 {
    position: absolute;
    width: 240px;
    height: 120px;
    bottom: 460px;
    left: 135px;
    z-index: 15;
}

#fruitCloud2 {
    position: absolute;
    width: 240px;
    height: 120px;
    bottom: 320px;
    left: 300px;
    z-index: 15;
}

#fruitCloud3 {
    position: absolute;
    width: 240px;
    height: 120px;
    bottom: 185px;
    left: 110px;
    z-index: 15;
}

#fruit1 {
    position: absolute;
    width: 240px;
    height: 120px;
    background-size: contain;
    background-repeat: no-repeat;
}

#fruit2 {
    position: absolute;
    width: 240px;
    height: 120px;
    background-size: contain;
    background-repeat: no-repeat;
}

#fruit3 {
    position: absolute;
    width: 240px;
    height: 120px;
    background-size: contain;
    background-repeat: no-repeat;
}

#jelly {
    position: absolute;
    background-image: url(Assets/JellyMonster/JellyMonsterDefault.png);
    background-size: contain;
    background-repeat: no-repeat;
    width: 260px;
    height: 190px;
    bottom: 50px;
    right: 390px;
    z-index: 10;
}</code>```

<!DOCTYPE html>

    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="stylesheet.css">

    <title>This is an experiment.</title>

<button id="startGame" onclick="startGame()"></button>
<button id="refreshFruits" onclick="refreshFruits()"></button>

```

答:
I also found a more ideal way to test this.
Instead of testing background images, I used the if condition to test whether the dragged data's id is matching the id of the div wanted.
To do this, I had to put all images in one array and alter random generation of the fruit images to make sure I will always get the image I want for each stage.</p>

Body:
I'm currently developing a javascript game utilising the drag and drop feature of HTML.
What I'm trying to do here is to allow randomly generated fruit images to be draggable and droppable onto the jelly image. Then if the dragged image is matching condition set (which is when number image array index == x, and fruit image index is == y), allow it to drop.
And in order to declare this if statement, I'm grabbing the value from background image. (If the background image of number is x, and background image of fruit is y)
My code was executing fine until I tried to set a condition to it. And logically I don't understand why it won't work when there's an if statement to it, it even won't display images.

Edit: tried using === instead of =, still not responsive

Edit: after removing the semicolon as in comment, the rest of the code executes fine. However drag and drop won't respond.

Edit: declared variables of image urls instead of using urls directly in on drop function. Drag and drop still doesn't work.

var myNumber = new Array(9);

myNumber[0] = '1.png';
myNumber[1] = '2.png';
myNumber[2] = '3.png';
myNumber[3] = '4.png';
myNumber[4] = '5.png';
myNumber[5] = '6.png';
myNumber[6] = '7.png';
myNumber[7] = '8.png';
myNumber[8] = '9.png';

var numberImage1 =  "url(" + numberAddress + myNumber[0] + ")";
var numberImage2 =  "url(" + numberAddress + myNumber[1] + ")";
var numberImage3 =  "url(" + numberAddress + myNumber[2] + ")";
var numberImage4 =  "url(" + numberAddress + myNumber[3] + ")";
var numberImage5 =  "url(" + numberAddress + myNumber[4] + ")";
var numberImage6 =  "url(" + numberAddress + myNumber[5] + ")";
var numberImage7 =  "url(" + numberAddress + myNumber[6] + ")";
var numberImage8 =  "url(" + numberAddress + myNumber[7] + ")";
var numberImage9 =  "url(" + numberAddress + myNumber[8] + ")";

var fruitCloudOne = new Array(15);

fruitCloudOne[0] = '3apple.png';
fruitCloudOne[1] = '3banana.png';
fruitCloudOne[2] = '3blueberry.png';
fruitCloudOne[3] = '3plum.png';
fruitCloudOne[4] = '3strawberry.png';

fruitCloudOne[5] = '5apple.png';
fruitCloudOne[6] = '5banana.png';
fruitCloudOne[7] = '5blueberry.png';
fruitCloudOne[8] = '5plum.png';
fruitCloudOne[9] = '5strawberry.png';

fruitCloudOne[10] = '8apple.png';
fruitCloudOne[11] = '8banana.png';
fruitCloudOne[12] = '8blueberry.png';
fruitCloudOne[13] = '8plum.png';
fruitCloudOne[14] = '8strawberry.png';

var apple3 = "url(" + fruit1Address + fruitCloudOne[0] + ")";
var banana3 = "url(" + fruit1Address + fruitCloudOne[1] + ")";
var blueberry3 = "url(" + fruit1Address + fruitCloudOne[2] + ")";
var plum3 = "url(" + fruit1Address + fruitCloudOne[3] + ")";
var strawberry3 = "url(" + fruit1Address + fruitCloudOne[4] + ")";

var apple5 = "url(" + fruit1Address + fruitCloudOne[5] + ")";
var banana5 = "url(" + fruit1Address + fruitCloudOne[6] + ")";
var blueberry5 = "url(" + fruit1Address + fruitCloudOne[7] + ")";
var plum5 = "url(" + fruit1Address + fruitCloudOne[8] + ")";
var strawberry5 = "url(" + fruit1Address + fruitCloudOne[9] + ")";

var apple8 = "url(" + fruit1Address + fruitCloudOne[10] + ")";
var banana8 = "url(" + fruit1Address + fruitCloudOne[11] + ")";
var blueberry8 = "url(" + fruit1Address + fruitCloudOne[12] + ")";
var plum8 = "url(" + fruit1Address + fruitCloudOne[13] + ")";
var strawberry8 = "url(" + fruit1Address + fruitCloudOne[14] + ")";

var fruitCloudTwo = new Array(15);

fruitCloudTwo[0] = '1apple.png';
fruitCloudTwo[1] = '1banana.png';
fruitCloudTwo[2] = '1blueberry.png';
fruitCloudTwo[3] = '1plum.png';
fruitCloudTwo[4] = '1strawberry.png';

fruitCloudTwo[5] = '2apple.png';
fruitCloudTwo[6] = '2banana.png';
fruitCloudTwo[7] = '2blueberry.png';
fruitCloudTwo[8] = '2plum.png';
fruitCloudTwo[9] = '2strawberry.png';

fruitCloudTwo[10] = '4apple.png';
fruitCloudTwo[11] = '4banana.png';
fruitCloudTwo[12] = '4blueberry.png';
fruitCloudTwo[13] = '4plum.png';
fruitCloudTwo[14] = '4strawberry.png';

var apple1 = "url(" + fruit2Address + fruitCloudTwo[0] + ")";
var banana1 = "url(" + fruit2Address + fruitCloudTwo[1] + ")";
var blueberry1 = "url(" + fruit2Address + fruitCloudTwo[2] + ")";
var plum1 = "url(" + fruit2Address + fruitCloudTwo[3] + ")";
var strawberry1 = "url(" + fruit2Address + fruitCloudTwo[4] + ")";

var apple2 = "url(" + fruit2Address + fruitCloudTwo[5] + ")";
var banana2 = "url(" + fruit2Address + fruitCloudTwo[6] + ")";
var blueberry2 = "url(" + fruit2Address + fruitCloudTwo[7] + ")";
var plum2 = "url(" + fruit2Address + fruitCloudTwo[8] + ")";
var strawberry2 = "url(" + fruit2Address + fruitCloudTwo[9] + ")";

var apple4 = "url(" + fruit2Address + fruitCloudTwo[10] + ")";
var banana4 = "url(" + fruit2Address + fruitCloudTwo[11] + ")";
var blueberry4 = "url(" + fruit2Address + fruitCloudTwo[12] + ")";
var plum4 = "url(" + fruit2Address + fruitCloudTwo[13] + ")";
var strawberry4 = "url(" + fruit2Address + fruitCloudTwo[14] + ")";

var fruitCloudThree = new Array(15);

fruitCloudThree[0] = '6apple.png';
fruitCloudThree[1] = '6banana.png';
fruitCloudThree[2] = '6blueberry.png';
fruitCloudThree[3] = '6plum.png';
fruitCloudThree[4] = '6strawberry.png';

fruitCloudThree[5] = '7apple.png';
fruitCloudThree[6] = '7banana.png';
fruitCloudThree[7] = '7blueberry.png';
fruitCloudThree[8] = '7plum.png';
fruitCloudThree[9] = '7strawberry.png';

fruitCloudThree[10] = '9apple.png';
fruitCloudThree[11] = '9banana.png';
fruitCloudThree[12] = '9blueberry.png';
fruitCloudThree[13] = '9plum.png';
fruitCloudThree[14] = '9strawberry.png';

var apple6 = "url(" + fruit3Address + fruitCloudThree[0] + ")";
var banana6 = "url(" + fruit3Address + fruitCloudThree[1] + ")";
var blueberry6 = "url(" + fruit3Address + fruitCloudThree[2] + ")";
var plum6 = "url(" + fruit3Address + fruitCloudThree[3] + ")";
var strawberry6 = "url(" + fruit3Address + fruitCloudThree[4] + ")";

var apple7 = "url(" + fruit3Address + fruitCloudThree[5] + ")";
var banana7 = "url(" + fruit3Address + fruitCloudThree[6] + ")";
var blueberry7 = "url(" + fruit3Address + fruitCloudThree[7] + ")";
var plum7 = "url(" + fruit3Address + fruitCloudThree[8] + ")";
var strawberry7 = "url(" + fruit3Address + fruitCloudThree[9] + ")";

var apple9 = "url(" + fruit3Address + fruitCloudThree[10] + ")";
var banana9 = "url(" + fruit3Address + fruitCloudThree[11] + ")";
var blueberry9 = "url(" + fruit3Address + fruitCloudThree[12] + ")";
var plum9 = "url(" + fruit3Address + fruitCloudThree[13] + ")";
var strawberry9 = "url(" + fruit3Address + fruitCloudThree[14] + ")";

//random generation of number and fruits & display
var numberAddress = 'Assets/Numbers/';

var fruit1Address = 'Assets/FruitCloud1/';
var randFruit1 = Math.floor(Math.random() * (fruitCloudOne.length));
var randFruit1Image = "url(" + fruit1Address + fruitCloudOne[randFruit1] + ")";

var fruit2Address = 'Assets/FruitCloud2/';
var randFruit2 = Math.floor(Math.random() * (fruitCloudTwo.length));
var randFruit2Image = "url(" + fruit2Address + fruitCloudTwo[randFruit2] + ")";

var fruit3Address = 'Assets/FruitCloud3/';
var randFruit3 = Math.floor(Math.random() * (fruitCloudThree.length));
var randFruit3Image = "url(" + fruit3Address + fruitCloudThree[randFruit3] + ")";

//refresh fruit images
function refreshFruits() {
    var fruit1Address = 'Assets/FruitCloud1/';
    var randFruit1 = Math.floor(Math.random() * (fruitCloudOne.length));
    var randFruit1Image = "url(" + fruit1Address + fruitCloudOne[randFruit1] + ")";
    document.getElementById("fruit1").style.backgroundImage = randFruit1Image;

    var fruit2Address = 'Assets/FruitCloud2/';
    var randFruit2 = Math.floor(Math.random() * (fruitCloudTwo.length));
    var randFruit2Image = "url(" + fruit2Address + fruitCloudTwo[randFruit2] + ")";
    document.getElementById("fruit2").style.backgroundImage = randFruit2Image;

    var fruit3Address = 'Assets/FruitCloud3/';
    var randFruit3 = Math.floor(Math.random() * (fruitCloudThree.length));
    var randFruit3Image = "url(" + fruit3Address + fruitCloudThree[randFruit3] + ")";
    document.getElementById("fruit3").style.backgroundImage = randFruit3Image;
}

//display number and three fruit images
function startGame() {
    var numberImage1 =  "url(" + numberAddress + myNumber[0] + ")";
    document.getElementById("number").style.backgroundImage = numberImage1;

    document.getElementById("fruit1").style.backgroundImage = randFruit1Image;

    document.getElementById("fruit2").style.backgroundImage = randFruit2Image;

    document.getElementById("fruit3").style.backgroundImage = randFruit3Image;
}

function dragOver(ev) {
    ev.preventDefault();
}

function dragStart(ev) {
    ev.dataTransfer.setData("fruit", ev.target.id);
}

function onDrop(ev) {
    var numberImage1 =  "url(" + numberAddress + myNumber[0] + ")";
    var apple1 = "url(" + fruit2Address + fruitCloudTwo[0] + ")";
    var banana1 = "url(" + fruit2Address + fruitCloudTwo[1] + ")";
    var blueberry1 = "url(" + fruit2Address + fruitCloudTwo[2] + ")";
    var plum1 = "url(" + fruit2Address + fruitCloudTwo[3] + ")";
    var strawberry1 = "url(" + fruit2Address + fruitCloudTwo[4] + ")";

    ev.preventDefault();
    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == apple1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == banana1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == blueberry1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == plum1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }

    if (document.getElementById("number").style.backgroundImage == numberImage1 && document.getElementById("fruit2").style.backgroundImage == strawberry1) {
        var data = ev.dataTransfer.getData("fruit");
        ev.target.appendChild(document.getElementById(data));
    }
}

body {
    width: 100%;
    max-width: 100%;
    margin: 0;
    overflow: hidden;
    padding: 0;
    background-color: black;
}

#background {
    position: absolute;
    background-image: url(Assets/Background_cloudPosition.png);
    background-size: cover;
    background-repeat: no-repeat;
    width: 100%;
    height: 100%;
    bottom: 0%;
    z-index: -10;
}

#startGame {
    position: absolute;
    left: 90px;
    width: 80px;
    height: 80px;
    background-color: green;
}

#refreshFruits {
    position: absolute;
    left: 180px;
    width: 80px;
    height: 80px;
    background-color: blue;
}

#number {
    position: absolute;
    width: 230px;
    height: 230px;
    left: 450px;
    bottom: 415px;
    background-size: contain;
    background-repeat: no-repeat;
    z-index: 15;
}

#fruitCloud1 {
    position: absolute;
    width: 240px;
    height: 120px;
    bottom: 460px;
    left: 135px;
    z-index: 15;
}

#fruitCloud2 {
    position: absolute;
    width: 240px;
    height: 120px;
    bottom: 320px;
    left: 300px;
    z-index: 15;
}

#fruitCloud3 {
    position: absolute;
    width: 240px;
    height: 120px;
    bottom: 185px;
    left: 110px;
    z-index: 15;
}

#fruit1 {
    position: absolute;
    width: 240px;
    height: 120px;
    background-size: contain;
    background-repeat: no-repeat;
}

#fruit2 {
    position: absolute;
    width: 240px;
    height: 120px;
    background-size: contain;
    background-repeat: no-repeat;
}

#fruit3 {
    position: absolute;
    width: 240px;
    height: 120px;
    background-size: contain;
    background-repeat: no-repeat;
}

#jelly {
    position: absolute;
    background-image: url(Assets/JellyMonster/JellyMonsterDefault.png);
    background-size: contain;
    background-repeat: no-repeat;
    width: 260px;
    height: 190px;
    bottom: 50px;
    right: 390px;
    z-index: 10;
}

<!DOCTYPE html>

    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="stylesheet.css">

    <title>This is an experiment.</title>

<button id="startGame" onclick="startGame()"></button>
<button id="refreshFruits" onclick="refreshFruits()"></button>


问:
Insert if not exists?
I'm prompting a user to add an item to an SQLiteDb. When they click add, I want to check if that item already exists... if it doesn't then I want to insert it.

I make the call

```<code>mDbHelper.createNote(inputLine.getText().toString().trim(), mTable[i]);
</code>```

Which calls...

```<code>public long createNote(String value, String table) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(table, value);

        return mDb.insert(table, null, initialValues);
    }
</code>```

Thats works but it doesn't check if the item already exists, so it still inserts duplicates. So I tried

```<code>return mDb.insertWithOnConflict(table, null, initialValues, SQLiteDatabase.CONFLICT_FAIL);
</code>```

However, it doesn't appear to recognize insertWIthOnConflict or SQLiteDatabase.CONFLICT_FAIL...

How can I get this to work?

Edit: it's 1 table, 2 rows. table name = note, rows = _id, note.

答:
In such situation I perfrom such checking:

```<code>if (!checkRecordExist(DATABASE_TABLE, new String[] {KEY_1, KEY_2}, new String[] {value_1, value_2}))
database.insert(DATABASE_TABLE, null, updateValues);
</code>```

where

```<code>private boolean checkRecordExist(String tableName, String[] keys, String [] values) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < keys.length; i++) {
        sb.append(keys[i])
            .append("=\"")
            .append(values[i])
            .append("\" ");
        if (i<keys.length-1) sb.append("AND ");
    }

    Cursor cursor = database.query(tableName, null, sb.toString(), null, null, null, null);
    boolean exists = (cursor.getCount() > 0);
    cursor.close();
    return exists;
}
</code>```

Title: Insert if not exists?

Body:
I'm prompting a user to add an item to an SQLiteDb. When they click add, I want to check if that item already exists... if it doesn't then I want to insert it.

I make the call

mDbHelper.createNote(inputLine.getText().toString().trim(), mTable[i]);

Which calls...

public long createNote(String value, String table) {
        ContentValues initialValues = new ContentValues();
        initialValues.put(table, value);

        return mDb.insert(table, null, initialValues);
    }

Thats works but it doesn't check if the item already exists, so it still inserts duplicates. So I tried

return mDb.insertWithOnConflict(table, null, initialValues, SQLiteDatabase.CONFLICT_FAIL);

However, it doesn't appear to recognize insertWIthOnConflict or SQLiteDatabase.CONFLICT_FAIL...

How can I get this to work?

Edit: it's 1 table, 2 rows. table name = note, rows = _id, note.

Body:
In such situation I perfrom such checking:

if (!checkRecordExist(DATABASE_TABLE, new String[] {KEY_1, KEY_2}, new String[] {value_1, value_2}))
database.insert(DATABASE_TABLE, null, updateValues);

where

private boolean checkRecordExist(String tableName, String[] keys, String [] values) {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < keys.length; i++) {
        sb.append(keys[i])
            .append("=\"")
            .append(values[i])
            .append("\" ");
        if (i<keys.length-1) sb.append("AND ");
    }

    Cursor cursor = database.query(tableName, null, sb.toString(), null, null, null, null);
    boolean exists = (cursor.getCount() > 0);
    cursor.close();
    return exists;
}


问:
Delete global variable and release memory from a function
I need to delete a global variable and release the memory it was using from inside a function with R, but none of the options I have tried work.

I have tried rm function with envir parameter and then gc, but gc does not release the memory. I have also tried runing gc in the global environment with eval+envir.

```<code>library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(dt){
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(DT, envir = globalenv())

  print(gc())
}

rm_and_release(DT)
</code>```

The result is the following

```<code>           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   661556  35.4    1168576   62.5   1143443   61.1
Vcells 96303112  734.8   146725516 1119.5 146722586 1119.5
           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   661569  35.4    1168576   62.5   1143443   61.1
Vcells 96303114  734.8   146725516 1119.5 146722586 1119.5
</code>```

I expected the second gc() to liberate more memory, since at that moment there is only one dataset, because the global DT has been removed.

I need to liberate RAM inside the function because the function generates more datasets and it runs out of memory.

答:
I have found some code that works

```<code>library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(){
  dt <- copy(DT)
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(DT, envir = globalenv())

  print(gc())
}

rm_and_release()
</code>```

It results in

```<code>           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   865272  46.3    1442291   77.1   1280599   68.4
Vcells 96733883 738.1  167167064 1275.4 147681076 1126.8
           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   865173  46.3    1442291   77.1   1280599   68.4
Vcells 46731629 356.6  133733651 1020.4 147681076 1126.8
</code>```

I think it's very ugly not inserting DT as an argument of the function, but at least in this scenario the memory is lowered from 738Mb to 356Mb, which is crucial to what I'm doing

Body:
I need to delete a global variable and release the memory it was using from inside a function with R, but none of the options I have tried work.

I have tried rm function with envir parameter and then gc, but gc does not release the memory. I have also tried runing gc in the global environment with eval+envir.

library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(dt){
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(DT, envir = globalenv())

  print(gc())
}

rm_and_release(DT)

The result is the following

           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   661556  35.4    1168576   62.5   1143443   61.1
Vcells 96303112  734.8   146725516 1119.5 146722586 1119.5
           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   661569  35.4    1168576   62.5   1143443   61.1
Vcells 96303114  734.8   146725516 1119.5 146722586 1119.5

I expected the second gc() to liberate more memory, since at that moment there is only one dataset, because the global DT has been removed.

I need to liberate RAM inside the function because the function generates more datasets and it runs out of memory.

Body:
I have found some code that works

library(data.table)
DT = data.table(col1 = 1:1e6)
cols = paste0('col', 2:100)
for (col in cols){ DT[, col := 1:1e6, with = F] }

rm_and_release <- function(){
  dt <- copy(DT)
  dt <- dt[sample(1e6, 9e5, FALSE)]
  print(gc())
  rm(DT, envir = globalenv())

  print(gc())
}

rm_and_release()

It results in

           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   865272  46.3    1442291   77.1   1280599   68.4
Vcells 96733883 738.1  167167064 1275.4 147681076 1126.8
           used  (Mb) gc trigger   (Mb)  max used   (Mb)
Ncells   865173  46.3    1442291   77.1   1280599   68.4
Vcells 46731629 356.6  133733651 1020.4 147681076 1126.8

I think it's very ugly not inserting DT as an argument of the function, but at least in this scenario the memory is lowered from 738Mb to 356Mb, which is crucial to what I'm doing


问:
How to extract numbers from a string and dumping them as a comma separated values?
I have a test_file in bash which outputs following on screen . I have no control on the upstream code to print them in a certain way. So, I need to do parse some values from the screen output.
Here is what I'm doing:

```<code>MyOut=$(./my_test_file.sh)    # this is my example script which echo's the
                                 #output
echo $MyOut
</code>```

shows me the following

```<code>output for different segments IP address: 192.168.0.12 Segment :0xfff Segment Data: 123 23 42 23 4 444 1121 8676 34 530 323 564 523 7878 7328 96
</code>```

my expected results would be a string variable

```<code>123,23,42,23,4,444,1121,8676,34,530,323,564,523,7878,7328,96
</code>```

comma-separated 16 values getting stored in some variable which I can dump in a text file for further processing.

I tried playing with regular expressions and would like to only extract last 16 numbers in the following output

I did this

```<code>numbers=$(echo $MyOut | grep -o -E '[0-9]+')
</code>```

gives me

```<code>192 168 0 12 0 123 23 42 23 4 444 1121 8676 34 530 323 564 523 7878 7328 96
</code>```

I need to extract the last 16 numbers. Since it is not a array format , Can I add something in regular expression which only spits out only last 16 numbers delimited by commma ???

btw If you need to look into my_test_file.sh , its just echoing the statements

```<code>#!/bin/bash

echo "output for different segments "
echo "IP address: 192.168.0.12 Segment :0xfff"
echo "Segment Data:"
echo "123"
echo "23"
echo "42"
echo "23"
echo "4"
echo "444"
echo "1121"
echo "8676"
echo "34"
echo "530"
echo "323"
echo "564"
echo "523"
echo "7878"
echo "7328"
echo "96"

</code>```

Thanks
Ash

答:
Using only awk:

```<code>./my_test_file.sh |awk -vlast=16 -v RS=    '{gsub(/[^[:digit:]]/," ") ; for(i=NF-last+1;i<=NF;i++) if(i!=NF)printf $i",";else print $i}'
123,23,42,23,4,444,1121,8676,34,530,323,564,523,7878,7328,96
</code>```

first used gsub() function to remove all the non-digit chars from each line, later looped for last 16 columns. printf and print both are used to deal with last comma char.

Body:
I have a test_file in bash which outputs following on screen . I have no control on the upstream code to print them in a certain way. So, I need to do parse some values from the screen output.
Here is what I'm doing:

MyOut=$(./my_test_file.sh)    # this is my example script which echo's the
                                 #output
echo $MyOut

shows me the following

output for different segments IP address: 192.168.0.12 Segment :0xfff Segment Data: 123 23 42 23 4 444 1121 8676 34 530 323 564 523 7878 7328 96

my expected results would be a string variable

123,23,42,23,4,444,1121,8676,34,530,323,564,523,7878,7328,96

comma-separated 16 values getting stored in some variable which I can dump in a text file for further processing.

I tried playing with regular expressions and would like to only extract last 16 numbers in the following output

I did this

numbers=$(echo $MyOut | grep -o -E '[0-9]+')

gives me

192 168 0 12 0 123 23 42 23 4 444 1121 8676 34 530 323 564 523 7878 7328 96

I need to extract the last 16 numbers. Since it is not a array format , Can I add something in regular expression which only spits out only last 16 numbers delimited by commma ???

btw If you need to look into my_test_file.sh , its just echoing the statements

#!/bin/bash

echo "output for different segments "
echo "IP address: 192.168.0.12 Segment :0xfff"
echo "Segment Data:"
echo "123"
echo "23"
echo "42"
echo "23"
echo "4"
echo "444"
echo "1121"
echo "8676"
echo "34"
echo "530"
echo "323"
echo "564"
echo "523"
echo "7878"
echo "7328"
echo "96"

Thanks
Ash

Body:
Using only awk:

./my_test_file.sh |awk -vlast=16 -v RS=    '{gsub(/[^[:digit:]]/," ") ; for(i=NF-last+1;i<=NF;i++) if(i!=NF)printf $i",";else print $i}'
123,23,42,23,4,444,1121,8676,34,530,323,564,523,7878,7328,96

first used gsub() function to remove all the non-digit chars from each line, later looped for last 16 columns. printf and print both are used to deal with last comma char.


问:
How to add ordinals to an address string using Excel VBA
I am trying to cleaning up some addresses. I already have some code to change "Sw","Ne" and capitalizing them.

However, I would like to add one more step to tack on ordinals to rural addresses in the same code if possible.

all the addresses I need to updated start with 5 numbers then space then 3 numbers.  "NNNNN NNN"

I have some code to add ordinals, I just need a way to only add it to those 3 numbers after the 5. Example "56579 123"  to  "56579 123rd" and leave the rest of the address alone.

Here is my current code.

```<code>Public Function TidyUp(sin As String) As String
    Dim i As Long
    arr = Split(sin, " ")
    For i = LBound(arr) To UBound(arr)

        If UCase(arr(i)) = "NE" Then arr(i) = "NE"
        If UCase(arr(i)) = "NW" Then arr(i) = "NW"
        If UCase(arr(i)) = "SE" Then arr(i) = "SE"
        If UCase(arr(i)) = "SW" Then arr(i) = "SW"

    Next i
    TidyUp = Join(arr, " ")
End Function
</code>```

Here is the ordinal function but this only works if i have a single number in a cell.

```<code>Function AddOrdinal(Address As String) As String

Select Case CLng(VBA.Right(Address, 1))
    Case 1
    AddOrdinal = Address & "st"
    Case 2
    AddOrdinal = Address & "nd"
    Case 3
    AddOrdinal = Address & "rd"
    Case Else
    AddOrdinal = Address & "th"
End Select
Select Case VBA.CLng(VBA.Right(Address, 2))
    Case 11, 12, 13
    AddOrdinal = Address & "th"
End Select
End Function
</code>```

This is basically what I am looking to achieve.

```<code>Address List        Expected Output
12345 673 Ave       12345 673rd Ave
213 N Apple St      213 N Apple St
69818 221st Rd      69818 221st Rd
569 Sw Maple Dr     569 SW Maple Dr
10005 654 Dr        10005 654th Dr
369 Ne Banana St    369 NE Banana St
54489 412th St      54489 412th St
986 W Timber St     986 W Timber St
79532 771 Dr        79532 771st Dr
126 E Washington Ave126 E Washington Ave
56898 422 Dr        56898 422nd Dr
</code>```

答:
you could have TidyUp function process the second "numeric" substring (if any)</p>

```<code>Public Function TidyUp(sin As String) As String
    Dim i As Long, arr
    arr = Split(sin, " ")
    For i = LBound(arr) To UBound(arr)

        Select Case UCase(arr(i))
            Case "NE", "NW", "SE", "SW"
                arr(i) = UCase(arr(i))
        End Select

        If i = 1 Then ' check 2nd substring
            If IsNumeric(arr(i)) Then arr(i) = AddOrdinal(CStr(arr(i))) 'if it's a "numeric" substring then have it processed by AddOrdinal() function
        End If

    Next

    TidyUp = Join(arr, " ")
End Function
</code>```

Body:
I am trying to cleaning up some addresses. I already have some code to change "Sw","Ne" and capitalizing them.

However, I would like to add one more step to tack on ordinals to rural addresses in the same code if possible.

all the addresses I need to updated start with 5 numbers then space then 3 numbers.  "NNNNN NNN"

I have some code to add ordinals, I just need a way to only add it to those 3 numbers after the 5. Example "56579 123"  to  "56579 123rd" and leave the rest of the address alone.

Here is my current code.

Public Function TidyUp(sin As String) As String
    Dim i As Long
    arr = Split(sin, " ")
    For i = LBound(arr) To UBound(arr)

        If UCase(arr(i)) = "NE" Then arr(i) = "NE"
        If UCase(arr(i)) = "NW" Then arr(i) = "NW"
        If UCase(arr(i)) = "SE" Then arr(i) = "SE"
        If UCase(arr(i)) = "SW" Then arr(i) = "SW"

    Next i
    TidyUp = Join(arr, " ")
End Function

Here is the ordinal function but this only works if i have a single number in a cell.

Function AddOrdinal(Address As String) As String

Select Case CLng(VBA.Right(Address, 1))
    Case 1
    AddOrdinal = Address & "st"
    Case 2
    AddOrdinal = Address & "nd"
    Case 3
    AddOrdinal = Address & "rd"
    Case Else
    AddOrdinal = Address & "th"
End Select
Select Case VBA.CLng(VBA.Right(Address, 2))
    Case 11, 12, 13
    AddOrdinal = Address & "th"
End Select
End Function

This is basically what I am looking to achieve.

Address List        Expected Output
12345 673 Ave       12345 673rd Ave
213 N Apple St      213 N Apple St
69818 221st Rd      69818 221st Rd
569 Sw Maple Dr     569 SW Maple Dr
10005 654 Dr        10005 654th Dr
369 Ne Banana St    369 NE Banana St
54489 412th St      54489 412th St
986 W Timber St     986 W Timber St
79532 771 Dr        79532 771st Dr
126 E Washington Ave126 E Washington Ave
56898 422 Dr        56898 422nd Dr

Body:
you could have TidyUp function process the second "numeric" substring (if any)

Public Function TidyUp(sin As String) As String
    Dim i As Long, arr
    arr = Split(sin, " ")
    For i = LBound(arr) To UBound(arr)

        Select Case UCase(arr(i))
            Case "NE", "NW", "SE", "SW"
                arr(i) = UCase(arr(i))
        End Select

        If i = 1 Then ' check 2nd substring
            If IsNumeric(arr(i)) Then arr(i) = AddOrdinal(CStr(arr(i))) 'if it's a "numeric" substring then have it processed by AddOrdinal() function
        End If

    Next

    TidyUp = Join(arr, " ")
End Function


问:
How to apply border-radius css property on ion-menu in ionic 4?
I'm creating Ionic 4 Angular app , in the app i'm using ion-menu to show menu items. how to apply border-top-right-radius and border-bottom-right-radius css properties on ion-menu ? Below image shows what exactly i want. Here is ion-menu documentation link.

答:
Have you try this?</p>

```<code>.ion-item-border {
 border-radius: 20px !important;
 padding-left: 10px;
 padding-right: 10px;
 padding-bottom: 5px;
 padding-top: 5px;
}
</code>```

Body:
Have you try this?

.ion-item-border {
 border-radius: 20px !important;
 padding-left: 10px;
 padding-right: 10px;
 padding-bottom: 5px;
 padding-top: 5px;
}


答: Use the REPLACE command</p>

Title: Insert if not exists?

Body: Use the REPLACE command


答:
Some of the lines in the .csv file don't have as many columns as you're expecting. It looks like you think it should be a consistent amount of columns so you just need to check before you actually start index the row like this:

```<code>for container in containers:
    if len(cols) == 7:
        cols = container.findAll("td")
        company_name = cols[1].find("a").text
        booth_number = cols[2].text
        category = cols[3].text.strip()
        country = cols[5].text

        company_names.append(company_name)
        booth_numbers.append(booth_number)
        categories.append(category)
        countries.append(country)

        csv_out.writerow([company_name, booth_number, category, country])
</code>```

I'm assuming that there will be 7 columns as that's what you calculated the first row to be but you can change that to whatever it should be.

Title: How to fix "List Index Our of Range" error

Body:
Some of the lines in the .csv file don't have as many columns as you're expecting. It looks like you think it should be a consistent amount of columns so you just need to check before you actually start index the row like this:

for container in containers:
    if len(cols) == 7:
        cols = container.findAll("td")
        company_name = cols[1].find("a").text
        booth_number = cols[2].text
        category = cols[3].text.strip()
        country = cols[5].text

        company_names.append(company_name)
        booth_numbers.append(booth_number)
        categories.append(category)
        countries.append(country)

        csv_out.writerow([company_name, booth_number, category, country])

I'm assuming that there will be 7 columns as that's what you calculated the first row to be but you can change that to whatever it should be.


问:
Convert char var to integer for use in join
I am trying to get a report to run through crystal using our postgres databse.

My SQL looks like

```<code>SELECT
    slcnote.note_date,
    slcnote.account,
    customer.name,
    slcnote.reference,
    slcnote.operator,
    salesman.name,
    slcnote.system_date,
    slcnote.note_type,
    slcnote.note_note,
                CAST(salesman.code as integer)
FROM
   slcnote
    Left JOIN customer ON slcnote.account=customer.account
    left JOIN salesman ON slcnote.operator=salesman.code
 ORDER BY "slcnote"."note_date"
</code>```

However it does not seem to be converting the salesman code to an integer. I am encountering the following error message in Crystal Reports:

```
--------------------------- Crystal Reports ---------------------------
Failed to retrieve data from the database.
Details: 42883:
ERROR: operator does not exist: integer = character varying;
Error while executing the query
[Database Vendor Code: 7 ]
--------------------------- OK ---------------------------
```

Thanks for help

Chris

答:
Your issue is that you cast salesman.code to an integer in the SELECT clause, but not in the ON clause. Therefore, the query is trying to join tables by comparing an integer to a VARCHAR, which generates the error message.

To solve your immediate problem, you need to perform the cast in your ON clause:

```
SELECT *
FROM slcnote
    LEFT JOIN salesman ON CAST(salesman.code AS INT) = slcnote."operator"
```

As noted in comments, however, performance of this query will be abysmal. If you can't change the table, are you able to create a materialized view that performs the cast? This might help. You should also see if the individual who is able to change the table will do so, citing these performance issues.

Body:
I am trying to get a report to run through crystal using our postgres databse.

My SQL looks like

SELECT
    slcnote.note_date,
    slcnote.account,
    customer.name,
    slcnote.reference,
    slcnote.operator,
    salesman.name,
    slcnote.system_date,
    slcnote.note_type,
    slcnote.note_note,
                CAST(salesman.code as integer)
FROM
   slcnote
    Left JOIN customer ON slcnote.account=customer.account
    left JOIN salesman ON slcnote.operator=salesman.code
 ORDER BY "slcnote"."note_date"

However it does not seem to be converting the salesman code to an integer. I am encountering the following error message in Crystal Reports:

--------------------------- Crystal Reports ---------------------------
Failed to retrieve data from the database.
Details: 42883:
ERROR: operator does not exist: integer = character varying;
Error while executing the query
[Database Vendor Code: 7 ]
--------------------------- OK ---------------------------

Thanks for help

Chris

Body:
Your issue is that you cast salesman.code to an integer in the SELECT clause, but not in the ON clause. Therefore, the query is trying to join tables by comparing an integer to a VARCHAR, which generates the error message.

To solve your immediate problem, you need to perform the cast in your ON clause:

SELECT *
FROM slcnote
    LEFT JOIN salesman ON CAST(salesman.code AS INT) = slcnote."operator"

As noted in comments, however, performance of this query will be abysmal. If you can't change the table, are you able to create a materialized view that performs the cast? This might help. You should also see if the individual who is able to change the table will do so, citing these performance issues.


问:
I am trying to Understand Content-Security-Policy Frame Ancestors tag
I am trying to display one of my sites in a iframe inside my IONIC app. I need to restrict my website from being iframed by other websites. I decided to go with the content-security-policy response header where

Content-security-policy: frame-ancestors ${website-to-be-allowed}

made sure only the websites mentioned could iframe my website however I needed my ionic app to iframe my website as well and Since Ionic apps are served as file system I am okay with giving access to all file system to iframe my website. When I added

Content-security-policy: frame-ancestors ${website-to-be-allowed} filesystem

as mentioned here,
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors

I tested on both my Android and IOS app and both threw the same error saying,
which says,

Refused to display ${website} in a frame because an ancestor violates the following content security policy directive: "frame-ancestors filesystem"

Here is the error that pops up enter image description here

答:
You need the colon at the end of "filesystem".  Try

frame-ancestors ${website-to-be-allowed} filesystem:


问:
How to determine when the distance between two lines gets within a certain threshold?
I have a graph with the main data points(blue line) and the maxima (green) and minima (red).

Note that the x-values of the minima and maxima values are not the same, nor are they guaranteed to have the same count of values.

Now my goal is to determine when the distance along the y-axis (integral? sorry, its been a while since calculus in uni) between the maxima and minima lines gets below 10% (or any other arbitrary threshold) from the the average distance along the y-axis.

Here is the code used to generate:

```<code># Finding the min and max
c_max_index = argrelextrema(df.flow.values, np.greater, order=3)
c_min_index = argrelextrema(df.flow.values, np.less, order=3)

df['min_extreme'] = df.flow[c_min_index[0]]
df['max_extreme'] = df.flow[c_max_index[0]]

# Plotting the values for the graph above
plt.plot(df.flow.values)
upper_bound = plt.plot(c_max_index[0], df.flow.values[c_max_index[0]], linewidth=0.8, c='g')
lower_bound = plt.plot(c_min_index[0], df.flow.values[c_min_index[0]], linewidth=0.8, c='r')
</code>```

If it makes a difference, I'm using a Pandas Dataframe, scipy, and matplotlib.

答:
This is a perfect solution by no means. It aims to give you some ideas of how it can be done since there is no more data.

The major problem you are trying to solve is to deal with two piece-wise straight lines. And the pieces do not align. An obvious solution is to interpolate both and obtain a union of x's. Then the calculation of distances is easier.

```<code>import numpy as np
import matplotlib.pyplot as plt

# Toy data
x1 = [0, 1, 2, 3, 4, 5, 6]
y1 = [9, 8, 9, 10, 7, 6, 9]
x2 = [0.5, 3, 5, 6, 9]
y2 = [0, 1, 3, 2, 1]

# Interpolation for both lines
points1 = list(zip(x1, y1))
y1_interp = np.interp(x2, x1, y1)
interp_points1 = list(zip(x2, y1_interp))
l1 = list(set(points1 + interp_points1))
all_points1 = sorted(l1, key = lambda x: x[0])

points2 = list(zip(x2, y2))
y2_interp = np.interp(x1, x2, y2)
interp_points2 = list(zip(x1, y2_interp))
l2 = list(set(points2 + interp_points2))
all_points2 = sorted(l2, key = lambda x: x[0])

assert(len(all_points1) == len(all_points2))

# Since I do not have data points on the blue line,
# I will calculate the average distance based on x's of all interpolated points
sum_d = 0
for i in range(len(all_points1)):
    sum_d += all_points1[i][1] - all_points2[i][1]
avg_d = sum_d / len(all_points1)
threshold = 0.5
d_threshold = avg_d * threshold

for i in range(len(all_points1)):
    d = all_points1[i][1] - all_points2[i][1]
    if d / avg_d < threshold:
        print("Distance below threshold between", all_points1[i], "and", all_points2[i])
</code>```

Notice that np.interp extrapolate values as well, but they do not participate in the calculation.

Now there is a remaining question: if you actually need to know when the distance falls below threshold other than the interpolated points only, one needs to analytically search for the first and last points in each piece of lines. Here is a piece of sample:

```<code>for i in range(len(all_points1) - 1):
    (pre_x1, pre_y1) = all_points1[i]
    (post_x1, post_y1) = all_points1[i + 1]
    (pre_x2, pre_y2) = all_points2[i]
    (post_x2, post_y2) = all_points2[i + 1]
    # Skip the pieces that will never have qualified points
    if (pre_y1 - pre_y2) / avg_d >= threshold and (post_y1 - post_y2) / avg_d >= threshold:
        continue
    k1 = (post_y1 - pre_y1) / (post_x1 - pre_x1)
    b1 = (post_x1 * pre_y1 - pre_x1 * post_y1) / (post_x1 - pre_x1)
    k2 = (post_y2 - pre_y2) / (post_x2 - pre_x2)
    b2 = (post_x2 * pre_y2 - pre_x2 * post_y2) / (post_x2 - pre_x2)
    x_start = (d_threshold - b1 + b2) / (k1 - k2)
    print("The first point where the distance falls below threshold is at x=", x_start)
    break
</code>```

Body:
I have a graph with the main data points(blue line) and the maxima (green) and minima (red).

Note that the x-values of the minima and maxima values are not the same, nor are they guaranteed to have the same count of values.

Now my goal is to determine when the distance along the y-axis (integral? sorry, its been a while since calculus in uni) between the maxima and minima lines gets below 10% (or any other arbitrary threshold) from the the average distance along the y-axis.

Here is the code used to generate:

# Finding the min and max
c_max_index = argrelextrema(df.flow.values, np.greater, order=3)
c_min_index = argrelextrema(df.flow.values, np.less, order=3)

df['min_extreme'] = df.flow[c_min_index[0]]
df['max_extreme'] = df.flow[c_max_index[0]]

# Plotting the values for the graph above
plt.plot(df.flow.values)
upper_bound = plt.plot(c_max_index[0], df.flow.values[c_max_index[0]], linewidth=0.8, c='g')
lower_bound = plt.plot(c_min_index[0], df.flow.values[c_min_index[0]], linewidth=0.8, c='r')

If it makes a difference, I'm using a Pandas Dataframe, scipy, and matplotlib.

Body:
This is a perfect solution by no means. It aims to give you some ideas of how it can be done since there is no more data.

The major problem you are trying to solve is to deal with two piece-wise straight lines. And the pieces do not align. An obvious solution is to interpolate both and obtain a union of x's. Then the calculation of distances is easier.

import numpy as np
import matplotlib.pyplot as plt

# Toy data
x1 = [0, 1, 2, 3, 4, 5, 6]
y1 = [9, 8, 9, 10, 7, 6, 9]
x2 = [0.5, 3, 5, 6, 9]
y2 = [0, 1, 3, 2, 1]

# Interpolation for both lines
points1 = list(zip(x1, y1))
y1_interp = np.interp(x2, x1, y1)
interp_points1 = list(zip(x2, y1_interp))
l1 = list(set(points1 + interp_points1))
all_points1 = sorted(l1, key = lambda x: x[0])

points2 = list(zip(x2, y2))
y2_interp = np.interp(x1, x2, y2)
interp_points2 = list(zip(x1, y2_interp))
l2 = list(set(points2 + interp_points2))
all_points2 = sorted(l2, key = lambda x: x[0])

assert(len(all_points1) == len(all_points2))

# Since I do not have data points on the blue line,
# I will calculate the average distance based on x's of all interpolated points
sum_d = 0
for i in range(len(all_points1)):
    sum_d += all_points1[i][1] - all_points2[i][1]
avg_d = sum_d / len(all_points1)
threshold = 0.5
d_threshold = avg_d * threshold

for i in range(len(all_points1)):
    d = all_points1[i][1] - all_points2[i][1]
    if d / avg_d < threshold:
        print("Distance below threshold between", all_points1[i], "and", all_points2[i])

Notice that np.interp extrapolate values as well, but they do not participate in the calculation.

Now there is a remaining question: if you actually need to know when the distance falls below threshold other than the interpolated points only, one needs to analytically search for the first and last points in each piece of lines. Here is a piece of sample:

for i in range(len(all_points1) - 1):
    (pre_x1, pre_y1) = all_points1[i]
    (post_x1, post_y1) = all_points1[i + 1]
    (pre_x2, pre_y2) = all_points2[i]
    (post_x2, post_y2) = all_points2[i + 1]
    # Skip the pieces that will never have qualified points
    if (pre_y1 - pre_y2) / avg_d >= threshold and (post_y1 - post_y2) / avg_d >= threshold:
        continue
    k1 = (post_y1 - pre_y1) / (post_x1 - pre_x1)
    b1 = (post_x1 * pre_y1 - pre_x1 * post_y1) / (post_x1 - pre_x1)
    k2 = (post_y2 - pre_y2) / (post_x2 - pre_x2)
    b2 = (post_x2 * pre_y2 - pre_x2 * post_y2) / (post_x2 - pre_x2)
    x_start = (d_threshold - b1 + b2) / (k1 - k2)
    print("The first point where the distance falls below threshold is at x=", x_start)
    break


问:
kotlin reflection get list of fields
is there an equivalent for the java reflection foo.getClass().getFields() in Kotlin? I could only find that I can access a field when I know it's name, but I would like to handle fields in a generic way.

答:
There is a method in Kotlin that works without  having to add a new dependency in a project:

Suppose a custom class called Mine

```<code>class Mine(var prop:String) {
    fun myMethod():Boolean {
        return true
    }
}
</code>```

A new user function called isMethod

```<code>fun isMethod(t:Any, s:String):Boolean {
try  {
    t.javaClass.getMethod(s)   // or t::class.java.getMethod(s)
    return true
  } catch(e:Exception)  {
    return false
  }
}
</code>```

After one declares an Mine instance and test it.

```<code>fun main() {
  var m = Mine("Paulo")
  println(isMethod(m, "myMethod"))  // it prints true
  println(isMethod(m, "otherMethod"))  // it prints false
}
</code>```

Title: kotlin reflection get list of fields

Body:
There is a method in Kotlin that works without  having to add a new dependency in a project:

Suppose a custom class called Mine

class Mine(var prop:String) {
    fun myMethod():Boolean {
        return true
    }
}

A new user function called isMethod

fun isMethod(t:Any, s:String):Boolean {
try  {
    t.javaClass.getMethod(s)   // or t::class.java.getMethod(s)
    return true
  } catch(e:Exception)  {
    return false
  }
}

After one declares an Mine instance and test it.

fun main() {
  var m = Mine("Paulo")
  println(isMethod(m, "myMethod"))  // it prints true
  println(isMethod(m, "otherMethod"))  // it prints false
}


问:
Date and Time Split, then added into another table column
EDIT:

I want to thanks @jimmix for giving me some idea to get started on my last post, But unfortunately, my post was put on hold. Due to the lack of details.

But here are the real scenario, I'm sorry if I didn't explain well my question.

From my CSV file, I have a raw data,  then I will upload using my upload() function in into my phpmyadmin database with the table name "tbldumpbio",

See the table structure below:(tbldumpbio)

From my table tbldumpbio data, I have a function called processTimesheet()

Here's the code:

```<code>public function processTimesheet(){
        $this->load->model('dbquery');

            $query = $this->db->query("SELECT * FROM tbldumpbio");

            foreach ($query->result() as $row){

            $dateTimeExplArr = explode(' ', $row->datetimex);

            $dateStr = $dateTimeExplArr[0];
            $timeStr = $dateTimeExplArr[1];

            if($row->status='C/Out' and !isset($timeStr) || empty($timeStr) ){
                $timeStrOut ='';
            } else {
                $timeStrOut = $dateTimeExplArr[1];
            }

            if($row->status='C/In' and !isset($timeStr) || empty($timeStr) ){
                $timeStrIn ='';
            } else {
                $timeStrIn = $dateTimeExplArr[1];
            }

            $data = array(
                'ID' => '',
                'companyAccessID' => '',
                'name' => $row->name,
                'empCompID' => $row->empid,
                'date' => $dateStr,
                'timeIn' => $timeStrIn,
                'timeOut' => $timeStrOut,
                'status' => '',
                'inputType' => ''
            );
            $this->dbquery->modInsertval('tblempbioupload',$data);

            }
    }
</code>```

This function will add another data into another table called "tblempbioupload". But here are the results that I'm getting with:

Please see the below data:(tblempbioupload)

The problem is:

the date should not be duplicated

Time In data should be added if the status is 'C/In'

Time Out data should be added if the status is 'C/Out'

The expected result should be something like this:

答:
The first problem I see is that you have a time expressed as 15:xx:yy PM, which is an ambiguous format, as one can write 15:xx:yy AM and that would not be a valid time.

That said, if what you want is that every time the date changes a row should be written, you should do just that: store the previous date in a variable, then when you move to the next record in the source table, you compare the date with the previous one and if they differ, then you insert the row, otherwise you simply progress reading the next bit of data.

Remember that this approach works only if you're certain that the input rows are in exact order, which means ordered by EmpCompId first and then by date and then by time; if they aren't this procedure doesn't work properly.

I would probably try another approach: if (but this is not clear from your question) only one row per empcompid and date should be present, i would do a grouping query on the source table, finding the minimum entrance time, another one to find the maximum exit date, and use both of them as a source for the insert query.

Body:
EDIT:

I want to thanks @jimmix for giving me some idea to get started on my last post, But unfortunately, my post was put on hold. Due to the lack of details.

But here are the real scenario, I'm sorry if I didn't explain well my question.

From my CSV file, I have a raw data,  then I will upload using my upload() function in into my phpmyadmin database with the table name "tbldumpbio",

See the table structure below:(tbldumpbio)

From my table tbldumpbio data, I have a function called processTimesheet()

Here's the code:

public function processTimesheet(){
        $this->load->model('dbquery');

            $query = $this->db->query("SELECT * FROM tbldumpbio");

            foreach ($query->result() as $row){

            $dateTimeExplArr = explode(' ', $row->datetimex);

            $dateStr = $dateTimeExplArr[0];
            $timeStr = $dateTimeExplArr[1];

            if($row->status='C/Out' and !isset($timeStr) || empty($timeStr) ){
                $timeStrOut ='';
            } else {
                $timeStrOut = $dateTimeExplArr[1];
            }

            if($row->status='C/In' and !isset($timeStr) || empty($timeStr) ){
                $timeStrIn ='';
            } else {
                $timeStrIn = $dateTimeExplArr[1];
            }

            $data = array(
                'ID' => '',
                'companyAccessID' => '',
                'name' => $row->name,
                'empCompID' => $row->empid,
                'date' => $dateStr,
                'timeIn' => $timeStrIn,
                'timeOut' => $timeStrOut,
                'status' => '',
                'inputType' => ''
            );
            $this->dbquery->modInsertval('tblempbioupload',$data);

            }
    }

This function will add another data into another table called "tblempbioupload". But here are the results that I'm getting with:

Please see the below data:(tblempbioupload)

The problem is:

the date should not be duplicated

Time In data should be added if the status is 'C/In'

Time Out data should be added if the status is 'C/Out'

The expected result should be something like this:


问:
Named semaphores in C are not deleted after a signal handler call
So the following code is supposed to do the following:

The main process creates N_READ number of children processes and then proceeds to print some lines endlessly.

The children also print some lines endlessly.

When the main process receives a SIGINT signal (CTRL^C from the terminal in this case) he must send a SIGTERM to all his children, wait for them to finish and then delete all the semaphores used.

The use of named semaphores is justified by the fact that this is simulation of the readers-writers problem giving priority to the readers.

However when I end the program and start it again the semaphores have not been deleted, as I get an "semaphore already exists" error and they are in fact in /dev/shm.

P.D. This is college homework and they say global variables are not permitted.

Thank you in advance and here is the code:

#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>

#define SEM1 "/example_sem1"
#define SEM2 "/example_sem2"
#define SEM3 "/example_sem3"

#define N_READ 1
#define SECS 0

int  valor_semaforo(sem_t *sem) {
    int sval;

    if (sem_getvalue(sem, &sval) == -1) {
        perror("sem_getvalue");
        sem_unlink(SEM1);
        sem_unlink(SEM2);
        sem_unlink(SEM3);
        exit(EXIT_FAILURE);
    }

   return sval;
}

void manejador_SIGINT(int sig) {

    kill(0,SIGTERM);
    while(wait(NULL)>0);
/*xq no llega xq*/
    sem_unlink(SEM1);
    sem_unlink(SEM2);
    sem_unlink(SEM3);

    exit(EXIT_SUCCESS);
}

int main(void) {
    sem_t *sem_write = NULL,*sem_read = NULL,*sem_count = NULL;
    pid_t pid[N_READ];
    int i;
    struct sigaction act;

    sigemptyset(&(act.sa_mask));
    act.sa_flags = 0;

    act.sa_handler = manejador_SIGINT;
    if (sigaction(SIGINT, &act, NULL) < 0) {
        perror("sigaction");
        exit(EXIT_FAILURE);
    }

    if ((sem_write = sem_open(SEM1, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    if ((sem_read = sem_open(SEM2, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 1)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }
    if ((sem_count = sem_open(SEM3, O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, 0)) == SEM_FAILED) {
        perror("sem_open");
        exit(EXIT_FAILURE);
    }

    for(i=0;i<N_READ;i++){
        pid[i] = fork();
        if (pid[i] < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        }
        if (pid[i] == 0) {

            sigemptyset(&(act.sa_mask));
            act.sa_flags = 0;

            act.sa_handler = SIG_IGN;
            if (sigaction(SIGINT, &act, NULL) < 0) {
                perror("sigaction");
                exit(EXIT_FAILURE);
            }
            while(1){

                sem_wait(sem_read);
                sem_post(sem_count);
                if(valor_semaforo(sem_count)==1)
                    sem_wait(sem_write);
                sem_post(sem_read);

                printf("R-INI %d\n",getpid());
                fflush(stdout);
                sleep(SECS);
                printf("R-FIN %d\n",getpid());
                fflush(stdout);

                sem_wait(sem_read);
                sem_wait(sem_count);
                if(valor_semaforo(sem_count)==0)
                    sem_post(sem_write);
                sem_post(sem_read);
            }

        }
    }
        while(1){
            sem_wait(sem_write);
            printf("W-INI %d\n",getpid());
            fflush(stdout);
            sleep(SECS);
            printf("W-FIN %d\n",getpid());
            fflush(stdout);
            sem_post(sem_write);
        }
    }

```

答: As @Jonathan said, the SIGTERM signal I use does terminate the process that should clean up the semaphores. By ignoring the signal in the parent process, everything works well.</p>


问:
How to remove MaterialCardView borders
I'm using this layout

```<code><android.support.design.card.MaterialCardView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:innerRadius="0dp"
    android:shape="ring"
    android:thicknessRatio="0"
    app:cardCornerRadius="24dp"
    card_view:cardElevation="0dp"
    card_view:cardMaxElevation="0dp">
  <ImageView
      android:id="@+id/close_button"
      android:layout_width="48dp"
      android:layout_height="48dp"
      android:layout_gravity="top|end"
      android:padding="@dimen/account_menu_close_button_padding"
      android:alpha="0"
      app:srcCompat="@drawable/quantum_gm_ic_close_vd_theme_24"
      />
</android.support.design.card.MaterialCardView>
</code>```

but I get a cardView with tiny border

How can I remove this border and make the cardview transparent?

I saw this similar post, but it gives no answer

答:
Have you used these, </p>

```<code>app:strokeColor
app:strokeWidth
</code>```

Title: How to remove MaterialCardView borders

Body:
I'm using this layout

<android.support.design.card.MaterialCardView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:innerRadius="0dp"
    android:shape="ring"
    android:thicknessRatio="0"
    app:cardCornerRadius="24dp"
    card_view:cardElevation="0dp"
    card_view:cardMaxElevation="0dp">
  <ImageView
      android:id="@+id/close_button"
      android:layout_width="48dp"
      android:layout_height="48dp"
      android:layout_gravity="top|end"
      android:padding="@dimen/account_menu_close_button_padding"
      android:alpha="0"
      app:srcCompat="@drawable/quantum_gm_ic_close_vd_theme_24"
      />
</android.support.design.card.MaterialCardView>

but I get a cardView with tiny border

How can I remove this border and make the cardview transparent?

I saw this similar post, but it gives no answer

Body:
Have you used these,

app:strokeColor
app:strokeWidth


问:
Input with shifting label field ( in all CSS) without required
I have a floating label for a styled input done with all CSS. The problem I am having is that this requires the input to have the required property in order to manage the moving label ( with pure CSS). I am wondering if it's possible to do this without the required field because putting this in certain forms is messing with the form validations. My markup and CSS looks like so :

```<code>.myInput {
  position: relative;
  input {
    padding: 30px 10px 10px;
    display: block;
    width: 100%;
    border: 1px solid black;
    &:focus {
      outline: none;
    }
    &:focus~label,
    &:valid~label,
    &:placeholder-shown~label {
      top: 10px;
      color: black;
    }
  }
  label {
    color: red;
    position: absolute;
    pointer-events: none;
    left: 10px;
    top: 20px;
    transition: 0.2s ease all;
    -moz-transition: 0.2s ease all;
    -webkit-transition: 0.2s ease all;
  }
}

<div class="myInput">
  <input type="text" required id="target" />
  <label htmlFor="target">
        label
    </label>
</div>
</code>```

You'll notice that if you remove the required the label no longer moves into the placeholder spot in an empty input. Here it is in a working fiddle - https://jsfiddle.net/1ob2npcu/2/

I am trying to see if there is a way to do this purely in CSS - i am using SCSS if this helps. Thanks!

答:
If you remove the required attribute then also remove

```<code>&:valid~label
</code>```

from the CSS: then you need to define a placeholder for the input and revert the logic for the placeholder-shown pseudoclass, so the SCSS style for the input becomes

```<code>input {
    padding: 30px 10px 10px;
    display: block;
    width: 100%;
    border: 1px solid black;

    &::placeholder {
       color: transparent;
    }

    &:focus {
        outline: none;
    }

    &:focus ~ label,
    &:not(:placeholder-shown) ~ label{
        top: 10px;
        color: black;
    }

}
</code>```

also, the attribute in the label is for (not htmlfor)

fork on jsfiddle

Body:
I have a floating label for a styled input done with all CSS. The problem I am having is that this requires the input to have the required property in order to manage the moving label ( with pure CSS). I am wondering if it's possible to do this without the required field because putting this in certain forms is messing with the form validations. My markup and CSS looks like so :

.myInput {
  position: relative;
  input {
    padding: 30px 10px 10px;
    display: block;
    width: 100%;
    border: 1px solid black;
    &:focus {
      outline: none;
    }
    &:focus~label,
    &:valid~label,
    &:placeholder-shown~label {
      top: 10px;
      color: black;
    }
  }
  label {
    color: red;
    position: absolute;
    pointer-events: none;
    left: 10px;
    top: 20px;
    transition: 0.2s ease all;
    -moz-transition: 0.2s ease all;
    -webkit-transition: 0.2s ease all;
  }
}

  <input type="text" required id="target" />

        label

You'll notice that if you remove the required the label no longer moves into the placeholder spot in an empty input. Here it is in a working fiddle - https://jsfiddle.net/1ob2npcu/2/

I am trying to see if there is a way to do this purely in CSS - i am using SCSS if this helps. Thanks!

Body:
If you remove the required attribute then also remove

&:valid~label

from the CSS: then you need to define a placeholder for the input and revert the logic for the placeholder-shown pseudoclass, so the SCSS style for the input becomes

input {
    padding: 30px 10px 10px;
    display: block;
    width: 100%;
    border: 1px solid black;

    &::placeholder {
       color: transparent;
    }

    &:focus {
        outline: none;
    }

    &:focus ~ label,
    &:not(:placeholder-shown) ~ label{
        top: 10px;
        color: black;
    }

}

also, the attribute in the label is for (not htmlfor)

fork on jsfiddle


问:
How to create PhoneStateListener that works in both Doze Mode and Power Saving Mode?
When device enters Doze mode or Power Saving mode my PhoneStateListener stops to work. Also I need to register PhoneStateListener on device reboot. I don't want to use BroadcastReceiver because it is not recommended anymore, see https://developer.android.com/about/versions/oreo/background#broadcasts</p>

答:
I don't think BroadcastReceiver are not recommended is the right definition at this point , its just has more limitations such as register broadcast receivers for implicit broadcasts in the manifest and according to docs :

Apps can continue to register for explicit broadcasts in their manifests

Apps can use Context.registerReceiver() at runtime to register a receiver for any broadcast, whether implicit or explicit.

Doze mode has few restrictions but it provide a solution for firing alarms at Doze mode an Power Saving Mode using AlarmManager :

If you need to set alarms that fire while in Doze, use setAndAllowWhileIdle() or setExactAndAllowWhileIdle().

You should about setAndAllowWhileIdle and setExactAndAllowWhileIdle and decide which one is relevant for you .