问:
Three.js canvas texture power of 2 but cropped
In Three.js it's best practice to keep textures to be a power of 2, and actually a requirement for some older Chrome browsers e.g.
32x32, 64x64 etc

Therefore I need to create a canvas texture of power of 2 dimensions, but I need to have that Sprite clickable, which means it needs to be cropped somehow.

Consider this example:

Black bg is the Three.js renderer

Red bg is the required size of a canvas (to power of 2)

White bg is the size of the text

I would like to keep the texture at dimensions power of 2, but crop it to only show the white area. This is so the user can hover on the label for example. I don't want them hovering on the red area!

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 400;

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var config = {
  fontface: 'Arial',
  fontsize: 32,
  fontweight: 500,
  lineheight: 1,
};
var text = 'Hello world!';

function nextPowerOf2(n) {
  return Math.pow(2, Math.ceil(Math.log(n) / Math.log(2)));
}

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
const textMetrics = ctx.measureText(text);
var textWidth = textMetrics.width;
var textHeight = config.fontsize * config.lineheight;
canvas.width = nextPowerOf2(textWidth);
canvas.height = nextPowerOf2(textHeight);
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, textWidth, textHeight);
ctx.fillStyle = 'black';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
ctx.fillText(text, 0, 0);

console.log('canvas', canvas.width, canvas.height);
console.log('text', textWidth, textHeight);

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({
  map: texture
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(spriteMaterial.map.image.width, spriteMaterial.map.image.height, 1);
scene.add(sprite);

var animate = function() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};

animate();```
<pre class="snippet-code-css lang-css prettyprint-override"><code>body { margin: 0; }</code>```

```

How is this possible? Somehow cropping the SpriteMaterial?

答:
You can set the texture's repeat so only the portion of the canvas used covers the sprite

```<code>texture.repeat.set(textWidth / canvas.width, textHeight / canvas.height);
</code>```

Then you can set the size of the sprite to just that portion

```<code>sprite.scale.set(textWidth, textHeight, 1);
</code>```

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 400;

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var config = {
  fontface: 'Arial',
  fontsize: 32,
  fontweight: 500,
  lineheight: 1,
};
var text = 'Hello world!';

function nextPowerOf2(n) {
  return Math.pow(2, Math.ceil(Math.log(n) / Math.log(2)));
}

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
const textMetrics = ctx.measureText(text);
var textWidth = textMetrics.width;
var textHeight = config.fontsize * config.lineheight;
canvas.width = nextPowerOf2(textWidth);
canvas.height = nextPowerOf2(textHeight);
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, textWidth, textHeight);
ctx.fillStyle = 'black';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
ctx.fillText(text, 0, 0);

console.log('canvas', canvas.width, canvas.height);
console.log('text', textWidth, textHeight);

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
texture.repeat.set(textWidth / canvas.width, textHeight / canvas.height);
var spriteMaterial = new THREE.SpriteMaterial({
  map: texture
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(textWidth, textHeight, 1);
scene.add(sprite);

var animate = function() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};

animate();```
<pre class="snippet-code-css lang-css prettyprint-override"><code>body { margin: 0; }</code>```

```

Body:
In Three.js it's best practice to keep textures to be a power of 2, and actually a requirement for some older Chrome browsers e.g.
32x32, 64x64 etc

Therefore I need to create a canvas texture of power of 2 dimensions, but I need to have that Sprite clickable, which means it needs to be cropped somehow.

Consider this example:

Black bg is the Three.js renderer

Red bg is the required size of a canvas (to power of 2)

White bg is the size of the text

I would like to keep the texture at dimensions power of 2, but crop it to only show the white area. This is so the user can hover on the label for example. I don't want them hovering on the red area!

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 400;

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var config = {
  fontface: 'Arial',
  fontsize: 32,
  fontweight: 500,
  lineheight: 1,
};
var text = 'Hello world!';

function nextPowerOf2(n) {
  return Math.pow(2, Math.ceil(Math.log(n) / Math.log(2)));
}

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
const textMetrics = ctx.measureText(text);
var textWidth = textMetrics.width;
var textHeight = config.fontsize * config.lineheight;
canvas.width = nextPowerOf2(textWidth);
canvas.height = nextPowerOf2(textHeight);
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, textWidth, textHeight);
ctx.fillStyle = 'black';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
ctx.fillText(text, 0, 0);

console.log('canvas', canvas.width, canvas.height);
console.log('text', textWidth, textHeight);

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({
  map: texture
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(spriteMaterial.map.image.width, spriteMaterial.map.image.height, 1);
scene.add(sprite);

var animate = function() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};

animate();

body { margin: 0; }

How is this possible? Somehow cropping the SpriteMaterial?

Body:
You can set the texture's repeat so only the portion of the canvas used covers the sprite

texture.repeat.set(textWidth / canvas.width, textHeight / canvas.height);

Then you can set the size of the sprite to just that portion

sprite.scale.set(textWidth, textHeight, 1);

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 400;

var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var config = {
  fontface: 'Arial',
  fontsize: 32,
  fontweight: 500,
  lineheight: 1,
};
var text = 'Hello world!';

function nextPowerOf2(n) {
  return Math.pow(2, Math.ceil(Math.log(n) / Math.log(2)));
}

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
const textMetrics = ctx.measureText(text);
var textWidth = textMetrics.width;
var textHeight = config.fontsize * config.lineheight;
canvas.width = nextPowerOf2(textWidth);
canvas.height = nextPowerOf2(textHeight);
ctx.fillStyle = 'red';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, textWidth, textHeight);
ctx.fillStyle = 'black';
ctx.textAlign = 'left';
ctx.textBaseline = 'top';
ctx.font = `${config.fontweight} ${config.fontsize}px/${config.lineheight} ${config.fontface}`;
ctx.fillText(text, 0, 0);

console.log('canvas', canvas.width, canvas.height);
console.log('text', textWidth, textHeight);

var texture = new THREE.Texture(canvas);
texture.needsUpdate = true;
texture.repeat.set(textWidth / canvas.width, textHeight / canvas.height);
var spriteMaterial = new THREE.SpriteMaterial({
  map: texture
});
var sprite = new THREE.Sprite(spriteMaterial);
sprite.scale.set(textWidth, textHeight, 1);
scene.add(sprite);

var animate = function() {
  requestAnimationFrame(animate);
  renderer.render(scene, camera);
};

animate();

body { margin: 0; }

<script src="https://threejsfundamentals.org/threejs/resources/threejs/r113/build/three.min.js"></script>


来源: stackexchange

问:
How to run ktor application?
I've created a Ktor application with Gradle and I followed the tutorial on https://ktor.io/quickstart/quickstart/gradle.html#initial.

At the end it says:

And then go to Run -> Edit Configurations select the blog.BlogAppKt
  configuration and change its Main class to:
  io.ktor.server.netty.EngineMain

Now when we run the new configuration, the application will start
  again.

I am searching for the option but could not find it:

The gradle file looks as follows:

```<code>plugins {
    application
    kotlin("jvm") version "1.3.61"
}

group = "org.example"
version = "1.0-SNAPSHOT"

val ktor_version = "1.3.0"

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))
    compile("io.ktor:ktor-server-netty:$ktor_version")
    compile("io.ktor:ktor-server-core:$ktor_version")
    compile("ch.qos.logback:logback-classic:1.2.3")
    testCompile(group = "junit", name = "junit", version = "4.12")
}

tasks {
    compileKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
    compileTestKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
}

application {
    mainClassName = "io.ktor.server.netty.EngineMain"
}
</code>```

Update

I'v tried following configuration:

But as you can, there is a error message.

What do I have to add to run the Ktor app?

答:
You need to create new Run configuration from template Application, not from Kotlin template. (And then fill Main class and Use classpath of module fields)

source:
https://ktor.io/servers/engine.html#running-the-application-from-inside-the-ide

ContentLicense: CC BY-SA 4.0

Title: How to run ktor application?

Body:
I've created a Ktor application with Gradle and I followed the tutorial on https://ktor.io/quickstart/quickstart/gradle.html#initial.

At the end it says:

And then go to Run -> Edit Configurations select the blog.BlogAppKt
  configuration and change its Main class to:
  io.ktor.server.netty.EngineMain

Now when we run the new configuration, the application will start
  again.

I am searching for the option but could not find it:

The gradle file looks as follows:

plugins {
    application
    kotlin("jvm") version "1.3.61"
}

group = "org.example"
version = "1.0-SNAPSHOT"

val ktor_version = "1.3.0"

repositories {
    mavenCentral()
    jcenter()
}

dependencies {
    implementation(kotlin("stdlib-jdk8"))
    compile("io.ktor:ktor-server-netty:$ktor_version")
    compile("io.ktor:ktor-server-core:$ktor_version")
    compile("ch.qos.logback:logback-classic:1.2.3")
    testCompile(group = "junit", name = "junit", version = "4.12")
}

tasks {
    compileKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
    compileTestKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
}

application {
    mainClassName = "io.ktor.server.netty.EngineMain"
}

Update

I'v tried following configuration:

But as you can, there is a error message.

What do I have to add to run the Ktor app?


