问:
Force type parameter to be invariant at use-site when it is covariant at declaration site
I am building an extension function on KProperty1. The function needs to accept an argument that extends the value type of property (R), even though KProperty1 is covariant in the type parameter R.

A slightly contrived example would be the following, though my use is more legitimate.

```<code>data class Data(val value: String)

fun <V> KProperty1<*, V>.setMagically(value: V) {
    this.javaField?.set(null, value)
}

fun test() {
    // I would like this to fail to compile
    Data::value.setMagically(190)
}
</code>```

It would seem that the compiler is inferring the type Any for R, which is totally valid, since KProperty1<*, String> : KProperty1<*, Any>

What I want is to say that for my particular case, I actually want V to be invariant. I know you can use out and in as variance wideners, but I was unable to figure out how to specify that I want to override the covariant annotation on KProperty1 with invariance for this case.

It's worth noting that it works great with KMutableProperty1, since that's invariant in R. But my code needs to work with non-mutable properties as well.

For context, I'm building something that generates database queries, which is why I need the value to be a subclass of the property type, even though I'm not actually writing to the property, but this question is more general than my specific, property-handling case.

答:
This is currently not possible in Kotlin. In fact, there is an internal annotation which enables this behavior (causes the compiler to report an error, if Any is inferred although nowhere at the call site was it mentioned) and it's used in several places in kotlin-stdlib, but using it outside of the standard library is still discouraged.

We have plans to make this annotation public. For more details, please check out KT-13198.

Body:
I am building an extension function on KProperty1. The function needs to accept an argument that extends the value type of property (R), even though KProperty1 is covariant in the type parameter R.

A slightly contrived example would be the following, though my use is more legitimate.

data class Data(val value: String)

fun <V> KProperty1<*, V>.setMagically(value: V) {
    this.javaField?.set(null, value)
}

fun test() {
    // I would like this to fail to compile
    Data::value.setMagically(190)
}

It would seem that the compiler is inferring the type Any for R, which is totally valid, since KProperty1<*, String> : KProperty1<*, Any>

What I want is to say that for my particular case, I actually want V to be invariant. I know you can use out and in as variance wideners, but I was unable to figure out how to specify that I want to override the covariant annotation on KProperty1 with invariance for this case.

It's worth noting that it works great with KMutableProperty1, since that's invariant in R. But my code needs to work with non-mutable properties as well.

For context, I'm building something that generates database queries, which is why I need the value to be a subclass of the property type, even though I'm not actually writing to the property, but this question is more general than my specific, property-handling case.


来源: stackexchange

问:
In ASP.Net MVC 3, how do indicate that properties of child objects have error while writing a custom model validator?
I have the following Model:

```<code>public class Person
{
   public string Name {get;set;}
   public Address Address {get;set;}
}

public class Address
{
   public string Street {get;set;}
   public string City {get;set}
}
</code>```

I have now created a ModelValidator for which validates Person objects. The ModelValidator has one method to implement:

```<code>public abstract System.Collections.Generic.IEnumerable<ModelValidationResult>
Validate(object container)
</code>```

In this case how do I indicate that an error has occurred for the Address.Street property of the Person object. I have tried setting the ModelValidationResult.MemberName to Address.Street but this is not working?

How do I accomplish this?

答:
My bad, it does work.

In the above example, setting the Member property of the Model Validation Error to "Address.City" does highlight the city field.

Thanks

ContentLicense: CC BY-SA 2.5

Body:
I have the following Model:

public class Person
{
   public string Name {get;set;}
   public Address Address {get;set;}
}

public class Address
{
   public string Street {get;set;}
   public string City {get;set}
}

I have now created a ModelValidator for which validates Person objects. The ModelValidator has one method to implement:

public abstract System.Collections.Generic.IEnumerable<ModelValidationResult>
Validate(object container)

In this case how do I indicate that an error has occurred for the Address.Street property of the Person object. I have tried setting the ModelValidationResult.MemberName to Address.Street but this is not working?

How do I accomplish this?


问:
Separate files for each class in Typescript?
Update: Thank you very much for Daniel's reply below.  I've however found rollup.js to be answer for me. It can handle necessary circular dependencies between classes in projects well (webpack struggled with that), works straight on the ES6 module format and very easily outputs code both for node and browsers.