问:
Flutter: animate appbar color with bottomnavigationbar
I wonna animate my appbar color the same way as the bottomnavigationbar does with the shifting type. So the appbar and bottomnavigationbar change color together.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  int _tabIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Dash')),
      body: Container(),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _tabIndex,
        onTap: (value) => setState(() => _tabIndex = value),
          type: BottomNavigationBarType.shifting,
          unselectedItemColor: Theme.of(context).unselectedWidgetColor,
          items: [
            BottomNavigationBarItem(
                icon: Icon(Icons.dashboard), title: Text('Dash'), backgroundColor: Colors.blue),
            BottomNavigationBarItem(
                icon: Icon(Icons.insert_chart), title: Text('Data'), backgroundColor: Colors.red),
            BottomNavigationBarItem(
                icon: Icon(Icons.monetization_on), title: Text('Income'), backgroundColor: Colors.orange),
          ]),
    );
  }
}
```

How can I do this? (I'm fairly new to flutter) Thanks!

答:
It's very simple. Simply change color based on the selected index.

Here you go

```<code>   import 'package:flutter/material.dart';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _tabIndex = 0;
  var colors = [Colors.blue, Colors.red, Colors.orange];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dash'),
        backgroundColor: colors[_tabIndex],
      ),
      body: Container(),
      bottomNavigationBar: BottomNavigationBar(
          currentIndex: _tabIndex,
          onTap: (value) => setState(() => _tabIndex = value),
          type: BottomNavigationBarType.shifting,
          unselectedItemColor: Theme.of(context).unselectedWidgetColor,
          items: [
            BottomNavigationBarItem(
                icon: Icon(Icons.dashboard),
                title: Text('Dash'),
                backgroundColor: colors[0]),
            BottomNavigationBarItem(
                icon: Icon(Icons.insert_chart),
                title: Text('Data'),
                backgroundColor: colors[1]),
            BottomNavigationBarItem(
                icon: Icon(Icons.monetization_on),
                title: Text('Income'),
                backgroundColor: colors[2]),
          ]),
    );
  }
}
</code>```

See the live demo here.

Body:
I wonna animate my appbar color the same way as the bottomnavigationbar does with the shifting type. So the appbar and bottomnavigationbar change color together.

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {

  int _tabIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Dash')),
      body: Container(),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _tabIndex,
        onTap: (value) => setState(() => _tabIndex = value),
          type: BottomNavigationBarType.shifting,
          unselectedItemColor: Theme.of(context).unselectedWidgetColor,
          items: [
            BottomNavigationBarItem(
                icon: Icon(Icons.dashboard), title: Text('Dash'), backgroundColor: Colors.blue),
            BottomNavigationBarItem(
                icon: Icon(Icons.insert_chart), title: Text('Data'), backgroundColor: Colors.red),
            BottomNavigationBarItem(
                icon: Icon(Icons.monetization_on), title: Text('Income'), backgroundColor: Colors.orange),
          ]),
    );
  }
}

How can I do this? (I'm fairly new to flutter) Thanks!

Body:
It's very simple. Simply change color based on the selected index.

Here you go

   import 'package:flutter/material.dart';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _tabIndex = 0;
  var colors = [Colors.blue, Colors.red, Colors.orange];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dash'),
        backgroundColor: colors[_tabIndex],
      ),
      body: Container(),
      bottomNavigationBar: BottomNavigationBar(
          currentIndex: _tabIndex,
          onTap: (value) => setState(() => _tabIndex = value),
          type: BottomNavigationBarType.shifting,
          unselectedItemColor: Theme.of(context).unselectedWidgetColor,
          items: [
            BottomNavigationBarItem(
                icon: Icon(Icons.dashboard),
                title: Text('Dash'),
                backgroundColor: colors[0]),
            BottomNavigationBarItem(
                icon: Icon(Icons.insert_chart),
                title: Text('Data'),
                backgroundColor: colors[1]),
            BottomNavigationBarItem(
                icon: Icon(Icons.monetization_on),
                title: Text('Income'),
                backgroundColor: colors[2]),
          ]),
    );
  }
}

See the live demo here.


问:
Hibernate Validator @SafeHtml fails to allow custom HTML tags and attributes
I have a Java-based back end in which I'm using Hibernate for some more specific bean validation, namely: @SafeHtml. It works great for 99% of my needs, however, I have a part that allows a user to enter basic HTML to create their own header/footer.  Therefore,  I need to be less restrictive here.

For some reason, something is not right in my code. I'm getting 400 Bad Request. I would really appreciate any help. Thank you in advance!

HTML:

```<code> <table bgcolor="navy" cellpadding="0" cellspacing="0" border="0" height="60" width="600" style="border-collapse:collapse;">
    <tr>
      <td>
          <div style="display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;">
          </div>
          <table align="left" width="600" class="email-container" cellpadding="0" cellspacing="0" border="0">
            <tr>
              <td style="padding: 20px 10px;width: 100%;font-size: 12px; mso-height-rule: exactly; line-height:14px; text-align: center; color: #CCCCCC;">
                © HELLO WORLD All rights reserved - <a href="https://www.someUrl" style="color: #CCCCCC" target="new" rel="noopener noreferrer">Privacy Policy GK</a>
              </td>
            </tr>
          </table>
      </td>
    </tr>
  </table>

Java:

    @SafeHtml(whitelistType = SafeHtml.WhiteListType.RELAXED,
            additionalTags = {"html", "tr", "body", "b", "i", "table", "td", "center", "div", "a", "img", "font"},
            additionalTagsWithAttributes = {
                    //@SafeHtml.Tag(name = "a", attributesWithProtocols = @SafeHtml.Attribute(name = "href", protocols = "#")),
                    @SafeHtml.Tag(name = "a", attributes = {"href"}),
                    @SafeHtml.Tag(name = "body", attributes = {"bgcolor", "width", "style"}),
                    @SafeHtml.Tag(name = "table", attributes = {"align", "bgcolor", "cellpadding", "cellspacing", "border", "height", "width", "style", "color", "class"}),
                    @SafeHtml.Tag(name = "td", attributes = {"style", "align", "bgcolor"}),
                    @SafeHtml.Tag(name = "font", attributes = {"face"}),
                    @SafeHtml.Tag(name = "img", attributes = {"src", "width", "height", "alt", "border"}),
                    @SafeHtml.Tag(name = ":all", attributes = {"style", "dir", "checked", "class", "id", "target", "title", "type"})
            })

</code>```

答:
You are not allowing for "rel" inside "a". Just try :

```<code>@SafeHtml.Tag(name = "a", attributes = {"href", "rel"}),
</code>```

And it will work.

Full test source:

```<code>package org.example;

import static org.junit.Assert.assertTrue;

import org.hibernate.validator.constraints.SafeHtml;
import org.hibernate.validator.internal.constraintvalidators.hv.SafeHtmlValidator;
import org.junit.Test;

@SafeHtml(whitelistType = SafeHtml.WhiteListType.RELAXED,
        additionalTags = {"html", "tr", "body", "b", "i", "table", "td", "center", "div", "a", "img", "font"},
        additionalTagsWithAttributes = {
                //@SafeHtml.Tag(name = "a", attributesWithProtocols = @SafeHtml.Attribute(name = "href", protocols = "#")),
                @SafeHtml.Tag(name = "a", attributes = {"href", "rel"}),
                @SafeHtml.Tag(name = "body", attributes = {"bgcolor", "width", "style"}),
                @SafeHtml.Tag(name = "table", attributes = {"align", "bgcolor", "cellpadding", "cellspacing", "border", "height", "width", "style", "color", "class"}),
                @SafeHtml.Tag(name = "td", attributes = {"style", "align", "bgcolor"}),
                @SafeHtml.Tag(name = "font", attributes = {"face"}),
                @SafeHtml.Tag(name = "img", attributes = {"src", "width", "height", "alt", "border"}),
                @SafeHtml.Tag(name = ":all", attributes = {"style", "dir", "checked", "class", "id", "target", "title", "type"})
        })