Hi (: What is good practice for Typescript coding when having large amounts of classes that might be used both in browser or in node?  Do you put multiple classes in single files and treat them as namespaces, or is there another way?

I'm a mainly C# using programmer looking into using Typescript for a new project.  I see that I can compile internal modules into a large .js file using references and --outFile, or use external modules with commonjs or amd.

Traditionally I've place each class in an individual file, and this feels natural in Typescript as well. However, let's say I have 200 classes in my project, this yields 200+ files to download when running in browser, which seems...  excessive.

答:
Yes, you would try to write small classes/modules with typescript with each in their own file.

But when you serve your app, you don't want the browser to load every file. So you need something to bundle your files and put them in one javascript file. Build tools help you with these (they also remove blank lines/unnecessary spacing and comments).

Popular build tools are

https://gruntjs.com/

https://github.com/webpack/webpack

When you come from a c# background, grunt might seem more familiar than webpack to you.

I use webpack.

ContentLicense: CC BY-SA 3.0


问:
How do I tell Spring Boot to ignore Jetty and always use Tomcat?
I have the following setup:

```<code>spring-boot application (using embedded tomcat)
spring-date-neo4j (embedded mode)
spring-websockets
</code>```

and neo4j-browser included using (the goal is to be able to use REST and web browser to debug embedded database):

```<code>    <dependency>
        <groupId>org.neo4j.app</groupId>
        <artifactId>neo4j-server</artifactId>
        <version>${neo4j.version}</version>
        <exclusions>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>javax.servlet</artifactId>
                <groupId>org.eclipse.jetty.orbit</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.neo4j.app</groupId>
        <artifactId>neo4j-server</artifactId>
        <version>${neo4j.version}</version>
        <classifier>static-web</classifier>
        <exclusions>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>javax.servlet</artifactId>
                <groupId>org.eclipse.jetty.orbit</groupId>
            </exclusion>
        </exclusions>
    </dependency>
</code>```

And started using:

```<code>@Autowired
@Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService(DatabaseConfiguration dbConf) {
    // removed with every maven clear
    return new GraphDatabaseFactory().newEmbeddedDatabase(dbConf.getDbPath());

    // stays after clear
    //return new EmbeddedGraphDatabase("./data/neo4j.db");
}

@Bean(destroyMethod = "stop")
public WrappingNeoServerBootstrapper serverWrapper(GraphDatabaseService db) {
    WrappingNeoServerBootstrapper wrapper = new WrappingNeoServerBootstrapper((GraphDatabaseAPI)db);
    wrapper.start();
    return wrapper;
}
</code>```

And spring boot is insisting on trying Jetty as the servlet container even with the following config annotations for the main app class:

```<code>@EnableAutoConfiguration(exclude = EmbeddedServletContainerAutoConfiguration.EmbeddedJetty.class)
@ComponentScan
@EnableWebMvc
@Configuration
public class WebApplication extends WebMvcConfigurerAdapter {
</code>```

But the jetty version Spring uses (8) does not support web sockets so I am getting

```<code>Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'jettyEmbeddedServletContainerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration$EmbeddedJetty.class]:
Initialization of bean failed; nested exception is java.lang.IllegalStateException:
Websockets are currently only supported in Tomcat (found class org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory).
</code>```

How do I tell Spring Boot to ignore Jetty and always use Tomcat?

The dependency tree:

```<code>[INFO] Building webapp 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ webapp ---
[INFO] webapp:war:1.0
[INFO] +- common:jar:1.0:compile
[INFO] |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  +- org.springframework.data:spring-data-neo4j:jar:3.1.0.RELEASE:compile
[INFO] |  |  +- org.aspectj:aspectjrt:jar:1.7.4:compile
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.8.0.RELEASE:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-dsl:jar:2.0.1:compile
[INFO] |  |  +- org.neo4j:neo4j:jar:2.0.3:compile
[INFO] |  |  +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] |  |  \- org.slf4j:jcl-over-slf4j:jar:1.7.7:compile
[INFO] |  +- commons-codec:commons-codec:jar:1.9:compile
[INFO] |  +- org.apache.poi:poi:jar:3.10-FINAL:compile
[INFO] |  +- org.apache.poi:poi-scratchpad:jar:3.10-FINAL:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.3.3:compile
[INFO] |  \- com.fasterxml.jackson.core:jackson-databind:jar:2.3.3:compile
[INFO] |     \- com.fasterxml.jackson.core:jackson-core:jar:2.3.3:compile
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.0.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.0.2.RELEASE:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.7:compile
[INFO] |  |  |  +- org.slf4j:log4j-over-slf4j:jar:1.7.7:compile
[INFO] |  |  |  \- ch.qos.logback:logback-classic:jar:1.1.2:compile
[INFO] |  |  |     \- ch.qos.logback:logback-core:jar:1.1.2:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.13:runtime
[INFO] |  \- org.springframework.boot:spring-boot-starter-tomcat:jar:1.0.2.RELEASE:compile
[INFO] |     +- org.apache.tomcat.embed:tomcat-embed-el:jar:7.0.52:compile
[INFO] |     \- org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:7.0.52:compile
[INFO] +- org.springframework:spring-core:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.springframework:spring-expression:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-web:jar:3.2.4.RELEASE:compile
[INFO] |  +- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  \- org.springframework.security:spring-security-core:jar:3.2.3.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-config:jar:3.2.4.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-taglibs:jar:3.2.4.RELEASE:compile
[INFO] |  \- org.springframework.security:spring-security-acl:jar:3.2.3.RELEASE:compile
[INFO] |     \- org.springframework:spring-jdbc:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-web:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-websocket:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-messaging:jar:4.0.3.RELEASE:compile
[INFO] +- org.apache.tomcat.embed:tomcat-embed-websocket:jar:7.0.52:compile
[INFO] |  \- org.apache.tomcat.embed:tomcat-embed-core:jar:7.0.52:compile
[INFO] +- org.freemarker:freemarker:jar:2.3.20:compile
[INFO] +- org.springframework:spring-context-support:jar:4.0.3.RELEASE:compile
[INFO] +- net.glxn:qrgen:jar:1.4:compile
[INFO] |  \- com.google.zxing:javase:jar:3.0.0:compile
[INFO] |     \- com.google.zxing:core:jar:3.0.0:compile
[INFO] +- org.springframework:spring-tx:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-aspects:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.aspectj:aspectjweaver:jar:1.7.4:compile
[INFO] +- org.hibernate:hibernate-validator:jar:5.1.1.Final:compile
[INFO] |  +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
[INFO] |  \- com.fasterxml:classmate:jar:1.0.0:compile
[INFO] +- javax.el:javax.el-api:jar:2.2.4:compile
[INFO] +- org.glassfish.web:javax.el:jar:2.2.4:compile
[INFO] +- org.apache.commons:commons-lang3:jar:3.3.2:compile
[INFO] +- commons-io:commons-io:jar:2.4:compile
[INFO] +- commons-fileupload:commons-fileupload:jar:1.3.1:compile
[INFO] +- org.jsoup:jsoup:jar:1.7.3:compile
[INFO] +- com.sun.jersey:jersey-server:jar:1.18:compile
[INFO] |  +- asm:asm:jar:3.1:compile
[INFO] |  \- com.sun.jersey:jersey-core:jar:1.18:compile
[INFO] +- com.sun.jersey:jersey-servlet:jar:1.18:compile
[INFO] +- org.neo4j.app:neo4j-server:jar:2.0.3:compile
[INFO] |  +- org.neo4j:neo4j:pom:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-lucene-index:jar:2.0.3:compile
[INFO] |  |  |  \- org.apache.lucene:lucene-core:jar:3.6.2:compile
[INFO] |  |  +- org.neo4j:neo4j-graph-algo:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-udc:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-graph-matching:jar:2.0.3:compile
[INFO] |  |  \- org.neo4j:neo4j-jmx:jar:2.0.3:compile
[INFO] |  +- org.neo4j:neo4j-kernel:jar:2.0.3:compile
[INFO] |  |  \- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1.1:compile
[INFO] |  +- org.neo4j:server-api:jar:2.0.3:compile
[INFO] |  |  \- org.neo4j.3rdparty.javax.ws.rs:jsr311-api:jar:1.1.2.r612:compile
[INFO] |  +- org.neo4j:neo4j-cypher:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-commons:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-compiler-1.9:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-compiler-2.0:jar:2.0.3:compile
[INFO] |  |  |  +- org.parboiled:parboiled-scala_2.10:jar:1.1.6:compile
[INFO] |  |  |  |  \- org.parboiled:parboiled-core:jar:1.1.6:compile
[INFO] |  |  |  \- net.sf.opencsv:opencsv:jar:2.0:compile
[INFO] |  |  +- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:jar:1.3.1:compile
[INFO] |  |  \- org.scala-lang:scala-library:jar:2.10.3:compile
[INFO] |  +- org.neo4j.app:neo4j-browser:jar:2.0.3:compile
[INFO] |  +- org.codehaus.janino:janino:jar:2.6.1:compile
[INFO] |  |  \- org.codehaus.janino:commons-compiler:jar:2.6.1:compile
[INFO] |  +- org.eclipse.jetty:jetty-server:jar:9.0.5.v20130815:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-http:jar:9.0.5.v20130815:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-io:jar:9.0.5.v20130815:compile
[INFO] |  +- org.eclipse.jetty:jetty-webapp:jar:8.1.14.v20131031:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-xml:jar:8.1.14.v20131031:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-servlet:jar:8.1.14.v20131031:compile
[INFO] |  |     \- org.eclipse.jetty:jetty-security:jar:8.1.14.v20131031:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.6:compile
[INFO] |  |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.4:compile
[INFO] |  |  +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] |  |  \- commons-beanutils:commons-beanutils-core:jar:1.8.0:compile
[INFO] |  +- commons-digester:commons-digester:jar:1.8.1:compile
[INFO] |  |  \- commons-beanutils:commons-beanutils:jar:1.8.0:compile
[INFO] |  +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.7:compile
[INFO] |  |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.7:compile
[INFO] |  |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.7:compile
[INFO] |  +- org.rrd4j:rrd4j:jar:2.0.7:compile
[INFO] |  +- org.mozilla:rhino:jar:1.7R4:compile
[INFO] |  +- bouncycastle:bcprov-jdk16:jar:140:compile
[INFO] |  +- com.sun.jersey.contribs:jersey-multipart:jar:1.9:compile
[INFO] |  |  \- org.jvnet:mimepull:jar:1.6:compile
[INFO] |  \- org.neo4j:neo4j-shell:jar:2.0.3:compile
[INFO] |     \- org.apache.servicemix.bundles:org.apache.servicemix.bundles.jline:jar:0.9.94_1:compile
[INFO] +- org.neo4j.app:neo4j-server:jar:static-web:2.0.3:compile
[INFO] +- org.eclipse.jetty:jetty-util:jar:9.0.7.v20131107:compile
[INFO] +- com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:jar:r239:compile
[INFO] |  +- com.google.guava:guava:jar:17.0:compile (version selected from constraint [11.0,))
[INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.0:compile (version selected from constraint [1.3.9,))
[INFO] +- junit:junit:jar:4.11:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- org.mockito:mockito-all:jar:1.9.5:test
[INFO] +- org.springframework:spring-test:jar:4.0.3.RELEASE:test
[INFO] +- org.mockito:mockito-core:jar:1.9.5:test
[INFO] |  \- org.objenesis:objenesis:jar:1.0:test
[INFO] \- org.hamcrest:hamcrest-library:jar:1.3:test
</code>```

答:
You could also import the EmbeddedTomcat configuration directly. Has the same effect as declaring TomcatEmbeddedServletContainerFactory directly and should there be any change with it you won't need to update anything.

```<code>@SpringBootApplication
@Import(EmbeddedServletContainerAutoConfiguration.EmbeddedTomcat.class)
... your configuration class
</code>```

Body:
I have the following setup:

spring-boot application (using embedded tomcat)
spring-date-neo4j (embedded mode)
spring-websockets

and neo4j-browser included using (the goal is to be able to use REST and web browser to debug embedded database):

    <dependency>
        <groupId>org.neo4j.app</groupId>
        <artifactId>neo4j-server</artifactId>
        <version>${neo4j.version}</version>
        <exclusions>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>javax.servlet</artifactId>
                <groupId>org.eclipse.jetty.orbit</groupId>
            </exclusion>
        </exclusions>
    </dependency>

    <dependency>
        <groupId>org.neo4j.app</groupId>
        <artifactId>neo4j-server</artifactId>
        <version>${neo4j.version}</version>
        <classifier>static-web</classifier>
        <exclusions>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </exclusion>
            <exclusion>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-access</artifactId>
            </exclusion>
            <exclusion>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
            </exclusion>
            <exclusion>
                <artifactId>javax.servlet</artifactId>
                <groupId>org.eclipse.jetty.orbit</groupId>
            </exclusion>
        </exclusions>
    </dependency>

And started using:

@Autowired
@Bean(destroyMethod = "shutdown")
public GraphDatabaseService graphDatabaseService(DatabaseConfiguration dbConf) {
    // removed with every maven clear
    return new GraphDatabaseFactory().newEmbeddedDatabase(dbConf.getDbPath());

    // stays after clear
    //return new EmbeddedGraphDatabase("./data/neo4j.db");
}

@Bean(destroyMethod = "stop")
public WrappingNeoServerBootstrapper serverWrapper(GraphDatabaseService db) {
    WrappingNeoServerBootstrapper wrapper = new WrappingNeoServerBootstrapper((GraphDatabaseAPI)db);
    wrapper.start();
    return wrapper;
}

And spring boot is insisting on trying Jetty as the servlet container even with the following config annotations for the main app class:

@EnableAutoConfiguration(exclude = EmbeddedServletContainerAutoConfiguration.EmbeddedJetty.class)
@ComponentScan
@EnableWebMvc
@Configuration
public class WebApplication extends WebMvcConfigurerAdapter {

But the jetty version Spring uses (8) does not support web sockets so I am getting

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'jettyEmbeddedServletContainerFactory' defined in class path resource
[org/springframework/boot/autoconfigure/web/EmbeddedServletContainerAutoConfiguration$EmbeddedJetty.class]:
Initialization of bean failed; nested exception is java.lang.IllegalStateException:
Websockets are currently only supported in Tomcat (found class org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory).

How do I tell Spring Boot to ignore Jetty and always use Tomcat?

The dependency tree:

[INFO] Building webapp 1.0
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ webapp ---
[INFO] webapp:war:1.0
[INFO] +- common:jar:1.0:compile
[INFO] |  +- javax.validation:validation-api:jar:1.1.0.Final:compile
[INFO] |  +- org.springframework.data:spring-data-neo4j:jar:3.1.0.RELEASE:compile
[INFO] |  |  +- org.aspectj:aspectjrt:jar:1.7.4:compile
[INFO] |  |  +- org.springframework.data:spring-data-commons:jar:1.8.0.RELEASE:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-dsl:jar:2.0.1:compile
[INFO] |  |  +- org.neo4j:neo4j:jar:2.0.3:compile
[INFO] |  |  +- org.slf4j:slf4j-api:jar:1.7.7:compile
[INFO] |  |  \- org.slf4j:jcl-over-slf4j:jar:1.7.7:compile
[INFO] |  +- commons-codec:commons-codec:jar:1.9:compile
[INFO] |  +- org.apache.poi:poi:jar:3.10-FINAL:compile
[INFO] |  +- org.apache.poi:poi-scratchpad:jar:3.10-FINAL:compile
[INFO] |  +- com.fasterxml.jackson.core:jackson-annotations:jar:2.3.3:compile
[INFO] |  \- com.fasterxml.jackson.core:jackson-databind:jar:2.3.3:compile
[INFO] |     \- com.fasterxml.jackson.core:jackson-core:jar:2.3.3:compile
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:1.0.2.RELEASE:compile
[INFO] |  +- org.springframework.boot:spring-boot-starter:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-autoconfigure:jar:1.0.2.RELEASE:compile
[INFO] |  |  +- org.springframework.boot:spring-boot-starter-logging:jar:1.0.2.RELEASE:compile
[INFO] |  |  |  +- org.slf4j:jul-to-slf4j:jar:1.7.7:compile
[INFO] |  |  |  +- org.slf4j:log4j-over-slf4j:jar:1.7.7:compile
[INFO] |  |  |  \- ch.qos.logback:logback-classic:jar:1.1.2:compile
[INFO] |  |  |     \- ch.qos.logback:logback-core:jar:1.1.2:compile
[INFO] |  |  \- org.yaml:snakeyaml:jar:1.13:runtime
[INFO] |  \- org.springframework.boot:spring-boot-starter-tomcat:jar:1.0.2.RELEASE:compile
[INFO] |     +- org.apache.tomcat.embed:tomcat-embed-el:jar:7.0.52:compile
[INFO] |     \- org.apache.tomcat.embed:tomcat-embed-logging-juli:jar:7.0.52:compile
[INFO] +- org.springframework:spring-core:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-context:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.springframework:spring-expression:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-web:jar:3.2.4.RELEASE:compile
[INFO] |  +- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  \- org.springframework.security:spring-security-core:jar:3.2.3.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-config:jar:3.2.4.RELEASE:compile
[INFO] +- org.springframework.security:spring-security-taglibs:jar:3.2.4.RELEASE:compile
[INFO] |  \- org.springframework.security:spring-security-acl:jar:3.2.3.RELEASE:compile
[INFO] |     \- org.springframework:spring-jdbc:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-webmvc:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-web:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-websocket:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-messaging:jar:4.0.3.RELEASE:compile
[INFO] +- org.apache.tomcat.embed:tomcat-embed-websocket:jar:7.0.52:compile
[INFO] |  \- org.apache.tomcat.embed:tomcat-embed-core:jar:7.0.52:compile
[INFO] +- org.freemarker:freemarker:jar:2.3.20:compile
[INFO] +- org.springframework:spring-context-support:jar:4.0.3.RELEASE:compile
[INFO] +- net.glxn:qrgen:jar:1.4:compile
[INFO] |  \- com.google.zxing:javase:jar:3.0.0:compile
[INFO] |     \- com.google.zxing:core:jar:3.0.0:compile
[INFO] +- org.springframework:spring-tx:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-aop:jar:4.0.3.RELEASE:compile
[INFO] +- org.springframework:spring-aspects:jar:4.0.3.RELEASE:compile
[INFO] |  \- org.aspectj:aspectjweaver:jar:1.7.4:compile
[INFO] +- org.hibernate:hibernate-validator:jar:5.1.1.Final:compile
[INFO] |  +- org.jboss.logging:jboss-logging:jar:3.1.3.GA:compile
[INFO] |  \- com.fasterxml:classmate:jar:1.0.0:compile
[INFO] +- javax.el:javax.el-api:jar:2.2.4:compile
[INFO] +- org.glassfish.web:javax.el:jar:2.2.4:compile
[INFO] +- org.apache.commons:commons-lang3:jar:3.3.2:compile
[INFO] +- commons-io:commons-io:jar:2.4:compile
[INFO] +- commons-fileupload:commons-fileupload:jar:1.3.1:compile
[INFO] +- org.jsoup:jsoup:jar:1.7.3:compile
[INFO] +- com.sun.jersey:jersey-server:jar:1.18:compile
[INFO] |  +- asm:asm:jar:3.1:compile
[INFO] |  \- com.sun.jersey:jersey-core:jar:1.18:compile
[INFO] +- com.sun.jersey:jersey-servlet:jar:1.18:compile
[INFO] +- org.neo4j.app:neo4j-server:jar:2.0.3:compile
[INFO] |  +- org.neo4j:neo4j:pom:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-lucene-index:jar:2.0.3:compile
[INFO] |  |  |  \- org.apache.lucene:lucene-core:jar:3.6.2:compile
[INFO] |  |  +- org.neo4j:neo4j-graph-algo:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-udc:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-graph-matching:jar:2.0.3:compile
[INFO] |  |  \- org.neo4j:neo4j-jmx:jar:2.0.3:compile
[INFO] |  +- org.neo4j:neo4j-kernel:jar:2.0.3:compile
[INFO] |  |  \- org.apache.geronimo.specs:geronimo-jta_1.1_spec:jar:1.1.1:compile
[INFO] |  +- org.neo4j:server-api:jar:2.0.3:compile
[INFO] |  |  \- org.neo4j.3rdparty.javax.ws.rs:jsr311-api:jar:1.1.2.r612:compile
[INFO] |  +- org.neo4j:neo4j-cypher:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-commons:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-compiler-1.9:jar:2.0.3:compile
[INFO] |  |  +- org.neo4j:neo4j-cypher-compiler-2.0:jar:2.0.3:compile
[INFO] |  |  |  +- org.parboiled:parboiled-scala_2.10:jar:1.1.6:compile
[INFO] |  |  |  |  \- org.parboiled:parboiled-core:jar:1.1.6:compile
[INFO] |  |  |  \- net.sf.opencsv:opencsv:jar:2.0:compile
[INFO] |  |  +- com.googlecode.concurrentlinkedhashmap:concurrentlinkedhashmap-lru:jar:1.3.1:compile
[INFO] |  |  \- org.scala-lang:scala-library:jar:2.10.3:compile
[INFO] |  +- org.neo4j.app:neo4j-browser:jar:2.0.3:compile
[INFO] |  +- org.codehaus.janino:janino:jar:2.6.1:compile
[INFO] |  |  \- org.codehaus.janino:commons-compiler:jar:2.6.1:compile
[INFO] |  +- org.eclipse.jetty:jetty-server:jar:9.0.5.v20130815:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-http:jar:9.0.5.v20130815:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-io:jar:9.0.5.v20130815:compile
[INFO] |  +- org.eclipse.jetty:jetty-webapp:jar:8.1.14.v20131031:compile
[INFO] |  |  +- org.eclipse.jetty:jetty-xml:jar:8.1.14.v20131031:compile
[INFO] |  |  \- org.eclipse.jetty:jetty-servlet:jar:8.1.14.v20131031:compile
[INFO] |  |     \- org.eclipse.jetty:jetty-security:jar:8.1.14.v20131031:compile
[INFO] |  +- commons-configuration:commons-configuration:jar:1.6:compile
[INFO] |  |  +- commons-collections:commons-collections:jar:3.2.1:compile
[INFO] |  |  +- commons-lang:commons-lang:jar:2.4:compile
[INFO] |  |  +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] |  |  \- commons-beanutils:commons-beanutils-core:jar:1.8.0:compile
[INFO] |  +- commons-digester:commons-digester:jar:1.8.1:compile
[INFO] |  |  \- commons-beanutils:commons-beanutils:jar:1.8.0:compile
[INFO] |  +- org.codehaus.jackson:jackson-jaxrs:jar:1.9.7:compile
[INFO] |  |  +- org.codehaus.jackson:jackson-core-asl:jar:1.9.7:compile
[INFO] |  |  \- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.7:compile
[INFO] |  +- org.rrd4j:rrd4j:jar:2.0.7:compile
[INFO] |  +- org.mozilla:rhino:jar:1.7R4:compile
[INFO] |  +- bouncycastle:bcprov-jdk16:jar:140:compile
[INFO] |  +- com.sun.jersey.contribs:jersey-multipart:jar:1.9:compile
[INFO] |  |  \- org.jvnet:mimepull:jar:1.6:compile
[INFO] |  \- org.neo4j:neo4j-shell:jar:2.0.3:compile
[INFO] |     \- org.apache.servicemix.bundles:org.apache.servicemix.bundles.jline:jar:0.9.94_1:compile
[INFO] +- org.neo4j.app:neo4j-server:jar:static-web:2.0.3:compile
[INFO] +- org.eclipse.jetty:jetty-util:jar:9.0.7.v20131107:compile
[INFO] +- com.googlecode.owasp-java-html-sanitizer:owasp-java-html-sanitizer:jar:r239:compile
[INFO] |  +- com.google.guava:guava:jar:17.0:compile (version selected from constraint [11.0,))
[INFO] |  \- com.google.code.findbugs:jsr305:jar:3.0.0:compile (version selected from constraint [1.3.9,))
[INFO] +- junit:junit:jar:4.11:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.3:test
[INFO] +- org.mockito:mockito-all:jar:1.9.5:test
[INFO] +- org.springframework:spring-test:jar:4.0.3.RELEASE:test
[INFO] +- org.mockito:mockito-core:jar:1.9.5:test
[INFO] |  \- org.objenesis:objenesis:jar:1.0:test
[INFO] \- org.hamcrest:hamcrest-library:jar:1.3:test

Body:
You could also import the EmbeddedTomcat configuration directly. Has the same effect as declaring TomcatEmbeddedServletContainerFactory directly and should there be any change with it you won't need to update anything.

@SpringBootApplication
@Import(EmbeddedServletContainerAutoConfiguration.EmbeddedTomcat.class)
... your configuration class


问:
Python Soccer Betting Model, How To Only Use 6 Latest Matches?
Need some help to this Python Soccer betting model.
I have this working script as shown below.
Now the problem with this is that variable 'matchrating' should only be based on the 6 latest matches so it represents form.
It's now off because at the end of the season the matchrating becomes very unrealistic as it uses all the matches played.

Can someone help me out?

The N1.csv used is from http://www.football-data.co.uk/mmz4281/1617/N1.csv

```<code>import csv, math, ast, numpy as np

csvFile = 'N1.csv'

team_list = []

k = open ('team_list.txt', 'w')
k.write("""{
""")

csvRead = csv.reader(open(csvFile))
next(csvRead)

for row in csvRead:
    if row[2] not in team_list:
        team_list.append(row[2])
    if row[3] not in team_list:
        team_list.append(row[3])

team_list.sort()

for team in team_list:
    k.write(""" '%s': {'goals_for': 0, 'goals_against': 0, 'teamrating': 0},
""" % (team))

k.write("}")
k.close()

s = open('team_list.txt', 'r').read()
dict = ast.literal_eval(s)

GAMES_PLAYED = 0
WEEKS_WAIT = 4
TOTAL_VALUE = 0

starting_bankroll = 100
stake = 5
bankroll = starting_bankroll

matchrating_low = -3
matchrating_high = 3

bets = 0

csvRead = csv.reader(open(csvFile))
next(csvRead)

for game in csvRead:
    home_team = game[2]
    away_team = game[3]

    goals_for = int(game[4])
    goals_against = int(game[5])

    home_win_prob = 0
    draw_win_prob = 0
    away_win_prob = 0

    matchrating = 0

    team_bet = ''
    ev_bet = ''

    if (GAMES_PLAYED > (WEEKS_WAIT * 9)):
        home_teamrating = (dict[home_team]['goals_for'] - dict[home_team]['goals_against'])
        away_teamrating = (dict[away_team]['goals_for'] - dict[away_team]['goals_against'])
        matchrating = home_teamrating - away_teamrating

        home_win_prob = ((1.76 * matchrating) + 49.47) / 100
        draw_win_prob = (((-0.03 * (matchrating ** 2)) - (0.49 * matchrating)) + 21.48) / 100
        away_win_prob = (((0.03 * (matchrating ** 2)) - (1.47 * matchrating)) + 29.65) / 100

        home_odd = float(game[33])
        draw_odd = float(game[35])
        away_odd = float(game[37])

        implied_prob_home = 1 / home_odd
        implied_prob_draw = 1 / draw_odd
        implied_prob_away = 1 / away_odd

        home_ev = (((stake * home_odd) - stake) * home_win_prob) - (stake * (draw_win_prob + away_win_prob))
        draw_ev = (((stake * draw_odd) - stake) * draw_win_prob) - (stake * (home_win_prob + away_win_prob))
        away_ev = (((stake * away_odd) - stake) * away_win_prob) - (stake * (home_win_prob + draw_win_prob))

        highest_ev = max(home_ev, draw_ev, away_ev)

        if (home_ev == highest_ev) and (home_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = home_team
            ev_bet = home_ev
            bets = bets + 1
            if goals_for > goals_against:
                bankroll += stake * (home_odd - 1)
            else:
                bankroll -= stake

        elif (draw_ev == highest_ev) and (draw_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = 'Draw'
            ev_bet = draw_ev
            bets = bets + 1
            if goals_for == goals_against:
                bankroll += stake * (draw_odd - 1)
            else:
                bankroll -= stake

        elif (away_ev == highest_ev) and (away_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = away_team
            ev_bet = away_ev
            bets = bets + 1
            if goals_for < goals_against:
                bankroll += stake * (away_odd - 1)
            else:
                bankroll -= stake

        print ("%s(%s) - %s(%s) = %s" % (home_team, home_teamrating, away_team, away_teamrating, matchrating))
        print ("Prob: %s | %s | %s" % (home_win_prob, draw_win_prob, away_win_prob))
        print ("Impl. Prob: %s | %s | %s" % (implied_prob_home, implied_prob_draw, implied_prob_away))
        print ("Odd: %s | %s | %s" % (home_odd, draw_odd, away_odd))
        print ("EV: %s | %s | %s >> %s" % (home_ev, draw_ev, away_ev, highest_ev))
        print ("Bankroll: %s" % (bankroll))
        print ("Games played: %s | Bets placed: %s" % (GAMES_PLAYED, bets))

    dict[home_team]['goals_for'] += goals_for
    dict[home_team]['goals_against'] += goals_against

    dict[away_team]['goals_for'] += goals_for
    dict[away_team]['goals_against'] += goals_for

    GAMES_PLAYED += 1
</code>```

答:
You could load the full csv file into a list in one step, which would make your code easier to follow in the first instance.

Then simply:

```<code>games = games_list[-6:]
</code>```

will give you a shorter list with only the last 6 games, for onward processing.

EDIT:

After looking again I can see that the problem is more involved than I initially thought.

The Solution is to compile a List of the goals for and against each team as each game is processed.  Then the Rating can be calculated by slicing the last 6 Ratings from the list.

In keeping with my other comments, I've reworked your code a bit:

```<code>import csv

def read_csv(filename):
    _csv_data = []

    with open(filename, 'r') as f:
        csv_reader = csv.reader(f)
        headers = next(csv_reader)
        for read_line in csv_reader:
            line_dict = {header:val for header, val in zip(headers, read_line)}
            _csv_data.append(line_dict)
    return _csv_data

def find_unique_teams(datafile):
    _team_list = []
    for record in datafile:
        if record['HomeTeam'] not in _team_list:
            _team_list.append(record['HomeTeam'])
        if record['AwayTeam'] not in _team_list:
            _team_list.append(record['AwayTeam'])
    _team_list.sort()
    return _team_list

csvFile = 'N1.csv'

#process CSV file
game_data = read_csv(csvFile)
#Extract Team list
team_list = find_unique_teams(game_data)
#Generate Form dictionary
form_dict = {team_name : {'goals_for': [], 'goals_against': []} for team_name in team_list}

GAMES_PLAYED = 0
WEEKS_WAIT = 4
TOTAL_VALUE = 0

starting_bankroll = 100
stake = 5
bankroll = starting_bankroll

matchrating_low = -3
matchrating_high = 3

bets = 0

for game in game_data:
    home_team = game['HomeTeam']
    away_team = game['AwayTeam']

    goals_for = int(game['FTHG'])
    goals_against = int(game['FTAG'])

    home_win_prob = 0
    draw_win_prob = 0
    away_win_prob = 0

    matchrating = 0

    team_bet = ''
    ev_bet = ''

    if (GAMES_PLAYED > (WEEKS_WAIT * 9)):
        home_teamrating = (sum(form_dict[home_team]['goals_for'][-6:]) - sum(form_dict[home_team]['goals_against'][-6:]))
        away_teamrating = (sum(form_dict[away_team]['goals_for'][-6:]) - sum(form_dict[away_team]['goals_against'][-6:]))
        matchrating = home_teamrating - away_teamrating

        home_win_prob = ((1.76 * matchrating) + 49.47) / 100
        draw_win_prob = (((-0.03 * (matchrating ** 2)) - (0.49 * matchrating)) + 21.48) / 100
        away_win_prob = (((0.03 * (matchrating ** 2)) - (1.47 * matchrating)) + 29.65) / 100

        home_odd = float(game['BbAvH'])
        draw_odd = float(game['BbAvD'])
        away_odd = float(game['BbAvA'])

        implied_prob_home = 1 / home_odd
        implied_prob_draw = 1 / draw_odd
        implied_prob_away = 1 / away_odd

        home_ev = (((stake * home_odd) - stake) * home_win_prob) - (stake * (draw_win_prob + away_win_prob))
        draw_ev = (((stake * draw_odd) - stake) * draw_win_prob) - (stake * (home_win_prob + away_win_prob))
        away_ev = (((stake * away_odd) - stake) * away_win_prob) - (stake * (home_win_prob + draw_win_prob))

        highest_ev = max(home_ev, draw_ev, away_ev)

        if (home_ev == highest_ev) and (home_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = home_team
            ev_bet = home_ev
            bets = bets + 1
            if goals_for > goals_against:
                bankroll += stake * (home_odd - 1)
            else:
                bankroll -= stake

        elif (draw_ev == highest_ev) and (draw_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = 'Draw'
            ev_bet = draw_ev
            bets = bets + 1
            if goals_for == goals_against:
                bankroll += stake * (draw_odd - 1)
            else:
                bankroll -= stake

        elif (away_ev == highest_ev) and (away_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = away_team
            ev_bet = away_ev
            bets = bets + 1
            if goals_for < goals_against:
                bankroll += stake * (away_odd - 1)
            else:
                bankroll -= stake

        print("{0:16s}({1:3d}) Vs {2:16s}({3:3d}) = {4:3d}".format(home_team, home_teamrating, away_team, away_teamrating, matchrating))
        print("Prob        : {0:8.4f} | {1:8.4f} | {2:8.4f}".format(home_win_prob, draw_win_prob, away_win_prob))
        print("Impl. Prob  : {0:8.4f} | {0:8.4f} | {0:8.4f}".format(implied_prob_home, implied_prob_draw, implied_prob_away))
        print("Odd         : {0:8.2f} | {1:8.2f} | {2:8.2f}".format(home_odd, draw_odd, away_odd))
        print("EV          : {0:8.4f} | {1:8.4f} | {2:8.4f} >> {3:8.4f}".format(home_ev, draw_ev, away_ev, highest_ev))
        print("Bankroll    : {0:6.2f}".format(bankroll))
        print("Games played: {0:8d} | Bets placed: {1:3d}".format(GAMES_PLAYED, bets))
        print()

    form_dict[home_team]['goals_for'].append(goals_for)
    form_dict[home_team]['goals_against'].append(goals_against)

    form_dict[away_team]['goals_for'].append(goals_for)
    form_dict[away_team]['goals_against'].append(goals_for)

    GAMES_PLAYED += 1
</code>```

I've not checked the results, so hopefully it works.  Sorry if I've taken a liberty, I got carried away!

Body:
Need some help to this Python Soccer betting model.
I have this working script as shown below.
Now the problem with this is that variable 'matchrating' should only be based on the 6 latest matches so it represents form.
It's now off because at the end of the season the matchrating becomes very unrealistic as it uses all the matches played.

Can someone help me out?

The N1.csv used is from http://www.football-data.co.uk/mmz4281/1617/N1.csv

import csv, math, ast, numpy as np

csvFile = 'N1.csv'

team_list = []

k = open ('team_list.txt', 'w')
k.write("""{
""")

csvRead = csv.reader(open(csvFile))
next(csvRead)

for row in csvRead:
    if row[2] not in team_list:
        team_list.append(row[2])
    if row[3] not in team_list:
        team_list.append(row[3])

team_list.sort()

for team in team_list:
    k.write(""" '%s': {'goals_for': 0, 'goals_against': 0, 'teamrating': 0},
""" % (team))

k.write("}")
k.close()

s = open('team_list.txt', 'r').read()
dict = ast.literal_eval(s)

GAMES_PLAYED = 0
WEEKS_WAIT = 4
TOTAL_VALUE = 0

starting_bankroll = 100
stake = 5
bankroll = starting_bankroll

matchrating_low = -3
matchrating_high = 3

bets = 0

csvRead = csv.reader(open(csvFile))
next(csvRead)

for game in csvRead:
    home_team = game[2]
    away_team = game[3]

    goals_for = int(game[4])
    goals_against = int(game[5])

    home_win_prob = 0
    draw_win_prob = 0
    away_win_prob = 0

    matchrating = 0

    team_bet = ''
    ev_bet = ''

    if (GAMES_PLAYED > (WEEKS_WAIT * 9)):
        home_teamrating = (dict[home_team]['goals_for'] - dict[home_team]['goals_against'])
        away_teamrating = (dict[away_team]['goals_for'] - dict[away_team]['goals_against'])
        matchrating = home_teamrating - away_teamrating

        home_win_prob = ((1.76 * matchrating) + 49.47) / 100
        draw_win_prob = (((-0.03 * (matchrating ** 2)) - (0.49 * matchrating)) + 21.48) / 100
        away_win_prob = (((0.03 * (matchrating ** 2)) - (1.47 * matchrating)) + 29.65) / 100

        home_odd = float(game[33])
        draw_odd = float(game[35])
        away_odd = float(game[37])

        implied_prob_home = 1 / home_odd
        implied_prob_draw = 1 / draw_odd
        implied_prob_away = 1 / away_odd

        home_ev = (((stake * home_odd) - stake) * home_win_prob) - (stake * (draw_win_prob + away_win_prob))
        draw_ev = (((stake * draw_odd) - stake) * draw_win_prob) - (stake * (home_win_prob + away_win_prob))
        away_ev = (((stake * away_odd) - stake) * away_win_prob) - (stake * (home_win_prob + draw_win_prob))

        highest_ev = max(home_ev, draw_ev, away_ev)

        if (home_ev == highest_ev) and (home_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = home_team
            ev_bet = home_ev
            bets = bets + 1
            if goals_for > goals_against:
                bankroll += stake * (home_odd - 1)
            else:
                bankroll -= stake

        elif (draw_ev == highest_ev) and (draw_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = 'Draw'
            ev_bet = draw_ev
            bets = bets + 1
            if goals_for == goals_against:
                bankroll += stake * (draw_odd - 1)
            else:
                bankroll -= stake

        elif (away_ev == highest_ev) and (away_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = away_team
            ev_bet = away_ev
            bets = bets + 1
            if goals_for < goals_against:
                bankroll += stake * (away_odd - 1)
            else:
                bankroll -= stake

        print ("%s(%s) - %s(%s) = %s" % (home_team, home_teamrating, away_team, away_teamrating, matchrating))
        print ("Prob: %s | %s | %s" % (home_win_prob, draw_win_prob, away_win_prob))
        print ("Impl. Prob: %s | %s | %s" % (implied_prob_home, implied_prob_draw, implied_prob_away))
        print ("Odd: %s | %s | %s" % (home_odd, draw_odd, away_odd))
        print ("EV: %s | %s | %s >> %s" % (home_ev, draw_ev, away_ev, highest_ev))
        print ("Bankroll: %s" % (bankroll))
        print ("Games played: %s | Bets placed: %s" % (GAMES_PLAYED, bets))

    dict[home_team]['goals_for'] += goals_for
    dict[home_team]['goals_against'] += goals_against

    dict[away_team]['goals_for'] += goals_for
    dict[away_team]['goals_against'] += goals_for

    GAMES_PLAYED += 1

Body:
You could load the full csv file into a list in one step, which would make your code easier to follow in the first instance.

Then simply:

games = games_list[-6:]

will give you a shorter list with only the last 6 games, for onward processing.

EDIT:

After looking again I can see that the problem is more involved than I initially thought.

The Solution is to compile a List of the goals for and against each team as each game is processed.  Then the Rating can be calculated by slicing the last 6 Ratings from the list.

In keeping with my other comments, I've reworked your code a bit:

import csv

def read_csv(filename):
    _csv_data = []

    with open(filename, 'r') as f:
        csv_reader = csv.reader(f)
        headers = next(csv_reader)
        for read_line in csv_reader:
            line_dict = {header:val for header, val in zip(headers, read_line)}
            _csv_data.append(line_dict)
    return _csv_data

def find_unique_teams(datafile):
    _team_list = []
    for record in datafile:
        if record['HomeTeam'] not in _team_list:
            _team_list.append(record['HomeTeam'])
        if record['AwayTeam'] not in _team_list:
            _team_list.append(record['AwayTeam'])
    _team_list.sort()
    return _team_list

csvFile = 'N1.csv'

#process CSV file
game_data = read_csv(csvFile)
#Extract Team list
team_list = find_unique_teams(game_data)
#Generate Form dictionary
form_dict = {team_name : {'goals_for': [], 'goals_against': []} for team_name in team_list}

GAMES_PLAYED = 0
WEEKS_WAIT = 4
TOTAL_VALUE = 0

starting_bankroll = 100
stake = 5
bankroll = starting_bankroll

matchrating_low = -3
matchrating_high = 3

bets = 0

for game in game_data:
    home_team = game['HomeTeam']
    away_team = game['AwayTeam']

    goals_for = int(game['FTHG'])
    goals_against = int(game['FTAG'])

    home_win_prob = 0
    draw_win_prob = 0
    away_win_prob = 0

    matchrating = 0

    team_bet = ''
    ev_bet = ''

    if (GAMES_PLAYED > (WEEKS_WAIT * 9)):
        home_teamrating = (sum(form_dict[home_team]['goals_for'][-6:]) - sum(form_dict[home_team]['goals_against'][-6:]))
        away_teamrating = (sum(form_dict[away_team]['goals_for'][-6:]) - sum(form_dict[away_team]['goals_against'][-6:]))
        matchrating = home_teamrating - away_teamrating

        home_win_prob = ((1.76 * matchrating) + 49.47) / 100
        draw_win_prob = (((-0.03 * (matchrating ** 2)) - (0.49 * matchrating)) + 21.48) / 100
        away_win_prob = (((0.03 * (matchrating ** 2)) - (1.47 * matchrating)) + 29.65) / 100

        home_odd = float(game['BbAvH'])
        draw_odd = float(game['BbAvD'])
        away_odd = float(game['BbAvA'])

        implied_prob_home = 1 / home_odd
        implied_prob_draw = 1 / draw_odd
        implied_prob_away = 1 / away_odd

        home_ev = (((stake * home_odd) - stake) * home_win_prob) - (stake * (draw_win_prob + away_win_prob))
        draw_ev = (((stake * draw_odd) - stake) * draw_win_prob) - (stake * (home_win_prob + away_win_prob))
        away_ev = (((stake * away_odd) - stake) * away_win_prob) - (stake * (home_win_prob + draw_win_prob))

        highest_ev = max(home_ev, draw_ev, away_ev)

        if (home_ev == highest_ev) and (home_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = home_team
            ev_bet = home_ev
            bets = bets + 1
            if goals_for > goals_against:
                bankroll += stake * (home_odd - 1)
            else:
                bankroll -= stake

        elif (draw_ev == highest_ev) and (draw_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = 'Draw'
            ev_bet = draw_ev
            bets = bets + 1
            if goals_for == goals_against:
                bankroll += stake * (draw_odd - 1)
            else:
                bankroll -= stake

        elif (away_ev == highest_ev) and (away_ev > 0) and (matchrating > matchrating_low) and (matchrating < matchrating_high):
            team_bet = away_team
            ev_bet = away_ev
            bets = bets + 1
            if goals_for < goals_against:
                bankroll += stake * (away_odd - 1)
            else:
                bankroll -= stake

        print("{0:16s}({1:3d}) Vs {2:16s}({3:3d}) = {4:3d}".format(home_team, home_teamrating, away_team, away_teamrating, matchrating))
        print("Prob        : {0:8.4f} | {1:8.4f} | {2:8.4f}".format(home_win_prob, draw_win_prob, away_win_prob))
        print("Impl. Prob  : {0:8.4f} | {0:8.4f} | {0:8.4f}".format(implied_prob_home, implied_prob_draw, implied_prob_away))
        print("Odd         : {0:8.2f} | {1:8.2f} | {2:8.2f}".format(home_odd, draw_odd, away_odd))
        print("EV          : {0:8.4f} | {1:8.4f} | {2:8.4f} >> {3:8.4f}".format(home_ev, draw_ev, away_ev, highest_ev))
        print("Bankroll    : {0:6.2f}".format(bankroll))
        print("Games played: {0:8d} | Bets placed: {1:3d}".format(GAMES_PLAYED, bets))
        print()

    form_dict[home_team]['goals_for'].append(goals_for)
    form_dict[home_team]['goals_against'].append(goals_against)

    form_dict[away_team]['goals_for'].append(goals_for)
    form_dict[away_team]['goals_against'].append(goals_for)

    GAMES_PLAYED += 1

I've not checked the results, so hopefully it works.  Sorry if I've taken a liberty, I got carried away!


问:
regex for email validation Not Working with Subdomains?
I'm using the following for email validation:

```<code>var filter = /^([\w]+)(.[\w]+)*@([\w]+)(.[\w]{2,3}){1,2}$/; // For Email Validation

if (filter.test(emailInputVal))) {console.log('good')}
</code>```

For some reason the above does not work with emails that have a subdomain Any ideas why?

```<code>xxxx@xxx.xxx.com
</code>```

Thanks

答:
Because your regular expression is incorrect. Try this instead:

```<code>var filter = /^\w+(?:\.\w+)*@\w+(?:\.\w+)+$/;
</code>```

This link may help you lots when validating email addresses:

http://www.regular-expressions.info/email.html

Official RFC 2822 standard

This non-trivial simplified regular expression conforming to RFC 2822 standard:

```<code>var filter = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/;
</code>```

Body:
I'm using the following for email validation:

var filter = /^([\w]+)(.[\w]+)*@([\w]+)(.[\w]{2,3}){1,2}$/; // For Email Validation

if (filter.test(emailInputVal))) {console.log('good')}

For some reason the above does not work with emails that have a subdomain Any ideas why?

xxxx@xxx.xxx.com

Thanks

Body:
Because your regular expression is incorrect. Try this instead:

var filter = /^\w+(?:\.\w+)*@\w+(?:\.\w+)+$/;

This link may help you lots when validating email addresses:

http://www.regular-expressions.info/email.html

Official RFC 2822 standard

This non-trivial simplified regular expression conforming to RFC 2822 standard:

var filter = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+(?:[A-Z]{2}|com|org|net|edu|gov|mil|biz|info|mobi|name|aero|asia|jobs|museum)\b/;


问:
Populate unbound text filed in MS ACCESS report via tempvars populated from a dlookup function
I'll try my very best to explain what I'm trying to bo. I'm still kinda novice in MS ACCESS and still trying to learn stuff. So what I'm trying to do is to populate the control source of an unbound textbox in Report. If for example I use this code ="
my name is " & [fullname] & ".
", it will work. The [fullname] field will be populated by the value assigned to it. But if I put that same code in a table then use the dlookup function to store the code in tempvars then use the tempvars to populate the unbound textbox, it will not work.

The unbound textbox is set to rich text so it recognizes the  and makes it bold but the value for the [fullname] field is not populated. It will just be returned as: my name is " & [fullname] & ".

Is there a way to do it so ms access will still populate the [fullname] value and not translate it literally?

Thanks,
Darren

答:
Try the Eval function, e.g.,

```<code>="<p>my name is <b>" & Eval([fullname]) & "</b>.</p>"
</code>```

Actually, in your case maybe this might be better:

```<code>=Eval("<p>my name is <b>" & [fullname] & "</b>.</p>")
</code>```

Body:
Try the Eval function, e.g.,

="<p>my name is <b>" & Eval([fullname]) & "</b>.</p>"

Actually, in your case maybe this might be better:

=Eval("<p>my name is <b>" & [fullname] & "</b>.</p>")


问:
Multithreading/multiprocessing in Django
I am working on a Django project in which i'll create an online judge (User can submit solutions to programming problems and will be autograded at server using python subprocess library where i can call g++) (something similiar to Codeforces website).

When user submits a solution i take his solution file and have to asynchronously call the grading function (automatic grading may take time)

I didnt use celery for the purpose because i read it has overheads and would have been overkill for mey project. So i built a queue object in Django and called a function to run on queue by creating a thread and it's working fine (i have read threads are evil warning).

I wanted to ask should i call python multiprocessing library to optimize the automatic grading on different cores. For example i'll create 4 queues and call grading function on each queue through different Processes. Will it be nice idea or overheads of calling multiprocessing will be larger?

Also will it be safe to do (if not good style of programming)?

答:
I think using celery is a much better and safer option.
Run workers with the concurrency you want.
That is hard and has  to control multi processes in your application level.</p>


问:
java.lang.RuntimeException: Unable to get provider android.arch.lifecycle.LifecycleRuntimeTrojanProvider
My app keeps crashing and this error keeps popping up when my app is run on a API level 19 device after I updated Android Studio to 3.0. This app worked fine with previous Android Studio. Also the app works fine with API level 24 device now.

P.S. -  I know this question was asked some times before and its a duplicate. But none of the solutions worked for me.

```<code>java.lang.RuntimeException: Unable to get provider android.arch.lifecycle.LifecycleRuntimeTrojanProvider: java.lang.ClassNotFoundException: Didn't find class "android.arch.lifecycle.LifecycleRuntimeTrojanProvider" on path: DexPathList[[zip file "/data/app/com.bayasys.bayatrade.mobile-76.apk"],nativeLibraryDirectories=[/data/app-lib/com.bayasys.bayatrade.mobile-76, /vendor/lib, /system/lib]]
                                                       at android.app.ActivityThread.installProvider(ActivityThread.java:5236)
                                                       at android.app.ActivityThread.installContentProviders(ActivityThread.java:4828)
                                                       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4711)
                                                       at android.app.ActivityThread.access$1600(ActivityThread.java:175)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:146)
                                                       at android.app.ActivityThread.main(ActivityThread.java:5602)
                                                       at java.lang.reflect.Method.invokeNative(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:515)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
                                                       at dalvik.system.NativeStart.main(Native Method)
                                                    Caused by: java.lang.ClassNotFoundException: Didn't find class "android.arch.lifecycle.LifecycleRuntimeTrojanProvider" on path: DexPathList[[zip file "/data/app/com.bayasys.bayatrade.mobile-76.apk"],nativeLibraryDirectories=[/data/app-lib/com.bayasys.bayatrade.mobile-76, /vendor/lib, /system/lib]]
                                                       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
                                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
                                                       at android.app.ActivityThread.installProvider(ActivityThread.java:5221)
                                                       at android.app.ActivityThread.installContentProviders(ActivityThread.java:4828)
                                                       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4711)
                                                       at android.app.ActivityThread.access$1600(ActivityThread.java:175)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:146)
                                                       at android.app.ActivityThread.main(ActivityThread.java:5602)
                                                       at java.lang.reflect.Method.invokeNative(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:515)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
                                                       at dalvik.system.NativeStart.main(Native Method)
</code>```

答: I faced the similar issue. I solved it by extending my Application class to MultidexApplication.</p>

Body:
My app keeps crashing and this error keeps popping up when my app is run on a API level 19 device after I updated Android Studio to 3.0. This app worked fine with previous Android Studio. Also the app works fine with API level 24 device now.

P.S. -  I know this question was asked some times before and its a duplicate. But none of the solutions worked for me.

java.lang.RuntimeException: Unable to get provider android.arch.lifecycle.LifecycleRuntimeTrojanProvider: java.lang.ClassNotFoundException: Didn't find class "android.arch.lifecycle.LifecycleRuntimeTrojanProvider" on path: DexPathList[[zip file "/data/app/com.bayasys.bayatrade.mobile-76.apk"],nativeLibraryDirectories=[/data/app-lib/com.bayasys.bayatrade.mobile-76, /vendor/lib, /system/lib]]
                                                       at android.app.ActivityThread.installProvider(ActivityThread.java:5236)
                                                       at android.app.ActivityThread.installContentProviders(ActivityThread.java:4828)
                                                       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4711)
                                                       at android.app.ActivityThread.access$1600(ActivityThread.java:175)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:146)
                                                       at android.app.ActivityThread.main(ActivityThread.java:5602)
                                                       at java.lang.reflect.Method.invokeNative(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:515)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
                                                       at dalvik.system.NativeStart.main(Native Method)
                                                    Caused by: java.lang.ClassNotFoundException: Didn't find class "android.arch.lifecycle.LifecycleRuntimeTrojanProvider" on path: DexPathList[[zip file "/data/app/com.bayasys.bayatrade.mobile-76.apk"],nativeLibraryDirectories=[/data/app-lib/com.bayasys.bayatrade.mobile-76, /vendor/lib, /system/lib]]
                                                       at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
                                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:497)
                                                       at java.lang.ClassLoader.loadClass(ClassLoader.java:457)
                                                       at android.app.ActivityThread.installProvider(ActivityThread.java:5221)
                                                       at android.app.ActivityThread.installContentProviders(ActivityThread.java:4828)
                                                       at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4711)
                                                       at android.app.ActivityThread.access$1600(ActivityThread.java:175)
                                                       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1368)
                                                       at android.os.Handler.dispatchMessage(Handler.java:102)
                                                       at android.os.Looper.loop(Looper.java:146)
                                                       at android.app.ActivityThread.main(ActivityThread.java:5602)
                                                       at java.lang.reflect.Method.invokeNative(Native Method)
                                                       at java.lang.reflect.Method.invoke(Method.java:515)
                                                       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
                                                       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
                                                       at dalvik.system.NativeStart.main(Native Method)