public class Q60122842Test
{
    @Test
    public void isValid()
    {
        String value = " <table bgcolor=\"navy\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" height=\"60\" width=\"600\" style=\"border-collapse:collapse;\">\n" +
                "    <tr>\n" +
                "      <td>\n" +
                "          <div style=\"display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;\">\n" +
                "          </div>\n" +
                "          <table align=\"left\" width=\"600\" class=\"email-container\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" +
                "            <tr>\n" +
                "              <td style=\"padding: 20px 10px;width: 100%;font-size: 12px; mso-height-rule: exactly; line-height:14px; text-align: center; color: #CCCCCC;\">\n" +
                "                © HELLO WORLD All rights reserved - <a href=\"https://www.someUrl\" style=\"color: #CCCCCC\" target=\"new\" rel=\"noopener noreferrer\">Privacy Policy GK</a>\n" +
                "              </td>\n" +
                "            </tr>\n" +
                "          </table>\n" +
                "      </td>\n" +
                "    </tr>\n" +
                "  </table>";

        SafeHtml annotation = Q60122842Test.class.getAnnotation(SafeHtml.class);
        SafeHtmlValidator validator = new SafeHtmlValidator();
        validator.initialize( annotation );
        assertTrue(validator.isValid(value, null));
    }
}
</code>```

Body:
I have a Java-based back end in which I'm using Hibernate for some more specific bean validation, namely: @SafeHtml. It works great for 99% of my needs, however, I have a part that allows a user to enter basic HTML to create their own header/footer.  Therefore,  I need to be less restrictive here.

For some reason, something is not right in my code. I'm getting 400 Bad Request. I would really appreciate any help. Thank you in advance!

HTML:

                © HELLO WORLD All rights reserved - Privacy Policy GK

Java:

    @SafeHtml(whitelistType = SafeHtml.WhiteListType.RELAXED,
            additionalTags = {"html", "tr", "body", "b", "i", "table", "td", "center", "div", "a", "img", "font"},
            additionalTagsWithAttributes = {
                    //@SafeHtml.Tag(name = "a", attributesWithProtocols = @SafeHtml.Attribute(name = "href", protocols = "#")),
                    @SafeHtml.Tag(name = "a", attributes = {"href"}),
                    @SafeHtml.Tag(name = "body", attributes = {"bgcolor", "width", "style"}),
                    @SafeHtml.Tag(name = "table", attributes = {"align", "bgcolor", "cellpadding", "cellspacing", "border", "height", "width", "style", "color", "class"}),
                    @SafeHtml.Tag(name = "td", attributes = {"style", "align", "bgcolor"}),
                    @SafeHtml.Tag(name = "font", attributes = {"face"}),
                    @SafeHtml.Tag(name = "img", attributes = {"src", "width", "height", "alt", "border"}),
                    @SafeHtml.Tag(name = ":all", attributes = {"style", "dir", "checked", "class", "id", "target", "title", "type"})
            })

Body:
You are not allowing for "rel" inside "a". Just try :

@SafeHtml.Tag(name = "a", attributes = {"href", "rel"}),

And it will work.

Full test source:

package org.example;

import static org.junit.Assert.assertTrue;

import org.hibernate.validator.constraints.SafeHtml;
import org.hibernate.validator.internal.constraintvalidators.hv.SafeHtmlValidator;
import org.junit.Test;

@SafeHtml(whitelistType = SafeHtml.WhiteListType.RELAXED,
        additionalTags = {"html", "tr", "body", "b", "i", "table", "td", "center", "div", "a", "img", "font"},
        additionalTagsWithAttributes = {
                //@SafeHtml.Tag(name = "a", attributesWithProtocols = @SafeHtml.Attribute(name = "href", protocols = "#")),
                @SafeHtml.Tag(name = "a", attributes = {"href", "rel"}),
                @SafeHtml.Tag(name = "body", attributes = {"bgcolor", "width", "style"}),
                @SafeHtml.Tag(name = "table", attributes = {"align", "bgcolor", "cellpadding", "cellspacing", "border", "height", "width", "style", "color", "class"}),
                @SafeHtml.Tag(name = "td", attributes = {"style", "align", "bgcolor"}),
                @SafeHtml.Tag(name = "font", attributes = {"face"}),
                @SafeHtml.Tag(name = "img", attributes = {"src", "width", "height", "alt", "border"}),
                @SafeHtml.Tag(name = ":all", attributes = {"style", "dir", "checked", "class", "id", "target", "title", "type"})
        })
public class Q60122842Test
{
    @Test
    public void isValid()
    {
        String value = " <table bgcolor=\"navy\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" height=\"60\" width=\"600\" style=\"border-collapse:collapse;\">\n" +
                "    <tr>\n" +
                "      <td>\n" +
                "          <div style=\"display:none;font-size:1px;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;mso-hide:all;font-family: sans-serif;\">\n" +
                "          </div>\n" +
                "          <table align=\"left\" width=\"600\" class=\"email-container\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n" +
                "            <tr>\n" +
                "              <td style=\"padding: 20px 10px;width: 100%;font-size: 12px; mso-height-rule: exactly; line-height:14px; text-align: center; color: #CCCCCC;\">\n" +
                "                © HELLO WORLD All rights reserved - <a href=\"https://www.someUrl\" style=\"color: #CCCCCC\" target=\"new\" rel=\"noopener noreferrer\">Privacy Policy GK</a>\n" +
                "              </td>\n" +
                "            </tr>\n" +
                "          </table>\n" +
                "      </td>\n" +
                "    </tr>\n" +
                "  </table>";

        SafeHtml annotation = Q60122842Test.class.getAnnotation(SafeHtml.class);
        SafeHtmlValidator validator = new SafeHtmlValidator();
        validator.initialize( annotation );
        assertTrue(validator.isValid(value, null));
    }
}


问:
Max salary of employee with name using MapReduce
Suppose I have a file in HDFS with the below data:

```<code>EmpId,EmpName,Dept,Salary