问:
How do I fix an xstring exception with tmxparser? SFML/C++
I currently I have a problem that when I run my code, it stops at an exception at line 3467 in the xstring system file. Here is a few screenshots of it:

.

I figured it had to do something to do with loading the file or the file is corrupted. Something is wrong with how it parses. Here is the link to my Github page. I used the tmxlite parser to load the file, here is also a link to the tmxlite Github page. Thanks so much! Sorry if this is a dumb question. I really have not programmed C++ for long, and done it without proper training. This is the tmx file link

答: I am so sorry for those who looked at this. It turns out I needed to edit my tmx files to include the tsx files and add the tsx files to the project. I am so sorry if I made anyone look for the answer when all I had to do was just use the resources in front of me. Thanks to underscore_d for telling me make it into a MCVE, leading me to find the answer. All this time... Sorry anyone whose time I wasted.</p>


问:
Magick.net converting PDF to image "unable to create temporary file '': No such file or directory @ error/pdf.c/ReadPDFImage/476"
I'm trying to use Magick.net in a console application to render images from a PDFs and can't seem to get around this problem.

Upon calling "MagickImageCollection.Read(byte[], settings)" I always get a

"unable to create temporary file '': No such file or directory @
  error/pdf.c/ReadPDFImage/476"

exception.

I have tried:

Placing both x86 and 64bit Ghostscript dlls in the bin folder.

Using combinations of AnyCPU, x86, 64 versions of Magick.net, with versions of GS

Setting MagickNET.SetGhostscriptDirectory to the program files GS bin folder

Setting MagickNET.SetTempDirectory to a folder in c:/temp and confirmed that my application can access by programatically moving a file in there.

Setting the MagickAnyCPU.CacheDirectory to a folder in c:/temp

I'm out of ideas of what I could be doing wrong

```<code>    using (MagickImageCollection images = new MagickImageCollection())
    {
        // Add all the pages of the pdf file to the collection
        images.Read(file, settings);

        switch (orientation)
        {
            case Orientation.Horizontal:
                using (MagickImage image = (MagickImage)images.AppendHorizontally())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        image.Write(ms);

                        return ms.ToArray();
                    }

                }
            case Orientation.Vertical:
                using (MagickImage image = (MagickImage)images.AppendHorizontally())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        image.Write(ms);

                        return ms.ToArray();
                    }
                }
        }
    }
</code>```

答:
I finally managed to overcome this problem, I was passing the wrong read settings to MagickImageCollection.Read(byte[], settings).

I was telling Magick to read the PDF with the PNG format instead of writing the result to PNG...

```<code>MagickReadSettings settings = new MagickReadSettings();
settings.Format = MagickFormat.Png;
</code>```