121,Raj,Dept1,8000
122,Kiran,Dept2,6000
123,John,Dept3,9000
</code>```

Using MapReduce I want to get only the Salary and EmpName of the employee with the max Salary

I was able to get the max Salary but not able to get the corresponding EmpName. I am able to get only the max Salary by keeping the empty key in my map class and Math.max() in my reduce class. When I keep the key as EmpName then it is displaying all the salaries of unique employees.

My Mapreduce code

File : test.csv

```<code>121,Raj,Dept1,8000
122,Kiran,Dept2,6000
123,John,Dept3,9000
</code>```

```<code>public static class MyMap extends Mapper<LongWritable,Text,Text,IntWritable>
 {
  public void map(LongWritable k,Text v, Context con)throws IOException, InterruptedException
  {
   String line = v.toString();
   String[] w=line.split(",");
   int sal=Integer.parseInt(w[3]);
   con.write(new Text("Raj"), new IntWritable(sal));
   }
 }

 public static class MyRed extends Reducer<Text,IntWritable,IntWritable,Text>
 {
  public void reduce(Text k, Iterable<IntWritable> vlist, Context con)
  throws IOException , InterruptedException
     {
      int max=0;
      for(IntWritable v:vlist)
   {
      max=Math.max(max, v.get());
   }

   con.write(new IntWritable(max), new Text());
  }
</code>```

Output :

```<code>9000
</code>```

Here I need the output to be:

```<code>9000 John
</code>```

Please let me know how to get this output.

答:
You have to pass values from mapper like {raj,8000 kiran,6000 john,9000} , so key will be constant , in following code you can check how it can be done ,

```<code> public class MyMap extends Mapper<LongWritable,Text,Text,Text>
   {
     public void map(LongWritable k,Text v, Mapper<LongWritable,Text,Text,Text>.Context
     con)throws IOException, InterruptedException
   {
     String line = v.toString();
     String[] w=line.split(",");
     String name = w[1] ;
    int sal=Integer.parseInt(w[3]);
    String map_op = name+","+sal ;
    con.write(new Text("ds"), new Text(map_op));
    //ds {raj,8000 kiran,6000 john,9000}

    }
   }
</code>```

after shuffling and sorting "//ds {raj,8000 kiran,6000 john,9000}"

This will be the result,here we are passing ds as key ,

Now let's have a look at reducer method

```<code>    public class MyRed extends Reducer<Text,Text,IntWritable,Text>
{

      //ds {raj,8000 kiran,6000 john,9000}

 public void reduce(Text k, Iterable<Text> vlist, Reducer<Text,Text,IntWritable,Text>.Context con)
 throws IOException , InterruptedException
    {
     int max=0;
     String name = k.toString() ;

     for(Text v: vlist)
  {

         int salary = Integer.parseInt(v.toString().split(",")[1]) ;
         max=Math.max(max, salary);

         if(salary == max)
        {
            name = v.toString().split(",")[0] ;
        }
  }

  con.write(new IntWritable(max), new Text(name));
 }
}
</code>```

//9000 john :- This o/p will be produced by reducer

Body:
Suppose I have a file in HDFS with the below data:

EmpId,EmpName,Dept,Salary

121,Raj,Dept1,8000
122,Kiran,Dept2,6000
123,John,Dept3,9000

Using MapReduce I want to get only the Salary and EmpName of the employee with the max Salary

I was able to get the max Salary but not able to get the corresponding EmpName. I am able to get only the max Salary by keeping the empty key in my map class and Math.max() in my reduce class. When I keep the key as EmpName then it is displaying all the salaries of unique employees.

My Mapreduce code

File : test.csv

121,Raj,Dept1,8000
122,Kiran,Dept2,6000
123,John,Dept3,9000

public static class MyMap extends Mapper<LongWritable,Text,Text,IntWritable>
 {
  public void map(LongWritable k,Text v, Context con)throws IOException, InterruptedException
  {
   String line = v.toString();
   String[] w=line.split(",");
   int sal=Integer.parseInt(w[3]);
   con.write(new Text("Raj"), new IntWritable(sal));
   }
 }

 public static class MyRed extends Reducer<Text,IntWritable,IntWritable,Text>
 {
  public void reduce(Text k, Iterable<IntWritable> vlist, Context con)
  throws IOException , InterruptedException
     {
      int max=0;
      for(IntWritable v:vlist)
   {
      max=Math.max(max, v.get());
   }

   con.write(new IntWritable(max), new Text());
  }

Output :

9000

Here I need the output to be:

9000 John

Please let me know how to get this output.

Body:
You have to pass values from mapper like {raj,8000 kiran,6000 john,9000} , so key will be constant , in following code you can check how it can be done ,

 public class MyMap extends Mapper<LongWritable,Text,Text,Text>
   {
     public void map(LongWritable k,Text v, Mapper<LongWritable,Text,Text,Text>.Context
     con)throws IOException, InterruptedException
   {
     String line = v.toString();
     String[] w=line.split(",");
     String name = w[1] ;
    int sal=Integer.parseInt(w[3]);
    String map_op = name+","+sal ;
    con.write(new Text("ds"), new Text(map_op));
    //ds {raj,8000 kiran,6000 john,9000}

    }
   }

after shuffling and sorting "//ds {raj,8000 kiran,6000 john,9000}"

This will be the result,here we are passing ds as key ,

Now let's have a look at reducer method

    public class MyRed extends Reducer<Text,Text,IntWritable,Text>
{

      //ds {raj,8000 kiran,6000 john,9000}

 public void reduce(Text k, Iterable<Text> vlist, Reducer<Text,Text,IntWritable,Text>.Context con)
 throws IOException , InterruptedException
    {
     int max=0;
     String name = k.toString() ;

     for(Text v: vlist)
  {

         int salary = Integer.parseInt(v.toString().split(",")[1]) ;
         max=Math.max(max, salary);

         if(salary == max)
        {
            name = v.toString().split(",")[0] ;
        }
  }

  con.write(new IntWritable(max), new Text(name));
 }
}

//9000 john :- This o/p will be produced by reducer


问:
Populate no.of days in html table
How to Calculate and populate no. of days between two input dates in an Html table row by using javascript?
I have an understanding of Html, javascript, jQuery

I am a new programmer and I stuck on this step please help me out
Thanks

答:
use

```<code>function datesDiff(d1, d2){return (new Date(d1)-new Date(d2))/(1000*60*60*24)}
</code>```

example usage:

```<code>datesDiff('03/12/2019', '02/12/2019'); //output 28
</code>```

Title: Populate no.of days in html table

Body:
use

function datesDiff(d1, d2){return (new Date(d1)-new Date(d2))/(1000*60*60*24)}

example usage:

datesDiff('03/12/2019', '02/12/2019'); //output 28


问:
When I kill a process in Android a Service is not restarted
I know that I can kill a process when I press the red square button that is in the logcat (Having the corresponding device and process selected).

This image shows the way I use to kill an android process

However, when I do that the service is not restarted how I expect. It calls onCreate and onDestroy and it doesn't call onStartCommand despite the fact that the onStartCommand returns START_STICKY.

I show you my code and please if you have an idea of what the problem might be tell me

Service code to start a music

答:
you need stop service:

```<code>Intent myService = new Intent(MainActivity.this, BackgroundSoundService.class);
stopService(myService);
</code>```

Body:
you need stop service:

Intent myService = new Intent(MainActivity.this, BackgroundSoundService.class);
stopService(myService);


问:
Make a play pause switch with html audio
I'm looking for a way to do a play / pause action on click of an element.

Basically when you click and the track is not playing it plays and when it's playing and you click it stops.

So far I was looking for a solution like this but it seems to make a conflict between the play / pause action.

```<code>$('#feli').click(function() {
  feli.currentTime = 0;
  if (feli.play()) {
    feli.pause();
  } else {
    feli.play();;
  }
})
</code>```

Any tips on how to do this simple action ?

Thanks !!

答:
check this code plz</p>

```<code>$('#feli').click(function() {

  if (feli.play()) {
    feli.pause();
    feli.currentTime = 0;
  } else {
    feli.play();;
  }
});
</code>```

Body:
I'm looking for a way to do a play / pause action on click of an element.

Basically when you click and the track is not playing it plays and when it's playing and you click it stops.

So far I was looking for a solution like this but it seems to make a conflict between the play / pause action.

$('#feli').click(function() {
  feli.currentTime = 0;
  if (feli.play()) {
    feli.pause();
  } else {
    feli.play();;
  }
})

Any tips on how to do this simple action ?

Thanks !!

Body:
check this code plz

$('#feli').click(function() {

  if (feli.play()) {
    feli.pause();
    feli.currentTime = 0;
  } else {
    feli.play();;
  }
});


问:
django mutlipleChoiceField how to validate?
i have the form below :

forms.py :

```<code>class enrolForm(forms.Form):
    CHOICES = [('male','male'),('female','female')]
    students = forms.MultipleChoiceField(choices = CHOICES)
</code>```

views.py :

```<code> form = enrolForm(request.POST)
 if form.is_valid():
            print "creating student"
            exam = models.Exam.objects.get(name=examName)
            .
            .#more code .......
</code>```

it NEVER  gets to ( print "creating student" ), the form is never valid  . why is that ?
how do i validate such a form
please help

EDIT :
it says in the form.errors :

 students

This field is required.

EDIT:

views.py :

```<code>def enrol(request,examName):
    print "EXAm naaame"
    form = enrolForm()
    allStudents = models.User.objects.filter(groups__name="students")
    myList = []

    for i in allStudents:
        myList.append((i,i))

    print allStudents,'33333333333333333333'

    form.fields['students'].choices = myList

    if request.method == 'POST':
        form = enrolForm(request.POST)

        if form.is_valid():
            exam = models.Exam.objects.get(name=examName)
            for i in form.cleaned_data['students']:

                user= models.User.objects.get(username=i)
                exam = models.Exam.objects.get(name= examName)
                models.Exam_Student.objects.create(user,exam)

            return render_to_response('enrol.html',RequestContext(request,{'form':form}))

    variables = RequestContext(request,{'form':form})
    return render_to_response("enrol.html",variables)
</code>```

答:
Your form isn't valid because the students field is required. That means you must select a student in order for is_valid() to be true.

EDIT: For some odd reason, I couldn't add new lines in my comments, so I'm adding this here...

For testing purposes, remove everything but the essentials and see what happens:

```<code>def enrol(request):
    if request.method == 'POST':
        form = enrolForm(request.POST)
        if form.is_valid():
            print 'Valid form'
        else:
            print form
    else:
        form = enrolForm()

    return render_to_response('enrol.html', {'form' : form}, context_instance=RequestContext(request))
</code>```

ContentLicense: CC BY-SA 3.0

Body:
i have the form below :

forms.py :

class enrolForm(forms.Form):
    CHOICES = [('male','male'),('female','female')]
    students = forms.MultipleChoiceField(choices = CHOICES)

views.py :

 form = enrolForm(request.POST)
 if form.is_valid():
            print "creating student"
            exam = models.Exam.objects.get(name=examName)
            .
            .#more code .......

it NEVER  gets to ( print "creating student" ), the form is never valid  . why is that ?
how do i validate such a form
please help

EDIT :
it says in the form.errors :

 students

This field is required.

EDIT:

views.py :

def enrol(request,examName):
    print "EXAm naaame"
    form = enrolForm()
    allStudents = models.User.objects.filter(groups__name="students")
    myList = []

    for i in allStudents:
        myList.append((i,i))

    print allStudents,'33333333333333333333'

    form.fields['students'].choices = myList

    if request.method == 'POST':
        form = enrolForm(request.POST)

        if form.is_valid():
            exam = models.Exam.objects.get(name=examName)
            for i in form.cleaned_data['students']:

                user= models.User.objects.get(username=i)
                exam = models.Exam.objects.get(name= examName)
                models.Exam_Student.objects.create(user,exam)

            return render_to_response('enrol.html',RequestContext(request,{'form':form}))

    variables = RequestContext(request,{'form':form})
    return render_to_response("enrol.html",variables)

Body:
Your form isn't valid because the students field is required. That means you must select a student in order for is_valid() to be true.

EDIT: For some odd reason, I couldn't add new lines in my comments, so I'm adding this here...

For testing purposes, remove everything but the essentials and see what happens:

def enrol(request):
    if request.method == 'POST':
        form = enrolForm(request.POST)
        if form.is_valid():
            print 'Valid form'
        else:
            print form
    else:
        form = enrolForm()

    return render_to_response('enrol.html', {'form' : form}, context_instance=RequestContext(request))


问:
Set all items to a listview from a file .txt (ArrayList) what contains textview value [Android Java]
I want after a button onClick generate1() show all items from my Arraylist(.txt) contains Edittext value.

I am a beginner in android java programming.

This is my onClick Method generate1():

```<code>    public void generate1(View view) throws IOException {

        ArrayAdapter<String> adapter;
        ArrayList<String> ls = new ArrayList<>();
        EditText editText = (EditText) findViewById(R.id.editText);

        BufferedReader br = null;

        br = new BufferedReader(new InputStreamReader(getAssets().open("themen.txt")));
        String word;
        while ((word = br.readLine()) != null) {
            ls.add(word);
        }
        br.close();
        ListView listView = (ListView) findViewById(R.id.listView);
        adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,ls);
        listView.setAdapter(adapter);

        for (String e : ls){
           if (e.toLowerCase().contains(editText.getText().toString())){
              //???? some toDO ???? (if i do here System.out.println(e); its work, but i want the Items to a listview!!
           }
        }
    }