I feel a bit silly but the error message completely through me off.

Body:
I'm trying to use Magick.net in a console application to render images from a PDFs and can't seem to get around this problem.

Upon calling "MagickImageCollection.Read(byte[], settings)" I always get a

"unable to create temporary file '': No such file or directory @
  error/pdf.c/ReadPDFImage/476"

exception.

I have tried:

Placing both x86 and 64bit Ghostscript dlls in the bin folder.

Using combinations of AnyCPU, x86, 64 versions of Magick.net, with versions of GS

Setting MagickNET.SetGhostscriptDirectory to the program files GS bin folder

Setting MagickNET.SetTempDirectory to a folder in c:/temp and confirmed that my application can access by programatically moving a file in there.

Setting the MagickAnyCPU.CacheDirectory to a folder in c:/temp

I'm out of ideas of what I could be doing wrong

    using (MagickImageCollection images = new MagickImageCollection())
    {
        // Add all the pages of the pdf file to the collection
        images.Read(file, settings);

        switch (orientation)
        {
            case Orientation.Horizontal:
                using (MagickImage image = (MagickImage)images.AppendHorizontally())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        image.Write(ms);

                        return ms.ToArray();
                    }

                }
            case Orientation.Vertical:
                using (MagickImage image = (MagickImage)images.AppendHorizontally())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        image.Write(ms);

                        return ms.ToArray();
                    }
                }
        }
    }

Body:
I finally managed to overcome this problem, I was passing the wrong read settings to MagickImageCollection.Read(byte[], settings).

I was telling Magick to read the PDF with the PNG format instead of writing the result to PNG...

MagickReadSettings settings = new MagickReadSettings();
settings.Format = MagickFormat.Png;

I feel a bit silly but the error message completely through me off.


问:
Database Query failed error when inserting Row into Table
I am getting Database query failed error while trying to insert a new row into a table. This table (pages) has a column (subject_id) referencing another table (subjects). I am passing the value of the of the subject_id from the url and it is passed on the form correctly. All the values seem to be passed correctly on the form using php, but i get error while i try to insert the row. The form submits to itself.

select_all_pages_by_subject($sid) is a function that selects all rows (pages) from the current subject (passed from the url). It works fine for the position field.

I suspect this error is probably a MySQL syntax error somewhere in my code, but i just cant seem to figure it out yet. I appreciate some help. Thank you.

Here is my code:

```<code><div class="body_content">
<?php
    $sid = null;
if(isset($_GET["subject"])) {
    $sid = $_GET["subject"];
}
?>
<form action="create_page.php" method="post">
Menu Name:  <input type="text" name="menu" /> <br>
Position:   <select name="position">
                <?php
                $new_page_query = select_all_pages_by_subject($sid);
                $page_count = mysqli_num_rows($new_page_query);
                for($count=1; $count<=($page_count + 1); $count++) {
                            echo "<option value=\"$count\">$count</option>";
                }
                ?>
            </select> <br>
Visible:<br>
No <input type="radio" name="visible" value="0" />
Yes <input type="radio" name="visible" value="1" /> <br>
Subject ID: <input type="text" name="subject_id" value="<?php echo $sid; ?>" /> <br>
Content: <br>
<textarea rows="5" cols="40" name="content"></textarea> <br>
<input type="submit" value="Create Page" name="submit" /> <br>
<a href="admin.php">Cancel</a> <br>
</form>
<?php
        if(isset($_POST['submit'])) {
        $menu_name = $_POST["menu"];
        $position = (int) $_POST["position"];
        $visible = (int) $_POST["visible"];
        $content = $_POST["content"];
        $subject_id = (int) $_POST["$sid"];
        $insert_query = "INSERT INTO pages (subject_id, menu_name, position,
                          visible, content) VALUES ({$subject_id},'{$menu_name}', {$position},
                          {$visible}, '{content}')";
        $page_insert = mysqli_query($connection, $insert_query);
        if($page_insert) {
            $_SESSION["message"] = "Page created successfully";
            redirect_to("admin.php");
        } else {
        $_SESSION["message"] = "Page creation failed";
        redirect_to("create_page.php?subject=$sid");
    }
}
?>
</div>
</code>```