</code>```

答:
First create an adapter class like this:

```<code>public class DemoAdapter extends BaseAdapter {
    private ArrayList<String> data;
    private Context context;
    private LayoutInflater inflater;

    public DemoAdapter(ArrayList<String> data, Context context) {
        this.data = data;
        this.context = context;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int i) {
        return data.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {

        MyViewHolder myViewHolder;

        if (view==null){
            view = inflater.inflate(android.R.layout.simple_list_item_1,viewGroup,false);
            myViewHolder = new MyViewHolder(view);
            view.setTag(myViewHolder);
        } else {
            myViewHolder = (MyViewHolder) view.getTag();
        }

        myViewHolder.myTv.setText(data.get(i));

        return view;
    }

    class MyViewHolder{
        TextView myTv;

        public MyViewHolder(View item){
            myTv = item.findViewById(android.R.id.text1);
        }
    }
}
</code>```

Then in your generate1 method iniialize it like this:

```<code>DemoAdapter adapter = DemoAdapter(this,ls);
listView.setAdapter(adapter);
</code>```

Body:
I want after a button onClick generate1() show all items from my Arraylist(.txt) contains Edittext value.

I am a beginner in android java programming.

This is my onClick Method generate1():

    public void generate1(View view) throws IOException {

        ArrayAdapter<String> adapter;
        ArrayList<String> ls = new ArrayList<>();
        EditText editText = (EditText) findViewById(R.id.editText);

        BufferedReader br = null;

        br = new BufferedReader(new InputStreamReader(getAssets().open("themen.txt")));
        String word;
        while ((word = br.readLine()) != null) {
            ls.add(word);
        }
        br.close();
        ListView listView = (ListView) findViewById(R.id.listView);
        adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1,ls);
        listView.setAdapter(adapter);

        for (String e : ls){
           if (e.toLowerCase().contains(editText.getText().toString())){
              //???? some toDO ???? (if i do here System.out.println(e); its work, but i want the Items to a listview!!
           }
        }
    }

Body:
First create an adapter class like this:

public class DemoAdapter extends BaseAdapter {
    private ArrayList<String> data;
    private Context context;
    private LayoutInflater inflater;

    public DemoAdapter(ArrayList<String> data, Context context) {
        this.data = data;
        this.context = context;
    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int i) {
        return data.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int i, View view, ViewGroup viewGroup) {

        MyViewHolder myViewHolder;

        if (view==null){
            view = inflater.inflate(android.R.layout.simple_list_item_1,viewGroup,false);
            myViewHolder = new MyViewHolder(view);
            view.setTag(myViewHolder);
        } else {
            myViewHolder = (MyViewHolder) view.getTag();
        }

        myViewHolder.myTv.setText(data.get(i));

        return view;
    }

    class MyViewHolder{
        TextView myTv;

        public MyViewHolder(View item){
            myTv = item.findViewById(android.R.id.text1);
        }
    }
}

Then in your generate1 method iniialize it like this:

DemoAdapter adapter = DemoAdapter(this,ls);
listView.setAdapter(adapter);


答:
You better use Foreground Service for music playback.

Also, you should try killing your app like this

Phone Settings>Apps>your app> Force Stop

Title: When I kill a process in Android a Service is not restarted

Body:
I know that I can kill a process when I press the red square button that is in the logcat (Having the corresponding device and process selected).

This image shows the way I use to kill an android process

However, when I do that the service is not restarted how I expect. It calls onCreate and onDestroy and it doesn't call onStartCommand despite the fact that the onStartCommand returns START_STICKY.

I show you my code and please if you have an idea of what the problem might be tell me

Service code to start a music


问:
Array of Strings to an Array of Objects
Maybe there is a method that does this that I don't know about - I doubt it though - but I'm trying to convert an array of strings to an array of Objects. Here is the problem: I'm reading a file in from the command line. The file represents several classes of the following types each with their own data fields. Vehicle is the parent class of all who follow: Vehicle,Car,American Car, Foreign car, Truck, Bicycle.

I have no problem reading the file into a string array. However I need to create objects of all these types and store them in an array of type Vehicle[]. For example a portion of the file looks like this:

Vehicle

Kim Stanley Robinson

2344 court drive

(221)885-7777

stackoverflow@overflow.com

American Car

John Bunyon

1010 binary lane

(221)885-55643

bgt.com

convertable

made in detroit

 union plant

Where Class type is the first line followed by, Owner's Name, address, phone number, email address...Each type has fields particular to it. So a foreign car is not made in Detroit. Each of these fields appear on a separate line in the file. So what I've done is read the  entire file into a string array. However, I need to find my types in the array of strings,create objects of those types, and store them in a Vehicle array. My main problem is that each data field is on a separate line. How should I approach this problem?
This is java code by the way.

答:
question is unclear. Do you want to know how to parse the file and use the words on each line to create a object of it?

pseudo:

```<code>Vehicle_ptr myVeh = null;
for each line in file
switch line
{
case vehicle: myVeh = new Vehicle();
case American Car : myVeh = new AmericanCar();
default:
if (line.startswithaninteger && (myVeh != NULL)) myVeh.address = line;
etcetc.
}
</code>```

Tips: use typeidentifiers in the textfile.for example:
car:americancar
address:12345 bla
etcetc

Or use a serializer

OwnerDisplayName: BloodParrot

ContentLicense: CC BY-SA 2.5

Title: Array of Strings to an Array of Objects

Body:
question is unclear. Do you want to know how to parse the file and use the words on each line to create a object of it?

pseudo:

Vehicle_ptr myVeh = null;
for each line in file
switch line
{
case vehicle: myVeh = new Vehicle();
case American Car : myVeh = new AmericanCar();
default:
if (line.startswithaninteger && (myVeh != NULL)) myVeh.address = line;
etcetc.
}

Tips: use typeidentifiers in the textfile.for example:
car:americancar
address:12345 bla
etcetc

Or use a serializer

OwnerDisplayName: PoweRoy


问:
How to safe data from another thread to use on controls?
I have a library that serves using events data came in from async tcp operations.
When using those data in controls after they received on the UI though I get Cross-Thread Opration exception. How to solve this problem before the consumer of the library gets the data to show on his controls. So basically I need to throw the data to his own thread where using the library?

The same code used for the compact framework with linked files.

I'm using inside the library this method with a help Control to say if invoke is required but its not working.

```<code>public static void InvokeIfNecessary(Control control, Action setValue)
{

    if (control.InvokeRequired)
    {
        control.Invoke(setValue);
    }
    else
    {
        setValue();
    }
}
</code>```

A sample code using an event to serve data to the user using the library.

```<code>    if (OnClientChangeConnection != null) SafeData.InvokeIfNecessary(_helpControl, () => OnClientChangeConnection(ConnectedClients, requestClientInfo)); // ConnectedClients is an integer and requestClientInfo is a List<ClientInfo> class type.
</code>```

Thank you.

答: You can save a reference to SynchronizationContext.Current from the UI thread, then call its Post or Send methods to run code on the UI thread.

Body:
I have a library that serves using events data came in from async tcp operations.
When using those data in controls after they received on the UI though I get Cross-Thread Opration exception. How to solve this problem before the consumer of the library gets the data to show on his controls. So basically I need to throw the data to his own thread where using the library?

The same code used for the compact framework with linked files.

I'm using inside the library this method with a help Control to say if invoke is required but its not working.

public static void InvokeIfNecessary(Control control, Action setValue)
{

    if (control.InvokeRequired)
    {
        control.Invoke(setValue);
    }
    else
    {
        setValue();
    }
}

A sample code using an event to serve data to the user using the library.

    if (OnClientChangeConnection != null) SafeData.InvokeIfNecessary(_helpControl, () => OnClientChangeConnection(ConnectedClients, requestClientInfo)); // ConnectedClients is an integer and requestClientInfo is a List<ClientInfo> class type.

Thank you.


问:
Class in javascript just show the lastest state when process
i have the following code:

```<code>solve(maze){
        let animateMaze = [];
        function resolveMaze(maze){
            let currentCell = maze.getNextUnsolveCell();
            //already solved maze
            if(currentCell===undefined) {
                return true;
            }
            let availableValues = maze.getAvailableValues(currentCell);
            for(let value of availableValues){
                maze.setValueForCell(currentCell,value);
                console.log(maze); //always show the final maze, not the current maze
                animateMaze.push(maze);
                if(resolveMaze(maze)){
                    return true;
                }
            }
            maze.setValueForCell(currentCell,0);

            return false;
        }

        if(resolveMaze(maze)){
            return animateMaze;
        }
        else
        {
            return undefined;
        }

    }
</code>```

i have an object maze in that code. what i tried to do is pushing the state of the object maze to an array. I will use this array to show the process step of the function. But i dont know why in each step, when i console log the maze, the value of maze is always the final state ( after processed is done). And array animateMaze is contain array of the same maze.
Does anyone has any solution for this?

答:
The issue is that maze variable is a reference to one object. In js any time you pass a reference to a function, it will copy the reference and this reference will still point out to the same object. And so every time you call resolveMaze function it uses the same maze over and over. The solution is to copy maze variable before calling a resolveMaze function so it takes new maze every time.

So how do I copy maze variable?

It depends on what maze variable represents, because it can either a class instance, an
object, it can have nested structures and so on. So it's up to you find proper way to copy it.

Hope it was clear and helpful :)

Body:
i have the following code:

solve(maze){
        let animateMaze = [];
        function resolveMaze(maze){
            let currentCell = maze.getNextUnsolveCell();
            //already solved maze
            if(currentCell===undefined) {
                return true;
            }
            let availableValues = maze.getAvailableValues(currentCell);
            for(let value of availableValues){
                maze.setValueForCell(currentCell,value);
                console.log(maze); //always show the final maze, not the current maze
                animateMaze.push(maze);
                if(resolveMaze(maze)){
                    return true;
                }
            }
            maze.setValueForCell(currentCell,0);

            return false;
        }

        if(resolveMaze(maze)){
            return animateMaze;
        }
        else
        {
            return undefined;
        }

    }

i have an object maze in that code. what i tried to do is pushing the state of the object maze to an array. I will use this array to show the process step of the function. But i dont know why in each step, when i console log the maze, the value of maze is always the final state ( after processed is done). And array animateMaze is contain array of the same maze.
Does anyone has any solution for this?


问:
Error installing mongodb , broken ubuntu dependency
Trying to install mongo with below command</p>

```<code>rahul@rahul ~ $ sudo apt-get install -y mongodb-org
Reading package lists... Done
Building dependency tree
Reading state information... Done
mongodb-org is already the newest version (3.6.2).
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
 mongodb-org : Depends: mongodb-org-tools but it is not going to be installed
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).
</code>```

答:
I had this same issue installing mongodb-org on an Ubuntu 18 box.

The issue was that a version of mongodb was already installed, and it had to be removed before I continued.

The solution was to run the following:

```<code>sudo apt remove mongodb-org
sudo apt purge mongodb-org
sudo apt autoremove

sudo apt-get install mongodb-org
</code>```

More info can be found on the Mongodb website - apparently this is a frequent enough issue that they had to address it there!

Body:
Trying to install mongo with below command

rahul@rahul ~ $ sudo apt-get install -y mongodb-org
Reading package lists... Done
Building dependency tree
Reading state information... Done
mongodb-org is already the newest version (3.6.2).
You might want to run 'apt --fix-broken install' to correct these.
The following packages have unmet dependencies:
 mongodb-org : Depends: mongodb-org-tools but it is not going to be installed
E: Unmet dependencies. Try 'apt --fix-broken install' with no packages (or specify a solution).

Body:
I had this same issue installing mongodb-org on an Ubuntu 18 box.

The issue was that a version of mongodb was already installed, and it had to be removed before I continued.

The solution was to run the following:

sudo apt remove mongodb-org
sudo apt purge mongodb-org
sudo apt autoremove

sudo apt-get install mongodb-org

More info can be found on the Mongodb website - apparently this is a frequent enough issue that they had to address it there!


问:
How to change values/items stored in LocalStorage
I have created a website where the user enters the movie that they have previously watched, this is stored in a database and then outputted, using local storage on a separate page under their history. This worked for the first user, however the output under history doesn't change according to the user, as the values in local storage doesn't change.
Is there another method of storage I should use, or can this be fixed using local storage.

```
<pre class="snippet-code-html lang-html prettyprint-override"><code><?php // retrieving users history from database
 for ($x = 0; $x<=$length -1; $x++){
        $select = $history[$x];
        $sql2= "SELECT FilmTitle FROM Films WHERE FilmID=".$select;
        $sql3= "SELECT imgFilm FROM Films WHERE FilmID=".$select;
        $result2 = mysqli_query($conn, $sql2);
        $result3 = mysqli_query($conn, $sql3);
        if (mysqli_num_rows($result2)> 0){
            while($row2 = mysqli_fetch_assoc($result2)){
                $h_films[] = $row2;
            }
            while($row3 = mysqli_fetch_assoc($result3)){
                $h_img[] = $row3;
            }
        }
    }
    $h_names = array();
    $h_images = array();

    for ($x = 0; $x<=$length -1; $x++){
        foreach($h_films[$x] as $data){
           // echo ($data['FilmTitle']);
            array_push($h_names,$data);
          // array_push($names,$value);
        }
    }
    for ($x = 0; $x<=$length -1; $x++){
        foreach($h_img[$x] as $imgdata){
           // echo ($data['FilmTitle']);
            array_push($h_images,$imgdata);
        }
    }
?>

<script> // storing databse results from localstorage
    var users = <?php echo json_encode(($h_names)) ;?>;
    document.cookie= "historynames="+ users;
    var users2 = <?php echo json_encode(($h_images)) ;?>;
    localStorage.setItem('historyimages', users2);
</script></code>```

答: you can make it simple and more secure you can store the values in the cookies in php and use them anywhere in your steps page</p>

Body:
I have created a website where the user enters the movie that they have previously watched, this is stored in a database and then outputted, using local storage on a separate page under their history. This worked for the first user, however the output under history doesn't change according to the user, as the values in local storage doesn't change.
Is there another method of storage I should use, or can this be fixed using local storage.

<?php // retrieving users history from database
 for ($x = 0; $x<=$length -1; $x++){
        $select = $history[$x];
        $sql2= "SELECT FilmTitle FROM Films WHERE FilmID=".$select;
        $sql3= "SELECT imgFilm FROM Films WHERE FilmID=".$select;
        $result2 = mysqli_query($conn, $sql2);
        $result3 = mysqli_query($conn, $sql3);
        if (mysqli_num_rows($result2)> 0){
            while($row2 = mysqli_fetch_assoc($result2)){
                $h_films[] = $row2;
            }
            while($row3 = mysqli_fetch_assoc($result3)){
                $h_img[] = $row3;
            }
        }
    }
    $h_names = array();
    $h_images = array();

    for ($x = 0; $x<=$length -1; $x++){
        foreach($h_films[$x] as $data){
           // echo ($data['FilmTitle']);
            array_push($h_names,$data);
          // array_push($names,$value);
        }
    }
    for ($x = 0; $x<=$length -1; $x++){
        foreach($h_img[$x] as $imgdata){
           // echo ($data['FilmTitle']);
            array_push($h_images,$imgdata);
        }
    }
?>


问:
How to convert eps files to png files with maintaining names?
In some folder on Linux I have got files *.eps and I would like to convert them into *.png with maintaining names, e.g.: ball.eps to ball.png. I tried to do:

```<code>convert *.eps *.png
</code>```

but the result wasn't satisfied. To do that I need to write some simple script maybe in Python or bash, so how can I take the files name from folder, e.g. in Python? Thanks.

答:
Since I landed here while looking for a way to fix convert: not authorized without loosening the security policy for the entire system, I might as well present some improvements to @vaibhav-jain's answer.

First, if you're rasterizing EPS to PNG, here's how to skip ImageMagic and go straight to Ghostscript:

#!/bin/sh

for file in *.eps; do
    gs -dSAFER -dEPSCrop -r300 -sDEVICE=pngalpha -o "${file%.*}.png" "$file"
done
```

-dSAFER puts Ghostscript in a sandboxed mode where Postscript code can only interact with the files you specified on the command line. (Yes, Postscript is turing-complete.)

-dEPSCrop asks Ghostscript to not pad it out to the size of a printable page. (details)

If you're rasterizing EPS, you probably don't want the default of 72 DPI, so -r300 specifies 300 DPI. (details)

-sDEVICE is how you pick the output format (See the Devices section of the manual for other choices.)

-o is a shorthand for -dBATCH -dNOPAUSE -sOutputFile= (details)

As for the other changes:

It's unnecessary to strip off the leading path unless you're in a situation where you don't want the output files to go into the same folder as the input ones... in that case, however, you can replace $(basename "$file") with ${file##*/} (strip characters up to and including last /) to stick to shell built-ins.

If you're using Zsh and want to write a one-off one-liner, Zsh allows nesting substitutions, so ${${file##*/}%.*} is valid.

Just as a matter of style, I prefer for ...; do over putting do on its own line.

Nothing in the script requires bash, so use #!/bin/sh in such situations and you'll get a lighter runtime environment (dash) on Debian-based systems and be compatible with BSDs that don't install a /bin/bash by default.

Body:
In some folder on Linux I have got files *.eps and I would like to convert them into *.png with maintaining names, e.g.: ball.eps to ball.png. I tried to do:

convert *.eps *.png

but the result wasn't satisfied. To do that I need to write some simple script maybe in Python or bash, so how can I take the files name from folder, e.g. in Python? Thanks.

Body:
Since I landed here while looking for a way to fix convert: not authorized without loosening the security policy for the entire system, I might as well present some improvements to @vaibhav-jain's answer.

First, if you're rasterizing EPS to PNG, here's how to skip ImageMagic and go straight to Ghostscript:

#!/bin/sh

for file in *.eps; do
    gs -dSAFER -dEPSCrop -r300 -sDEVICE=pngalpha -o "${file%.*}.png" "$file"
done

-dSAFER puts Ghostscript in a sandboxed mode where Postscript code can only interact with the files you specified on the command line. (Yes, Postscript is turing-complete.)

-dEPSCrop asks Ghostscript to not pad it out to the size of a printable page. (details)

If you're rasterizing EPS, you probably don't want the default of 72 DPI, so -r300 specifies 300 DPI. (details)

-sDEVICE is how you pick the output format (See the Devices section of the manual for other choices.)

-o is a shorthand for -dBATCH -dNOPAUSE -sOutputFile= (details)