Edit: removed the WHERE statement

答:
The problem is INSERT cannot have a WHERE after it.

```<code>$insert_query = "INSERT INTO pages (subject_id, menu_name, position, visible, content) VALUES ({$subject_id},'{$menu_name}', {$position}, {$visible}, '{content}')";
</code>```

Body:
I am getting Database query failed error while trying to insert a new row into a table. This table (pages) has a column (subject_id) referencing another table (subjects). I am passing the value of the of the subject_id from the url and it is passed on the form correctly. All the values seem to be passed correctly on the form using php, but i get error while i try to insert the row. The form submits to itself.

select_all_pages_by_subject($sid) is a function that selects all rows (pages) from the current subject (passed from the url). It works fine for the position field.

I suspect this error is probably a MySQL syntax error somewhere in my code, but i just cant seem to figure it out yet. I appreciate some help. Thank you.

Here is my code:

<?php
    $sid = null;
if(isset($_GET["subject"])) {
    $sid = $_GET["subject"];
}
?>
<form action="create_page.php" method="post">
Menu Name:  <input type="text" name="menu" />

Position:   <select name="position">
                <?php
                $new_page_query = select_all_pages_by_subject($sid);
                $page_count = mysqli_num_rows($new_page_query);
                for($count=1; $count<=($page_count + 1); $count++) {
                            echo "<option value=\"$count\">$count</option>";
                }
                ?>
            </select>