As for the other changes:

It's unnecessary to strip off the leading path unless you're in a situation where you don't want the output files to go into the same folder as the input ones... in that case, however, you can replace $(basename "$file") with ${file##*/} (strip characters up to and including last /) to stick to shell built-ins.

If you're using Zsh and want to write a one-off one-liner, Zsh allows nesting substitutions, so ${${file##*/}%.*} is valid.

Just as a matter of style, I prefer for ...; do over putting do on its own line.

Nothing in the script requires bash, so use #!/bin/sh in such situations and you'll get a lighter runtime environment (dash) on Debian-based systems and be compatible with BSDs that don't install a /bin/bash by default.


问:
Edit and delete the item from recyclerview on swipe?
Iam trying to edit and delete items in recyclerview.
When I swipe recyclerview I should get 2 buttons. One is for editing the data and the other buttonis for deleting the data from recyclerview. </p>

```<code>public class Bills_Adapter extends RecyclerView.Adapter<Bills_Adapter.BillHolder> implements Filterable
{

    Context context;
    List<Manager_Bill_Model> bill_lists;

    public Bills_Adapter(Context context, List<Manager_Bill_Model> bill_lists)
    {
        this.context = context;
        this.bill_lists = bill_lists;
    }

    @Override
    public BillHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i)
    {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_bills, viewGroup, false);
        BillHolder billHolder = new BillHolder(v);
        return billHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull BillHolder billHolder, int i)
    {
        billHolder.tview_billNumber.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                final Dialog dialog = new Dialog(context);
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                dialog.setContentView(R.layout.activity_bill_dialog);
                dialog.getWindow().setLayout(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
                dialog.show();

            }
        });

    }

    @Override
    public int getItemCount() {
        return 50;
    }

    @Override
    public Filter getFilter() {
        return null;
    }

    public class BillHolder extends RecyclerView.ViewHolder
    {
        TextView tview_billNumber;

        public BillHolder(@NonNull View itemView)
        {
            super(itemView);
            tview_billNumber = itemView.findViewById(R.id.tview_billNumber);
        }
    }
}
</code>```

答:
```<code>    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.graphics.Point;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.support.v7.widget.RecyclerView;
    import android.support.v7.widget.helper.ItemTouchHelper;
    import android.util.Log;
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.View;

    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Map;
    import java.util.Queue;

    public abstract class SwipeHelper extends ItemTouchHelper.SimpleCallback {

        public static final int BUTTON_WIDTH = YOUR_WIDTH_IN_PIXEL_PER_BUTTON
        private RecyclerView recyclerView;
        private List<UnderlayButton> buttons;
        private GestureDetector gestureDetector;
        private int swipedPos = -1;
        private float swipeThreshold = 0.5f;
        private Map<Integer, List<UnderlayButton>> buttonsBuffer;
        private Queue<Integer> recoverQueue;

        private GestureDetector.SimpleOnGestureListener gestureListener = new GestureDetector.SimpleOnGestureListener(){
            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                for (UnderlayButton button : buttons){
                    if(button.onClick(e.getX(), e.getY()))
                        break;
                }

                return true;
            }
        };

        private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent e) {
                if (swipedPos < 0) return false;
                Point point = new Point((int) e.getRawX(), (int) e.getRawY());

                RecyclerView.ViewHolder swipedViewHolder = recyclerView.findViewHolderForAdapterPosition(swipedPos);
                View swipedItem = swipedViewHolder.itemView;
                Rect rect = new Rect();
                swipedItem.getGlobalVisibleRect(rect);

                if (e.getAction() == MotionEvent.ACTION_DOWN || e.getAction() == MotionEvent.ACTION_UP ||e.getAction() == MotionEvent.ACTION_MOVE) {
                    if (rect.top < point.y && rect.bottom > point.y)
                        gestureDetector.onTouchEvent(e);
                    else {
                        recoverQueue.add(swipedPos);
                        swipedPos = -1;
                        recoverSwipedItem();
                    }
                }
                return false;
            }
        };

        public SwipeHelper(Context context, RecyclerView recyclerView) {
            super(0, ItemTouchHelper.LEFT);
            this.recyclerView = recyclerView;
            this.buttons = new ArrayList<>();
            this.gestureDetector = new GestureDetector(context, gestureListener);
            this.recyclerView.setOnTouchListener(onTouchListener);
            buttonsBuffer = new HashMap<>();
            recoverQueue = new LinkedList<Integer>(){
                @Override
                public boolean add(Integer o) {
                    if (contains(o))
                        return false;
                    else
                        return super.add(o);
                }
            };

            attachSwipe();
        }

        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            int pos = viewHolder.getAdapterPosition();

            if (swipedPos != pos)
                recoverQueue.add(swipedPos);

            swipedPos = pos;

            if (buttonsBuffer.containsKey(swipedPos))
                buttons = buttonsBuffer.get(swipedPos);
            else
                buttons.clear();

            buttonsBuffer.clear();
            swipeThreshold = 0.5f * buttons.size() * BUTTON_WIDTH;
            recoverSwipedItem();
        }

        @Override
        public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) {
            return swipeThreshold;
        }

        @Override
        public float getSwipeEscapeVelocity(float defaultValue) {
            return 0.1f * defaultValue;
        }

        @Override
        public float getSwipeVelocityThreshold(float defaultValue) {
            return 5.0f * defaultValue;
        }

        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            int pos = viewHolder.getAdapterPosition();
            float translationX = dX;
            View itemView = viewHolder.itemView;

            if (pos < 0){
                swipedPos = pos;
                return;
            }

            if(actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
                if(dX < 0) {
                    List<UnderlayButton> buffer = new ArrayList<>();

                    if (!buttonsBuffer.containsKey(pos)){
                        instantiateUnderlayButton(viewHolder, buffer);
                        buttonsBuffer.put(pos, buffer);
                    }
                    else {
                        buffer = buttonsBuffer.get(pos);
                    }

                    translationX = dX * buffer.size() * BUTTON_WIDTH / itemView.getWidth();
                    drawButtons(c, itemView, buffer, pos, translationX);
                }
            }

            super.onChildDraw(c, recyclerView, viewHolder, translationX, dY, actionState, isCurrentlyActive);
        }

        private synchronized void recoverSwipedItem(){
            while (!recoverQueue.isEmpty()){
                int pos = recoverQueue.poll();
                if (pos > -1) {
                    recyclerView.getAdapter().notifyItemChanged(pos);
                }
            }
        }

        private void drawButtons(Canvas c, View itemView, List<UnderlayButton> buffer, int pos, float dX){
            float right = itemView.getRight();
            float dButtonWidth = (-1) * dX / buffer.size();

            for (UnderlayButton button : buffer) {
                float left = right - dButtonWidth;
                button.onDraw(
                        c,
                        new RectF(
                                left,
                                itemView.getTop(),
                                right,
                                itemView.getBottom()
                        ),
                        pos
                );

                right = left;
            }
        }

        public void attachSwipe(){
            ItemTouchHelper itemTouchHelper = new ItemTouchHelper(this);
            itemTouchHelper.attachToRecyclerView(recyclerView);
        }

        public abstract void instantiateUnderlayButton(RecyclerView.ViewHolder viewHolder, List<UnderlayButton> underlayButtons);

        public static class UnderlayButton {
            private String text;
            private int imageResId;
            private int color;
            private int pos;
            private RectF clickRegion;
            private UnderlayButtonClickListener clickListener;

            public UnderlayButton(String text, int imageResId, int color, UnderlayButtonClickListener clickListener) {
                this.text = text;
                this.imageResId = imageResId;
                this.color = color;
                this.clickListener = clickListener;
            }

            public boolean onClick(float x, float y){
                if (clickRegion != null && clickRegion.contains(x, y)){
                    clickListener.onClick(pos);
                    return true;
                }

                return false;
            }

            public void onDraw(Canvas c, RectF rect, int pos){
                Paint p = new Paint();

                // Draw background
                p.setColor(color);
                c.drawRect(rect, p);

                // Draw Text
                p.setColor(Color.WHITE);
                p.setTextSize(LayoutHelper.getPx(MyApplication.getAppContext(), 12));

                Rect r = new Rect();
                float cHeight = rect.height();
                float cWidth = rect.width();
                p.setTextAlign(Paint.Align.LEFT);
                p.getTextBounds(text, 0, text.length(), r);
                float x = cWidth / 2f - r.width() / 2f - r.left;
                float y = cHeight / 2f + r.height() / 2f - r.bottom;
                c.drawText(text, rect.left + x, rect.top + y, p);

                clickRegion = rect;
                this.pos = pos;
            }
        }

        public interface UnderlayButtonClickListener {
            void onClick(int pos);
        }
    }

Usage:----------------

SwipeHelper swipeHelper = new SwipeHelper(this, recyclerView) {
    @Override
    public void instantiateUnderlayButton(RecyclerView.ViewHolder viewHolder, List<UnderlayButton> underlayButtons) {
        underlayButtons.add(new SwipeHelper.UnderlayButton(
                "Delete",
                0,
                Color.parseColor("#FF3C30"),
                new SwipeHelper.UnderlayButtonClickListener() {
                    @Override
                    public void onClick(int pos) {
                        // TODO: onDelete
                    }
                }
        ));

        underlayButtons.add(new SwipeHelper.UnderlayButton(
                "Transfer",
                0,
                Color.parseColor("#FF9502"),
                new SwipeHelper.UnderlayButtonClickListener() {
                    @Override
                    public void onClick(int pos) {
                        // TODO: OnTransfer
                    }
                }
        ));
        underlayButtons.add(new SwipeHelper.UnderlayButton(
                "Unshare",
                0,
                Color.parseColor("#C7C7CB"),
                new SwipeHelper.UnderlayButtonClickListener() {
                    @Override
                    public void onClick(int pos) {
                        // TODO: OnUnshare
                    }
                }
        ));
    }
};
</code>```

Body:
Iam trying to edit and delete items in recyclerview.
When I swipe recyclerview I should get 2 buttons. One is for editing the data and the other buttonis for deleting the data from recyclerview.

public class Bills_Adapter extends RecyclerView.Adapter<Bills_Adapter.BillHolder> implements Filterable
{

    Context context;
    List<Manager_Bill_Model> bill_lists;

    public Bills_Adapter(Context context, List<Manager_Bill_Model> bill_lists)
    {
        this.context = context;
        this.bill_lists = bill_lists;
    }

    @Override
    public BillHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i)
    {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_bills, viewGroup, false);
        BillHolder billHolder = new BillHolder(v);
        return billHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull BillHolder billHolder, int i)
    {
        billHolder.tview_billNumber.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                final Dialog dialog = new Dialog(context);
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
                dialog.setContentView(R.layout.activity_bill_dialog);
                dialog.getWindow().setLayout(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
                dialog.show();

            }
        });

    }

    @Override
    public int getItemCount() {
        return 50;
    }

    @Override
    public Filter getFilter() {
        return null;
    }

    public class BillHolder extends RecyclerView.ViewHolder
    {
        TextView tview_billNumber;

        public BillHolder(@NonNull View itemView)
        {
            super(itemView);
            tview_billNumber = itemView.findViewById(R.id.tview_billNumber);
        }
    }
}


问:
How do I externally set a version for my jar without a parent pom that produces a usable pom.xml for dependencies
How do I externally define the version tag in pom.xml for a jar project, with no parent pom?

I've used properties-maven-plugin and flatten-maven-plugin to get real close. The resulting pom.xml that gets deployed has an unusable version because of the value substitutions being used by properties-maven-plugin to set version. flatten-maven-plugin resolves issues with dependency versions, but does not seem to resolve the version of the primary artifact. The code does appear to build and name the jar correctly.

I looked into https://maven.apache.org/maven-ci-friendly.html and learned about ${revision}, but the examples there seem to include parent poms.

I'm hoping someone has come across a solution without use of a parent pom. If there's no solution, I'd like to consider this a feature request for one of the plugins, but I'd like to try here first before I submit such a request.

This is the simplest configuration I can provide to demonstrate my issue.

pom.xml

```<code><project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>testgroup</groupId>
    <artifactId>test</artifactId>
    <version>${revision}</version>
    <packaging>jar</packaging>

    <name>test</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <lang>3.9</lang>
        <revision>${major}.${minor}</revision>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${lang}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>properties-maven-plugin</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <id>pre</id>
                        <phase>pre-clean</phase>
                        <goals>
                            <goal>read-project-properties</goal>
                        </goals>
                        <configuration>
                            <files>
                                <file>test.properties</file>
                            </files>
                        </configuration>
                    </execution>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>read-project-properties</goal>
                        </goals>
                        <configuration>
                            <files>
                                <file>test.properties</file>
                            </files>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>flatten-maven-plugin</artifactId>
                <version>1.1.0</version>
                <configuration>
                    <flattenMode>defaults</flattenMode>
                </configuration>
                <executions>
                    <execution>
                        <id>flatten</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>flatten</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>flatten.clean</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>clean</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
</code>```

test.properties

```<code>major=1
minor=2
</code>```

src/main/java/testgroup/test/App.java

```<code>package testgroup.test;

import org.apache.commons.lang3.StringUtils;

public class App
{
    public static void main( String[] args )
    {
        System.out.println(StringUtils.chop("boo"));

    }
}
</code>```

Resulting .flattened-pom.xml

```<code><?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>testgroup</groupId>
  <artifactId>test</artifactId>
  <version>${major}.${minor}</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
</code>```

I expect the version in .flattened-pom.xml to be 1.2, not ${major}.${minor}

So, I'm not sure if this is something I'm doing wrong, or some kind of bug in one of the plugins. For example, even Maven displays this weirdly:

```<code>C:\Users\Robert\eclipse-workspace\test>mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------------< testgroup:test >---------------------------
[INFO] Building test ${major}.${minor}
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- properties-maven-plugin:1.0.0:read-project-properties (pre) @ test ---

</code>```

< snip >

```<code>[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ test ---
[INFO] Building jar: C:\Users\Robert\eclipse-workspace\test\target\test-1.2.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
</code>```

答:
I don't know if you managed to find a way to resolve this, but from what I see, you are correctly setting the $revision property to the version element.

But do you run the tests? In order to build/test the application you need to run it like this:

```<code>mvn clean flatten:flatten test
</code>```

or

```<code>mvn clean flatten:flatten package
</code>```

What I find a bit off is that you are using $major and $minor without having them initialized in your pom.xml as properties and not using properties instead.

I understand that you would like to use the properties file which I assume you inject it somehow in your test environment. Instead you could use properties <major> and <minor> to initialize them and when you want to change them you can use

```<code>mvn clean -Dmajor=1 -Dminor=3 flatten:flatten test
</code>```

If you have found some other way to resolve this, please share it with the rest of us :)

Body:
How do I externally define the version tag in pom.xml for a jar project, with no parent pom?

I've used properties-maven-plugin and flatten-maven-plugin to get real close. The resulting pom.xml that gets deployed has an unusable version because of the value substitutions being used by properties-maven-plugin to set version. flatten-maven-plugin resolves issues with dependency versions, but does not seem to resolve the version of the primary artifact. The code does appear to build and name the jar correctly.

I looked into https://maven.apache.org/maven-ci-friendly.html and learned about ${revision}, but the examples there seem to include parent poms.

I'm hoping someone has come across a solution without use of a parent pom. If there's no solution, I'd like to consider this a feature request for one of the plugins, but I'd like to try here first before I submit such a request.

This is the simplest configuration I can provide to demonstrate my issue.

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>testgroup</groupId>
    <artifactId>test</artifactId>
    <version>${revision}</version>
    <packaging>jar</packaging>

    <name>test</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <lang>3.9</lang>
        <revision>${major}.${minor}</revision>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>${lang}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>properties-maven-plugin</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <id>pre</id>
                        <phase>pre-clean</phase>
                        <goals>
                            <goal>read-project-properties</goal>
                        </goals>
                        <configuration>
                            <files>
                                <file>test.properties</file>
                            </files>
                        </configuration>
                    </execution>
                    <execution>
                        <phase>initialize</phase>
                        <goals>
                            <goal>read-project-properties</goal>
                        </goals>
                        <configuration>
                            <files>
                                <file>test.properties</file>
                            </files>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>flatten-maven-plugin</artifactId>
                <version>1.1.0</version>
                <configuration>
                    <flattenMode>defaults</flattenMode>
                </configuration>
                <executions>
                    <execution>
                        <id>flatten</id>
                        <phase>process-resources</phase>
                        <goals>
                            <goal>flatten</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>flatten.clean</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>clean</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

test.properties

major=1
minor=2

src/main/java/testgroup/test/App.java

package testgroup.test;

import org.apache.commons.lang3.StringUtils;

public class App
{
    public static void main( String[] args )
    {
        System.out.println(StringUtils.chop("boo"));

    }
}

Resulting .flattened-pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>testgroup</groupId>
  <artifactId>test</artifactId>
  <version>${major}.${minor}</version>
  <dependencies>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>

I expect the version in .flattened-pom.xml to be 1.2, not ${major}.${minor}

So, I'm not sure if this is something I'm doing wrong, or some kind of bug in one of the plugins. For example, even Maven displays this weirdly:

C:\Users\Robert\eclipse-workspace\test>mvn clean package
[INFO] Scanning for projects...
[INFO]
[INFO] ---------------------------< testgroup:test >---------------------------
[INFO] Building test ${major}.${minor}
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] --- properties-maven-plugin:1.0.0:read-project-properties (pre) @ test ---

< snip >

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ test ---
[INFO] Building jar: C:\Users\Robert\eclipse-workspace\test\target\test-1.2.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Body:
I don't know if you managed to find a way to resolve this, but from what I see, you are correctly setting the $revision property to the version element.

But do you run the tests? In order to build/test the application you need to run it like this:

mvn clean flatten:flatten test

or

mvn clean flatten:flatten package

What I find a bit off is that you are using $major and $minor without having them initialized in your pom.xml as properties and not using properties instead.

I understand that you would like to use the properties file which I assume you inject it somehow in your test environment. Instead you could use properties <major> and <minor> to initialize them and when you want to change them you can use

mvn clean -Dmajor=1 -Dminor=3 flatten:flatten test

If you have found some other way to resolve this, please share it with the rest of us :)