Visible:

No <input type="radio" name="visible" value="0" />
Yes <input type="radio" name="visible" value="1" />

Subject ID: <input type="text" name="subject_id" value="<?php echo $sid; ?>" />

Content:

<textarea rows="5" cols="40" name="content"></textarea>

<input type="submit" value="Create Page" name="submit" />

Cancel

</form>
<?php
        if(isset($_POST['submit'])) {
        $menu_name = $_POST["menu"];
        $position = (int) $_POST["position"];
        $visible = (int) $_POST["visible"];
        $content = $_POST["content"];
        $subject_id = (int) $_POST["$sid"];
        $insert_query = "INSERT INTO pages (subject_id, menu_name, position,
                          visible, content) VALUES ({$subject_id},'{$menu_name}', {$position},
                          {$visible}, '{content}')";
        $page_insert = mysqli_query($connection, $insert_query);
        if($page_insert) {
            $_SESSION["message"] = "Page created successfully";
            redirect_to("admin.php");
        } else {
        $_SESSION["message"] = "Page creation failed";
        redirect_to("create_page.php?subject=$sid");
    }
}
?>

Edit: removed the WHERE statement

Body:
The problem is INSERT cannot have a WHERE after it.

$insert_query = "INSERT INTO pages (subject_id, menu_name, position, visible, content) VALUES ({$subject_id},'{$menu_name}', {$position}, {$visible}, '{content}')";


问:
Pushing object to observableArray
New to knockoutjs and I was following the tutorial on Loading and saving data, but I am having a little trouble. When I push my object to an array the array is empty. I am also using a form. Here is my code,

```<code>function Quiz(data) {
    this.quiz_name = ko.observable(data.newQuizName);
    this.quiz_type = ko.observable(data.newQuizType);
}

function QuizViewModel() {
    var self = this;
    self.quizzes = ko.observableArray([]);
    self.newQuizName = ko.observable();
    self.newQuizType = ko.observable();

    self.addQuiz = function () {
        self.quizzes.push(new Quiz({quiz_name: this.newQuizName(), quiz_type: this.newQuizType()}))
        console.log(ko.toJSON(self.quizzes));
    };
}

ko.applyBindings(new QuizViewModel());
</code>```

and this is my HTML

```<code> <form name="quizzes" id="new-form-quizzes" data-bind="submit: addQuiz" style="display:none">
    <div class="form-group">
        <label for="quiz-name">Quiz Name</label>
        <input type="text" class="form-control" id="quiz-name" aria-describedby="quiz name"
               data-bind="value: newQuizName"
               placeholder="Quize Name"/>
    </div>
    <div class="form-group">
        <label for="quiz-type">Quiz Type</label>
        <input type="text"
               class="form-control"
               id="quiz-type"
               data-bind="value: newQuizType"
               placeholder="Quiz Type"/>
    </div>
    <button type="submit">Save</button>
</form>
</code>```

Not sure what I am doing wrong as both newQuizName and newQuizType do have values. Any help would be much appreciated.

答:
You should pass an object (or an array) containing observables as an argument to ko.toJSON. Not the observable itself. So, you need to change your code to:

```<code>ko.toJSON(self.quizzes());
</code>```

ko.toJSON internally calls ko.toJS. The latter method goes through the object and converts each observable to the value of that observable.

After making this change you'll find that there's another problem. The newly added Quiz object has undefined properties. This is because you are passing an object with quiz_name and quiz_type to the Quiz constructor function. But you are accessing newQuizName property from the data parameter. So change your code to:

function Quiz(data) {
  this.quiz_name = ko.observable(data.quiz_name); // these 2 props must be changed
  this.quiz_type = ko.observable(data.quiz_type);
}

function QuizViewModel() {
  var self = this;
  self.quizzes = ko.observableArray([]);
  self.newQuizName = ko.observable();
  self.newQuizType = ko.observable();

  self.addQuiz = function() {
    self.quizzes.push(new Quiz({
      quiz_name: this.newQuizName(),
      quiz_type: this.newQuizType()
    }));

    console.log(ko.toJSON(self.quizzes()));
  };
}

ko.applyBindings(new QuizViewModel());```
<pre class="snippet-code-html lang-html prettyprint-override"><code><script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<form name="quizzes" id="new-form-quizzes" data-bind="submit: addQuiz">
  <div class="form-group">
    <label for="quiz-name">Quiz Name</label>
    <input type="text" class="form-control" id="quiz-name" aria-describedby="quiz name" data-bind="value: newQuizName" placeholder="Quize Name" />
  </div>
  <div class="form-group">
    <label for="quiz-type">Quiz Type</label>
    <input type="text" class="form-control" id="quiz-type" data-bind="value: newQuizType" placeholder="Quiz Type" />
  </div>
  <button type="submit">Save</button>
</form>

<!--Table to display the added quizzes-->
<table data-bind="if: quizzes() && quizzes().length > 0">
  <thead>
    <th>Quiz Name</th>
    <th>Quiz Type </th>
  </thead>
  <tbody data-bind="foreach: quizzes">
    <tr>
      <td data-bind="text:quiz_name"></td>
      <td data-bind="text:quiz_type"></td>
    </tr>
  </tbody>
</table></code>```

Title: Pushing object to observableArray

Body:
New to knockoutjs and I was following the tutorial on Loading and saving data, but I am having a little trouble. When I push my object to an array the array is empty. I am also using a form. Here is my code,

function Quiz(data) {
    this.quiz_name = ko.observable(data.newQuizName);
    this.quiz_type = ko.observable(data.newQuizType);
}

function QuizViewModel() {
    var self = this;
    self.quizzes = ko.observableArray([]);
    self.newQuizName = ko.observable();
    self.newQuizType = ko.observable();

    self.addQuiz = function () {
        self.quizzes.push(new Quiz({quiz_name: this.newQuizName(), quiz_type: this.newQuizType()}))
        console.log(ko.toJSON(self.quizzes));
    };
}

ko.applyBindings(new QuizViewModel());

and this is my HTML

 <form name="quizzes" id="new-form-quizzes" data-bind="submit: addQuiz" style="display:none">

        Quiz Name
        <input type="text" class="form-control" id="quiz-name" aria-describedby="quiz name"
               data-bind="value: newQuizName"
               placeholder="Quize Name"/>

        Quiz Type
        <input type="text"
               class="form-control"
               id="quiz-type"
               data-bind="value: newQuizType"
               placeholder="Quiz Type"/>

    <button type="submit">Save</button>
</form>

Not sure what I am doing wrong as both newQuizName and newQuizType do have values. Any help would be much appreciated.

Body:
You should pass an object (or an array) containing observables as an argument to ko.toJSON. Not the observable itself. So, you need to change your code to:

ko.toJSON(self.quizzes());

ko.toJSON internally calls ko.toJS. The latter method goes through the object and converts each observable to the value of that observable.

After making this change you'll find that there's another problem. The newly added Quiz object has undefined properties. This is because you are passing an object with quiz_name and quiz_type to the Quiz constructor function. But you are accessing newQuizName property from the data parameter. So change your code to:

function Quiz(data) {
  this.quiz_name = ko.observable(data.quiz_name); // these 2 props must be changed
  this.quiz_type = ko.observable(data.quiz_type);
}

function QuizViewModel() {
  var self = this;
  self.quizzes = ko.observableArray([]);
  self.newQuizName = ko.observable();
  self.newQuizType = ko.observable();

  self.addQuiz = function() {
    self.quizzes.push(new Quiz({
      quiz_name: this.newQuizName(),
      quiz_type: this.newQuizType()
    }));

    console.log(ko.toJSON(self.quizzes()));
  };
}

ko.applyBindings(new QuizViewModel());

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<form name="quizzes" id="new-form-quizzes" data-bind="submit: addQuiz">
  <div class="form-group">
    <label for="quiz-name">Quiz Name</label>
    <input type="text" class="form-control" id="quiz-name" aria-describedby="quiz name" data-bind="value: newQuizName" placeholder="Quize Name" />
  </div>
  <div class="form-group">
    <label for="quiz-type">Quiz Type</label>
    <input type="text" class="form-control" id="quiz-type" data-bind="value: newQuizType" placeholder="Quiz Type" />
  </div>
  <button type="submit">Save</button>
</form>

<!--Table to display the added quizzes-->
<table data-bind="if: quizzes() && quizzes().length > 0">
  <thead>
    <th>Quiz Name</th>
    <th>Quiz Type </th>
  </thead>
  <tbody data-bind="foreach: quizzes">
    <tr>
      <td data-bind="text:quiz_name"></td>
      <td data-bind="text:quiz_type"></td>
    </tr>
  </tbody>
</table>