问:
Go timeout for Read
I'd like to do something like unix's tail -f, but on the output produced by a process run through Go's Cmd facility.

My google-fu is not up to par, evidently, but I did find this article which lead me to write the following code, which almost works, with a bizarre twist I'm hoping I can get help with.

If it matters, I'm running this on a Mac.

First, here's the minimal program that's compiled to be the slowroll executable:

package main

import (
    "fmt"
    "time"
)

func main() {
    line := 1
    for {
        fmt.Println("This is line", line)
        line += 1
        time.Sleep(2 * time.Second)
    }
}
```
<p>When run, it produces the following output, one line every 2 seconds:</p>
```    > ./slowroll
    This is line 1
    This is line 2
    This is line 3
    This is line 4
```
<p>And so on.</p>
<p>Here's the package code that attempts to read this, but allowing timeouts so other things can be done:</p>
<pre class="lang-golang prettyprint-override"><code>package timeout_io

import (
    "bufio"
    "bytes"
    "context"
    "errors"
    "time"
)

const BufferSize = 4096

var ErrTimeout = errors.New("timeout")

type TimeoutReader struct {
    b *bufio.Reader
    t time.Duration
}

func NewTimeoutReader(stdOut *bytes.Buffer) *TimeoutReader {
    return &TimeoutReader{b: bufio.NewReaderSize(stdOut, BufferSize), t: 0}
}

func (r *TimeoutReader) SetTimeout(t time.Duration) time.Duration {
    prev := r.t
    r.t = t
    return prev
}

type CallResponse struct {
    Resp string
    Err  error
}

func helper(r *bufio.Reader) <-chan *CallResponse {
    respChan := make(chan *CallResponse, 1)

    go func() {
        resp, err := r.ReadString('\n')

        if err != nil {
            respChan <- &CallResponse{resp, err}
        } else {
            respChan <- &CallResponse{resp, nil}
        }

        return
    }()

    return respChan
}

func (r *TimeoutReader) ReadLineCtx(ctx context.Context) (string, error) {
    select {
    case <-ctx.Done():
        return "", ErrTimeout
    case respChan := <-helper(r.b):
        return respChan.Resp, respChan.Err
    }
}

func (r *TimeoutReader) ReadLine() (string, error) {
    ctx, cancel := context.WithTimeout(context.Background(), r.t)
    defer cancel()

    s, err := r.ReadLineCtx(ctx)
    if err != nil {
        return "", err
    }

    return s, nil
}
</code>```

Finally, here's the main code that calls ReadLine with timeout:

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
    "os/exec"
    "sync"
    "time"

    "watcher/timeout_io"
)

func main() {
    var stdOut bytes.Buffer
    var stdErr bytes.Buffer
    runCommand := &exec.Cmd{
        Path:   "./slowroll",
        Stdout: &stdOut,
        Stderr: &stdErr,
    }

    var wg sync.WaitGroup

    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        err := runCommand.Run()
        if err != nil {
            fmt.Println("failed due to error:", err)
            os.Exit(1)
        }
    }(&wg)

    wg.Add(1)

    stdOutReader := timeout_io.NewTimeoutReader(&stdOut)
    stdOutReader.SetTimeout(10 * time.Millisecond)
    index := 1
    for {
        s, err := stdOutReader.ReadLine()
        if err != nil {
            if err != timeout_io.ErrTimeout && err != io.EOF {
                fmt.Println("ReadLine got error", err)
                break
            }
        } else if len(s) > 0 {
            fmt.Println("index: ", index, " s: ", s)
            index += 1
            s = ""
        }
    }

    wg.Wait()
    fmt.Println("Done!")
}
```
<p>When run, it produces the following output:</p>
```    > go run watcher.go
    index:  1  s:  This is line 1

    index:  2  s:  This is line 2

    index:  3  s:  This is line 2

    index:  4  s:  This is line 3

    index:  5  s:  This is line 2

    index:  6  s:  This is line 3

    index:  7  s:  This is line 4

    index:  8  s:  This is line 2

    index:  9  s:  This is line 3

    index:  10  s:  This is line 4

    index:  11  s:  This is line 5
```

And so on.

Occasionally, some slowroll output lines don't show up at all; which lines get repeated is random.

So that's my mystery... I don't see where the (apparent) loop is happening that causes the lines to be produced multiple times.

Thanks very much in advance for any help!

答:
Realized late last night that I was kind of fighting go's standard behavior.

Should have explained that the goal was to be able to watch stdout and stderr at the same time.

Taking @Zombo's advice above, I switched to cmd.StdoutPipe and cmd.StderrPipe.

The main idea is to just have goroutines that read the pipes and put content found into channels, and then select between the channels.

So slowroll.go does not produce infinite output, to show that EOF doesn't cause a infinite loop:

package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    line := 1
    for {
        fmt.Println("This is line", line)
        line += 1
        time.Sleep(2 * time.Second)
        if line%3 == 0 {
            fmt.Fprintf(os.Stderr, "This is error %d\n", line)
        }
        if line > 10 {
            break
        }
    }
}
```
<p>And the simpler, working <code>watcher.go</code> is now:</p>
<pre class="lang-golang prettyprint-override"><code>package main

import (
    "bufio"
    "fmt"
    "os"
    "os/exec"
    "sync"
)

func main() {
    runCommand := &exec.Cmd{
        Path: "./slowroll",
    }
    stdOut, err := runCommand.StdoutPipe()
    if err != nil {
        fmt.Println("Can't create StdoutPipe:", err)
        os.Exit(1)
    }
    stdErr, err := runCommand.StderrPipe()
    if err != nil {
        fmt.Println("Can't create StderrPipe:", err)
        os.Exit(1)
    }

    var wg sync.WaitGroup

    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        err := runCommand.Run()
        if err != nil {
            fmt.Println("failed due to error:", err)
            os.Exit(1)
        }
    }(&wg)

    wg.Add(1)

    stdOutChan := make(chan string, 1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        scanner := bufio.NewScanner(stdOut)
        for scanner.Scan() {
            stdOutChan <- string(scanner.Bytes())
        }
        fmt.Println("Ran out of stdout input, read thread bailing.")
        close(stdOutChan)
    }(&wg)

    wg.Add(1)

    stdErrChan := make(chan string, 1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        scanner := bufio.NewScanner(stdErr)
        for scanner.Scan() {
            stdErrChan <- string(scanner.Bytes())
        }
        fmt.Println("Ran out of stderr input, read thread bailing.")
        close(stdErrChan)
    }(&wg)

    wg.Add(1)

    index := 1
    keepGoing := true
    for keepGoing {
        select {
        case res, isOpen := <-stdOutChan:
            if !isOpen {
                fmt.Println("stdOutChan is no longer open, main bailing.")
                keepGoing = false
            } else {
                fmt.Println(index, "s:", res)
                index += 1
            }

        case res, isOpen := <-stdErrChan:
            if !isOpen {
                fmt.Println("stdErrChan is no longer open, main bailing.")
                keepGoing = false
            } else {
                fmt.Println(index, "error s:", res)
                index += 1
            }
        }
    }

    wg.Wait()
    fmt.Println("Done!")
}
</code>```

Output:

```<code>    > go run watcher.go
    1 s: This is line 1
    2 s: This is line 2
    3 error s: This is error 3
    4 s: This is line 3
    5 s: This is line 4
    6 s: This is line 5
    7 s: This is line 6
    8 error s: This is error 6
    9 s: This is line 7
    10 s: This is line 8
    11 s: This is line 9
    12 error s: This is error 9
    13 s: This is line 10
    Ran out of stdout input, read thread bailing.
    stdOutChan is no longer open, main bailing.
    Ran out of stderr input, read thread bailing.
    Done!
</code>```

Could stand with some refactoring, obviously, but it works, which is the goal.

Thanks!

Title: Go timeout for Read

Body:
I'd like to do something like unix's tail -f, but on the output produced by a process run through Go's Cmd facility.

My google-fu is not up to par, evidently, but I did find this article which lead me to write the following code, which almost works, with a bizarre twist I'm hoping I can get help with.

If it matters, I'm running this on a Mac.

First, here's the minimal program that's compiled to be the slowroll executable:

package main

import (
    "fmt"
    "time"
)

func main() {
    line := 1
    for {
        fmt.Println("This is line", line)
        line += 1
        time.Sleep(2 * time.Second)
    }
}

When run, it produces the following output, one line every 2 seconds:

    > ./slowroll
    This is line 1
    This is line 2
    This is line 3
    This is line 4

And so on.

Here's the package code that attempts to read this, but allowing timeouts so other things can be done:

package timeout_io

import (
    "bufio"
    "bytes"
    "context"
    "errors"
    "time"
)

const BufferSize = 4096

var ErrTimeout = errors.New("timeout")

type TimeoutReader struct {
    b *bufio.Reader
    t time.Duration
}

func NewTimeoutReader(stdOut *bytes.Buffer) *TimeoutReader {
    return &TimeoutReader{b: bufio.NewReaderSize(stdOut, BufferSize), t: 0}
}

func (r *TimeoutReader) SetTimeout(t time.Duration) time.Duration {
    prev := r.t
    r.t = t
    return prev
}

type CallResponse struct {
    Resp string
    Err  error
}

func helper(r *bufio.Reader) <-chan *CallResponse {
    respChan := make(chan *CallResponse, 1)

    go func() {
        resp, err := r.ReadString('\n')

        if err != nil {
            respChan <- &CallResponse{resp, err}
        } else {
            respChan <- &CallResponse{resp, nil}
        }

        return
    }()

    return respChan
}

func (r *TimeoutReader) ReadLineCtx(ctx context.Context) (string, error) {
    select {
    case <-ctx.Done():
        return "", ErrTimeout
    case respChan := <-helper(r.b):
        return respChan.Resp, respChan.Err
    }
}

func (r *TimeoutReader) ReadLine() (string, error) {
    ctx, cancel := context.WithTimeout(context.Background(), r.t)
    defer cancel()

    s, err := r.ReadLineCtx(ctx)
    if err != nil {
        return "", err
    }

    return s, nil
}

Finally, here's the main code that calls ReadLine with timeout:

package main

import (
    "bytes"
    "fmt"
    "io"
    "os"
    "os/exec"
    "sync"
    "time"

    "watcher/timeout_io"
)

func main() {
    var stdOut bytes.Buffer
    var stdErr bytes.Buffer
    runCommand := &exec.Cmd{
        Path:   "./slowroll",
        Stdout: &stdOut,
        Stderr: &stdErr,
    }

    var wg sync.WaitGroup

    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        err := runCommand.Run()
        if err != nil {
            fmt.Println("failed due to error:", err)
            os.Exit(1)
        }
    }(&wg)

    wg.Add(1)

    stdOutReader := timeout_io.NewTimeoutReader(&stdOut)
    stdOutReader.SetTimeout(10 * time.Millisecond)
    index := 1
    for {
        s, err := stdOutReader.ReadLine()
        if err != nil {
            if err != timeout_io.ErrTimeout && err != io.EOF {
                fmt.Println("ReadLine got error", err)
                break
            }
        } else if len(s) > 0 {
            fmt.Println("index: ", index, " s: ", s)
            index += 1
            s = ""
        }
    }

    wg.Wait()
    fmt.Println("Done!")
}

When run, it produces the following output:

    > go run watcher.go
    index:  1  s:  This is line 1

    index:  2  s:  This is line 2

    index:  3  s:  This is line 2

    index:  4  s:  This is line 3

    index:  5  s:  This is line 2

    index:  6  s:  This is line 3

    index:  7  s:  This is line 4

    index:  8  s:  This is line 2

    index:  9  s:  This is line 3

    index:  10  s:  This is line 4

    index:  11  s:  This is line 5

And so on.

Occasionally, some slowroll output lines don't show up at all; which lines get repeated is random.

So that's my mystery... I don't see where the (apparent) loop is happening that causes the lines to be produced multiple times.

Thanks very much in advance for any help!

Body:
Realized late last night that I was kind of fighting go's standard behavior.

Should have explained that the goal was to be able to watch stdout and stderr at the same time.

Taking @Zombo's advice above, I switched to cmd.StdoutPipe and cmd.StderrPipe.

The main idea is to just have goroutines that read the pipes and put content found into channels, and then select between the channels.

So slowroll.go does not produce infinite output, to show that EOF doesn't cause a infinite loop:

package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    line := 1
    for {
        fmt.Println("This is line", line)
        line += 1
        time.Sleep(2 * time.Second)
        if line%3 == 0 {
            fmt.Fprintf(os.Stderr, "This is error %d\n", line)
        }
        if line > 10 {
            break
        }
    }
}

And the simpler, working watcher.go is now:

package main

import (
    "bufio"
    "fmt"
    "os"
    "os/exec"
    "sync"
)

func main() {
    runCommand := &exec.Cmd{
        Path: "./slowroll",
    }
    stdOut, err := runCommand.StdoutPipe()
    if err != nil {
        fmt.Println("Can't create StdoutPipe:", err)
        os.Exit(1)
    }
    stdErr, err := runCommand.StderrPipe()
    if err != nil {
        fmt.Println("Can't create StderrPipe:", err)
        os.Exit(1)
    }

    var wg sync.WaitGroup

    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        err := runCommand.Run()
        if err != nil {
            fmt.Println("failed due to error:", err)
            os.Exit(1)
        }
    }(&wg)

    wg.Add(1)

    stdOutChan := make(chan string, 1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        scanner := bufio.NewScanner(stdOut)
        for scanner.Scan() {
            stdOutChan <- string(scanner.Bytes())
        }
        fmt.Println("Ran out of stdout input, read thread bailing.")
        close(stdOutChan)
    }(&wg)

    wg.Add(1)

    stdErrChan := make(chan string, 1)
    go func(wg *sync.WaitGroup) {
        defer wg.Done()

        scanner := bufio.NewScanner(stdErr)
        for scanner.Scan() {
            stdErrChan <- string(scanner.Bytes())
        }
        fmt.Println("Ran out of stderr input, read thread bailing.")
        close(stdErrChan)
    }(&wg)

    wg.Add(1)

    index := 1
    keepGoing := true
    for keepGoing {
        select {
        case res, isOpen := <-stdOutChan:
            if !isOpen {
                fmt.Println("stdOutChan is no longer open, main bailing.")
                keepGoing = false
            } else {
                fmt.Println(index, "s:", res)
                index += 1
            }

        case res, isOpen := <-stdErrChan:
            if !isOpen {
                fmt.Println("stdErrChan is no longer open, main bailing.")
                keepGoing = false
            } else {
                fmt.Println(index, "error s:", res)
                index += 1
            }
        }
    }

    wg.Wait()
    fmt.Println("Done!")
}

Output:

    > go run watcher.go
    1 s: This is line 1
    2 s: This is line 2
    3 error s: This is error 3
    4 s: This is line 3
    5 s: This is line 4
    6 s: This is line 5
    7 s: This is line 6
    8 error s: This is error 6
    9 s: This is line 7
    10 s: This is line 8
    11 s: This is line 9
    12 error s: This is error 9
    13 s: This is line 10
    Ran out of stdout input, read thread bailing.
    stdOutChan is no longer open, main bailing.
    Ran out of stderr input, read thread bailing.
    Done!

Could stand with some refactoring, obviously, but it works, which is the goal.

Thanks!


来源: stackexchange

问:
Clarification on overloading
When the parent class have an add method with 2 parameters, If we add new add method with 3 parameters in child class, shall we call this as over loading?

Thanks in advance.

答: Yes definitely a overloading and a nice feature of inheritance.</p>

ContentLicense: CC BY-SA 3.0

Title: Clarification on overloading


问:
Apache Pulsar Admin UI Login Issue - M1 Mac - Docker-Desktop
I am having an issue logging into the Pulsar Manager UI running on my k8s cluster in docker-desktop on my M1 Mac.

When I try to login, I am unable to progress past the login page with the default pulsar admin credentials and when I inspect the page I see  the following:

```<code>Failed to load resource: the server responded with a status of 404 (Not Found)
</code>```

I think the issue has something to do with me being unable to connect with the backed service over port 7750 but I am honestly not sure how I can resolve that. I have deployed using the helm chart and used the minikube.yaml file values to keep replica counts and such down since it's running on the single docker-destop node.

Has anyone encountered this issue before or know of a solution?
If this issue has already come up here, I would love a link to that thread!

Below I have included some details of what's running in my cluster, the other values are all the same as what's included in the helm chart.

Services:

```<code>k get svc -n pulsar
NAME                         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                               AGE
pulsar-mini-bookie           ClusterIP      None             <none>        3181/TCP,8000/TCP                     21h
pulsar-mini-broker           ClusterIP      None             <none>        8080/TCP,6650/TCP                     21h
pulsar-mini-proxy            LoadBalancer   10.102.192.239   localhost     80:30132/TCP,6650:30925/TCP           21h
pulsar-mini-pulsar-manager   LoadBalancer   10.98.70.14      localhost     9527:30322/TCP                        21h
pulsar-mini-toolset          ClusterIP      None             <none>        <none>                                21h
pulsar-mini-zookeeper        ClusterIP      None             <none>        8000/TCP,2888/TCP,3888/TCP,2181/TCP   21h
</code>```

Output of csrf command, showing that connection is refused from 7750, even if I try to use kubectl port-forward of the pulsar-mini-pulsar-manager pod (though perhaps this isn't the correct way to do it):

```<code>% CSRF_TOKEN=$(curl http://localhost:7750/pulsar-manager/csrf-token)
curl \
    -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
    -H "Cookie: XSRF-TOKEN=$CSRF_TOKEN;" \
    -H 'Content-Type: application/json' \
    -X PUT http://localhost:7750/pulsar-manager/users/superuser \
    -d '{"name": "admin", "password": "apachepulsar", "description": "test", "email": "username@test.org"}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (7) Failed to connect to localhost port 7750: Connection refused
curl: (7) Failed to connect to localhost port 7750: Connection refused
</code>```

When I run the bin/pulsar-admin commands from my local machine, things work just fine. I simply can't access the commands or the UI for some reason.
Output of some commands below:

```<code>$ bin/pulsar-admin topics list-partitioned-topics apache/pulsar
"persistent://apache/pulsar/test-topic"
/apache-pulsar-2.9.1
$ bin/pulsar-admin namespaces list apache
"apache/pulsar"
"apache/tester"
$ bin/pulsar-admin topics create-partitioned-topic apache/pulsar/test-topic-2 -p 4
$ bin/pulsar-admin topics list-partitioned-topics apache/pulsar
"persistent://apache/pulsar/test-topic"
"persistent://apache/pulsar/test-topic-2"
</code>```

答:
Is that the correct port?  What is in your PM configuration?   Anything in the logs?

https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/

9527:30322/TCP

https://pulsar.apache.org/docs/en/administration-pulsar-manager/

in docker we have to specify the second port.

docker run -it

-p 9527:9527 -p 7750:7750

-e SPRING_CONFIGURATION_FILE=/pulsar-manager/pulsar-manager/application.properties

apachepulsar/pulsar-manager:v0.2.0

You only have the 9527 port specific

ContentLicense: CC BY-SA 4.0

Body:
I am having an issue logging into the Pulsar Manager UI running on my k8s cluster in docker-desktop on my M1 Mac.

When I try to login, I am unable to progress past the login page with the default pulsar admin credentials and when I inspect the page I see  the following:

Failed to load resource: the server responded with a status of 404 (Not Found)

I think the issue has something to do with me being unable to connect with the backed service over port 7750 but I am honestly not sure how I can resolve that. I have deployed using the helm chart and used the minikube.yaml file values to keep replica counts and such down since it's running on the single docker-destop node.

Has anyone encountered this issue before or know of a solution?
If this issue has already come up here, I would love a link to that thread!

Below I have included some details of what's running in my cluster, the other values are all the same as what's included in the helm chart.

Services:

k get svc -n pulsar
NAME                         TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                               AGE
pulsar-mini-bookie           ClusterIP      None             <none>        3181/TCP,8000/TCP                     21h
pulsar-mini-broker           ClusterIP      None             <none>        8080/TCP,6650/TCP                     21h
pulsar-mini-proxy            LoadBalancer   10.102.192.239   localhost     80:30132/TCP,6650:30925/TCP           21h
pulsar-mini-pulsar-manager   LoadBalancer   10.98.70.14      localhost     9527:30322/TCP                        21h
pulsar-mini-toolset          ClusterIP      None             <none>        <none>                                21h
pulsar-mini-zookeeper        ClusterIP      None             <none>        8000/TCP,2888/TCP,3888/TCP,2181/TCP   21h

Output of csrf command, showing that connection is refused from 7750, even if I try to use kubectl port-forward of the pulsar-mini-pulsar-manager pod (though perhaps this isn't the correct way to do it):

% CSRF_TOKEN=$(curl http://localhost:7750/pulsar-manager/csrf-token)
curl \
    -H "X-XSRF-TOKEN: $CSRF_TOKEN" \
    -H "Cookie: XSRF-TOKEN=$CSRF_TOKEN;" \
    -H 'Content-Type: application/json' \
    -X PUT http://localhost:7750/pulsar-manager/users/superuser \
    -d '{"name": "admin", "password": "apachepulsar", "description": "test", "email": "username@test.org"}'
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
curl: (7) Failed to connect to localhost port 7750: Connection refused
curl: (7) Failed to connect to localhost port 7750: Connection refused

When I run the bin/pulsar-admin commands from my local machine, things work just fine. I simply can't access the commands or the UI for some reason.
Output of some commands below:

$ bin/pulsar-admin topics list-partitioned-topics apache/pulsar
"persistent://apache/pulsar/test-topic"
/apache-pulsar-2.9.1
$ bin/pulsar-admin namespaces list apache
"apache/pulsar"
"apache/tester"
$ bin/pulsar-admin topics create-partitioned-topic apache/pulsar/test-topic-2 -p 4
$ bin/pulsar-admin topics list-partitioned-topics apache/pulsar
"persistent://apache/pulsar/test-topic"
"persistent://apache/pulsar/test-topic-2"


问:
How do I get the domain originating the request (of the front-end) in NestJS
My question is similar to the following: How do I get the domain originating the request in express.js? but I'm using NestJS.
I found that there might be a good answer for express.js, but I cannot apply it on NestJS (req.origin is undefined).

Could anyone help me with this?
Thank you in advance.

答:
In the controller use the @Req() decorator to access the request object and req.get('origin') will give you the domain from which the request originated</p>
```<code>    @Get()
    async testAPIKey(@Req() req, @Headers() headers) {
       const origin = req.get('origin');
       console.log(origin) // This will return the origin.
    }
</code>```

Body:
In the controller use the @Req() decorator to access the request object and req.get('origin') will give you the domain from which the request originated

    @Get()
    async testAPIKey(@Req() req, @Headers() headers) {
       const origin = req.get('origin');
       console.log(origin) // This will return the origin.
    }


问:
I am unable to create user with email and password with firebase
I am trying to create user with email and password and then store their details if the task is successful in firebase database for reference purpose but I don't know what happen. The progressDialog keeps loading without creating the user. Here is the code. Please I will appreciate if anyone can put me through on it</p>
```<code>private void registerSeller() {
  String sellerName = name.getText().toString();
  String phoneNumber = phone.getText().toString();
  String sellerEmail = email.getText().toString();
  String sellerPassword = password.getText().toString();
  String sellerAddress = address.getText().toString();

  if (sellerName.isEmpty()) {
    name.setError("Please Enter Your Name");
    `enter code here`
    cancel = true;
    name.requestFocus();
  } else if (phoneNumber.isEmpty()) {
    phone.setError("Please Enter Your Phone Number");
    cancel = true;
    phone.requestFocus();
  } else if (sellerEmail.isEmpty()) {
    email.setError("Please Enter Your Email Address");
    cancel = true;
    email.requestFocus();
  } else if (sellerPassword.isEmpty()) {
    password.setError("Please Enter Your Password");
    cancel = true;
    password.requestFocus();
  } else if (sellerAddress.isEmpty()) {
    address.setError("Please Enter Your Shop Address");
    cancel = true;
    address.requestFocus();
  } else {
    loadingDialog.setTitle("Registration Processing...");
    loadingDialog.setMessage("Please wait while we are checking your credentials");
    loadingDialog.setCanceledOnTouchOutside(false);
    loadingDialog.show();
    mAuth.createUserWithEmailAndPassword(sellerEmail, sellerPassword)
      .addOnCompleteListener(new OnCompleteListener < AuthResult > () {
        @Override
        public void onComplete(@NonNull Task < AuthResult > task) {
          if (task.isSuccessful()) {
            final DatabaseReference sellerRef = FirebaseDatabase.getInstance().getReference();
            FirebaseUser user = mAuth.getCurrentUser();
            String sid = mAuth.getCurrentUser().getUid();

            HashMap < String, Object > sellerMap = new HashMap < > ();
            sellerMap.put("sid", sid);
            sellerMap.put("name", sellerName);
            sellerMap.put("phone", phoneNumber);
            sellerMap.put("email", sellerEmail);
            sellerMap.put("password", sellerPassword);
            sellerMap.put("address", sellerAddress);
            sellerRef.child("sellers").child(sid)
              .updateChildren(sellerMap)
              .addOnCompleteListener(new OnCompleteListener < Void > () {
                @Override
                public void onComplete(@NonNull Task < Void > task) {
                  if (task.isSuccessful()) {

                    loadingDialog.dismiss();
                    Toast.makeText(SellerRegistrationActivity.this, "Seller Registered Successfully", Toast.LENGTH_SHORT).show();
                    Intent intent = new Intent(SellerRegistrationActivity.this, SellerLoginActivity.class);
                    startActivity(intent);
                  } else {
                    loadingDialog.dismiss();
                    Toast.makeText(SellerRegistrationActivity.this, "Error Occurred", Toast.LENGTH_SHORT).show();
                  }
                }
              });

        }
      });
  }
}
</code>```

答:
The first step in troubleshooting is to stop ignoring potential errors. If a Task fails, it has an exception that explains what caused it to fail. You should log or raise that exception, to find the root cause:

```<code>mAuth.createUserWithEmailAndPassword(sellerEmail, sellerPassword)
  .addOnCompleteListener(new OnCompleteListener < AuthResult > () {
    @Override
    public void onComplete(@NonNull Task < AuthResult > task) {
      if (task.isSuccessful()) {
          ...
      }
      else {
          throw task.getException();
      }
    }
</code>```

Body:
I am trying to create user with email and password and then store their details if the task is successful in firebase database for reference purpose but I don't know what happen. The progressDialog keeps loading without creating the user. Here is the code. Please I will appreciate if anyone can put me through on it

private void registerSeller() {
  String sellerName = name.getText().toString();
  String phoneNumber = phone.getText().toString();
  String sellerEmail = email.getText().toString();
  String sellerPassword = password.getText().toString();
  String sellerAddress = address.getText().toString();

  if (sellerName.isEmpty()) {
    name.setError("Please Enter Your Name");
    `enter code here`
    cancel = true;
    name.requestFocus();
  } else if (phoneNumber.isEmpty()) {
    phone.setError("Please Enter Your Phone Number");
    cancel = true;
    phone.requestFocus();
  } else if (sellerEmail.isEmpty()) {
    email.setError("Please Enter Your Email Address");
    cancel = true;
    email.requestFocus();
  } else if (sellerPassword.isEmpty()) {
    password.setError("Please Enter Your Password");
    cancel = true;
    password.requestFocus();
  } else if (sellerAddress.isEmpty()) {
    address.setError("Please Enter Your Shop Address");
    cancel = true;
    address.requestFocus();
  } else {
    loadingDialog.setTitle("Registration Processing...");
    loadingDialog.setMessage("Please wait while we are checking your credentials");
    loadingDialog.setCanceledOnTouchOutside(false);
    loadingDialog.show();
    mAuth.createUserWithEmailAndPassword(sellerEmail, sellerPassword)
      .addOnCompleteListener(new OnCompleteListener < AuthResult > () {
        @Override
        public void onComplete(@NonNull Task < AuthResult > task) {
          if (task.isSuccessful()) {
            final DatabaseReference sellerRef = FirebaseDatabase.getInstance().getReference();
            FirebaseUser user = mAuth.getCurrentUser();
            String sid = mAuth.getCurrentUser().getUid();

            HashMap < String, Object > sellerMap = new HashMap < > ();
            sellerMap.put("sid", sid);
            sellerMap.put("name", sellerName);
            sellerMap.put("phone", phoneNumber);
            sellerMap.put("email", sellerEmail);
            sellerMap.put("password", sellerPassword);
            sellerMap.put("address", sellerAddress);
            sellerRef.child("sellers").child(sid)
              .updateChildren(sellerMap)
              .addOnCompleteListener(new OnCompleteListener < Void > () {
                @Override
                public void onComplete(@NonNull Task < Void > task) {
                  if (task.isSuccessful()) {

                    loadingDialog.dismiss();
                    Toast.makeText(SellerRegistrationActivity.this, "Seller Registered Successfully", Toast.LENGTH_SHORT).show();
                    Intent intent = new Intent(SellerRegistrationActivity.this, SellerLoginActivity.class);
                    startActivity(intent);
                  } else {
                    loadingDialog.dismiss();
                    Toast.makeText(SellerRegistrationActivity.this, "Error Occurred", Toast.LENGTH_SHORT).show();
                  }
                }
              });

        }
      });
  }
}

Body:
The first step in troubleshooting is to stop ignoring potential errors. If a Task fails, it has an exception that explains what caused it to fail. You should log or raise that exception, to find the root cause:

mAuth.createUserWithEmailAndPassword(sellerEmail, sellerPassword)
  .addOnCompleteListener(new OnCompleteListener < AuthResult > () {
    @Override
    public void onComplete(@NonNull Task < AuthResult > task) {
      if (task.isSuccessful()) {
          ...
      }
      else {
          throw task.getException();
      }
    }


问:
Google App Script User Scope Approval for new scope
I've added the script.external_request scope to my GMail Add-on so that I can connect to and store information in a MySQL dB.

The scope was submitted and approved by Google OAuth and Marketplace SDK.

If I run the script in the editor from the HEAD deployment, I get the OAuth approval workflow and the script connects to the database.

In the deployed version I keep getting the following error:

You do not have permission to call Jdbc.getConnection. Required permissions: https://www.googleapis.com/auth/script.external_request

It seems to me that the end users are not getting a trigger to accept the new scope from the UI of the addon.

Is there a way to force the OAuth workflow re-authorization from the addon UI?

Or is there something else going on here?

ADDED INFO

I used Aaron's suggestion on the QuickStart to add a logging check to see if the required permissions are present. At least this will point to if this might be a red-herring.

```<code>    if (authInfo.getAuthorizationStatus() ==
    ScriptApp.AuthorizationStatus.REQUIRED) {
        Logger.log(`${user} - Missing required scope authorizations`)
    }else{
        Logger.log(`${user} - Required scope authorizations present`)
    }
</code>```

Naturally in the 12hrs this has been present, no user has opened the app. So will have to report back later.

Also adding my appscript.json manifest

```<code>  "timeZone": "America/New_York",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "GMailAddOn",
      "logoUrl": "https://lh3.googleusercontent.com/...",
      "layoutProperties": {
        "primaryColor": "#2772ed"
      },
      "useLocaleFromApp": true
    },
    "gmail": {
      "homepageTrigger": {
        "enabled": true,
        "runFunction": "initApp"
      }
    }
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.addons.execute",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile",
    "https://www.googleapis.com/auth/script.send_mail",
    "https://www.googleapis.com/auth/script.locale",
    "https://www.googleapis.com/auth/script.scriptapp",
    "https://www.googleapis.com/auth/gmail.modify",
    "https://www.googleapis.com/auth/script.external_request"
  ],
  "urlFetchWhitelist": [
    "https://google.com/"
  ]
}
</code>```

答:
So after a lot of hair pulling and digging, I believe I found the answer and it comes from a UI/UX issue with Google Marketplace SDK. When a new scope is added to already published Marketplace Addon on the Marketplace SDK App Configuration needs to be updated. I knew this and took care of it on 2/6 at about 2pm EST and hit save. Great, process done.... not so fast.

Errors continued in the logs through mid-day on 2/7 then stopped, but unfortunately so did new downloads volume from Marketplace, which is the trigger for the transaction. So I had no live transactions to monitor. Until 2/9, a new transaction posted and it was suddenly successful.

Because of the gap between working in the editor and not working in the deployment, my hypothesis is that there is an opaque, offline background process for Google Marketplace SDK to approve the new scopes for a published addon.

(MMQB: I probably could have been more thorough in my testing by uninstalling and reinstalling the app from test account to expose this gap, lesson learned)

Google's OAuth scope approval process is transparent as to when the new scope is pending or approved. Google Marketplace's is not. I never received any notification that an approval was pending or had been approved/rejected.

NB: Marketplace SDK approval is in addition to the OAuth scope approval and can't take place until the OAuth approval is complete.

Body:
I've added the script.external_request scope to my GMail Add-on so that I can connect to and store information in a MySQL dB.

The scope was submitted and approved by Google OAuth and Marketplace SDK.

If I run the script in the editor from the HEAD deployment, I get the OAuth approval workflow and the script connects to the database.

In the deployed version I keep getting the following error:

You do not have permission to call Jdbc.getConnection. Required permissions: https://www.googleapis.com/auth/script.external_request

It seems to me that the end users are not getting a trigger to accept the new scope from the UI of the addon.

Is there a way to force the OAuth workflow re-authorization from the addon UI?

Or is there something else going on here?

ADDED INFO

I used Aaron's suggestion on the QuickStart to add a logging check to see if the required permissions are present. At least this will point to if this might be a red-herring.

    if (authInfo.getAuthorizationStatus() ==
    ScriptApp.AuthorizationStatus.REQUIRED) {
        Logger.log(`${user} - Missing required scope authorizations`)
    }else{
        Logger.log(`${user} - Required scope authorizations present`)
    }

Naturally in the 12hrs this has been present, no user has opened the app. So will have to report back later.

Also adding my appscript.json manifest

  "timeZone": "America/New_York",
  "runtimeVersion": "V8",
  "addOns": {
    "common": {
      "name": "GMailAddOn",
      "logoUrl": "https://lh3.googleusercontent.com/...",
      "layoutProperties": {
        "primaryColor": "#2772ed"
      },
      "useLocaleFromApp": true
    },
    "gmail": {
      "homepageTrigger": {
        "enabled": true,
        "runFunction": "initApp"
      }
    }
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": [
    "https://www.googleapis.com/auth/gmail.addons.execute",
    "https://www.googleapis.com/auth/userinfo.email",
    "https://www.googleapis.com/auth/userinfo.profile",
    "https://www.googleapis.com/auth/script.send_mail",
    "https://www.googleapis.com/auth/script.locale",
    "https://www.googleapis.com/auth/script.scriptapp",
    "https://www.googleapis.com/auth/gmail.modify",
    "https://www.googleapis.com/auth/script.external_request"
  ],
  "urlFetchWhitelist": [
    "https://google.com/"
  ]
}


问:
Getting CruiseControl.NET to use output from long-running task when displaying "Activity"
In CruiseControl.NET, I have two projects set up, one for building and one for deploying build packages.

Our build is largely based around MSBuild, and as it runs the dashboard constantly updates with the latest output from the build. This means that even though a full build may take 15 minutes, you can see exactly where it is, and that it's making progress.

The deploy is run using another tool (VisualBuild, though I'm see the same basic behaviour with other tools like PowerShell).  This is another long-running task, but in this case the dashboard is not updated with its output as it progresses.  Since a deploy may take a long time, it's hard to tell whether things are progressing or if things have stalled.  The output is getting logged to the CruiseControl.NET log, and will display on the dashboard once things are done, but not while the deploy is in progress.

Is there a way to get output from other arbitrary long-running tasks updated on the dashboard in something resembling real time? What makes MSBuild special in this regard?

答:
CruiseControl.Net, since version 1.4, includes support for build listener files: it's a mechanism which allows tracking the execution of long-running tasks by reading from a log file. While this mechanism is generic, and can be used with any tool, CruiseControl.Net by itself ships only with build listeners for MSBuild and NAnt (which means that for those two tools progress is reported automatically, without the need for extra configuration).

For an external tool, such as VisualBuild, called by <exec> task, you would have to plug in your own logger that creates a simple progress file:

```<code><data>
  <Item Time="2007-10-14 08:43:12" Data="Starting Build timetester" />
  <Item Time="2007-10-14 08:43:16" Data="Starting Target build" />
  <Item Time="2007-10-14 08:43:16" Data="Sleeping for 5000 milliseconds." />
</data>
</code>```

in the location pointed to by the CCNetListenerFile environment variable.

Body:
CruiseControl.Net, since version 1.4, includes support for build listener files: it's a mechanism which allows tracking the execution of long-running tasks by reading from a log file. While this mechanism is generic, and can be used with any tool, CruiseControl.Net by itself ships only with build listeners for MSBuild and NAnt (which means that for those two tools progress is reported automatically, without the need for extra configuration).

For an external tool, such as VisualBuild, called by <exec> task, you would have to plug in your own logger that creates a simple progress file:

<data>
  <Item Time="2007-10-14 08:43:12" Data="Starting Build timetester" />
  <Item Time="2007-10-14 08:43:16" Data="Starting Target build" />
  <Item Time="2007-10-14 08:43:16" Data="Sleeping for 5000 milliseconds." />
</data>

in the location pointed to by the CCNetListenerFile environment variable.


问:
Tukey's significance letters for each group
I'd like to add letters to show significant differences onto a ggplot.

This is my data frame, which has basal area (y-axis), treatment (x-axis), survey year (group) and L which are the letters derived from a Tukey's post hoc test from a glmer with an interaction between treatment and year.

```<code>hab <- structure(list(survey_year = structure(c(1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("2019",
"2021"), class = "factor"), treatment = c("Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular"), basal_area = c(42, 42, 38, 36, 36,
51, 28, 30, 58, 38, 24, 32, 30, 36, 28, 28, 30, 28, 30, 26, 28,
28, 28, 36, 30, 22, 24, 22, 22, 20, 16, 18, 40, 18, 38, 38, 56,
44, 44, 42, 38, 38, 42, 34, 42, 36, 38, 36, 28, 46, 34, 44, 36,
60, 32, 52, 24, 34, 30, 32, 32, 30, 34, 34, 28, 30, 26, 28, 24,
32, 26, 20, 36, 38, 48, 36, 28, 28, 38, 34, 38, 40, 38, 34, 28,
40, 26, 32, 40, 36, 36, 36, 30, 26, 24, 16, 22, 24, 32, 22, 16,
26, 26, 26, 18, 22, 16, 30, 32, 22, 26, 26, 18, 22, 18, 24, 44,
24, 18, 18, 26, 36, 26, 14, 14, 20, 16, 16), L = c("c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "ac", "ac", "ac", "ac",
"ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac",
"ab", "ab", "ab", "ab", "ab", "ab", "ab", "ab", "ab", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "b", "b", "b", "b", "b", "b", "b", "b",
"b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b",
"b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b",
"b")), class = "data.frame", row.names = c(NA, -128L))
</code>```

This is the plot and associated code I have so far, which has basal area on the y-axis, treatment on the x-axis and the letters showing significance. But the letters are not grouped by survey year. Is there a way I can do this?

```<code>maxy <- 66 # set where I want the letters to be on the y-axis
ggplot(hab, aes(x=treatment, y = basal_area, colour=survey_year)) +
  geom_boxplot(outlier.shape = NA, fill="white", outlier.colour=NA, position=position_dodge(width=0.9)) +
  geom_point(position=position_jitterdodge()) +
  geom_text(aes(x=treatment, y = maxy, label = L, group=survey_year)) +
  ylab("Basal area")+
  xlab("Treatment") +
  theme_classic()
</code>```

As you can see the plot doesn't separate the letters by survey year, as Early Transitioning Irregular should have letters ac for 2019 and c for 2021, but right now they are overlapping.

Any ideas how to fix this?

Thanks!

答:
You need to also specify position = position_dodge(width = 0.9) to geom_text().

```<code>library(tidyverse)

ggplot(hab, aes(treatment,
                basal_area,
                colour = survey_year,
                label = L)) +
  geom_boxplot(outlier.shape = NA,
               fill = "white",
               outlier.colour = NA,
               position = position_dodge(width = 0.9)) +
  geom_point(position = position_jitterdodge()) +
  geom_text(aes(y = maxy,
                group = survey_year),
            check_overlap = T,
            position = position_dodge(width = 0.9), col = "black") +
  ylab("Basal area") +
  xlab("Treatment") +
  theme_classic()
</code>```

Body:
I'd like to add letters to show significant differences onto a ggplot.

This is my data frame, which has basal area (y-axis), treatment (x-axis), survey year (group) and L which are the letters derived from a Tukey's post hoc test from a glmer with an interaction between treatment and year.

hab <- structure(list(survey_year = structure(c(1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L,
1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), .Label = c("2019",
"2021"), class = "factor"), treatment = c("Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell", "Clear Fell",
"Clear Fell", "Clear Fell", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Early Transitioning Irregular",
"Early Transitioning Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular", "Irregular", "Irregular", "Irregular",
"Irregular", "Irregular"), basal_area = c(42, 42, 38, 36, 36,
51, 28, 30, 58, 38, 24, 32, 30, 36, 28, 28, 30, 28, 30, 26, 28,
28, 28, 36, 30, 22, 24, 22, 22, 20, 16, 18, 40, 18, 38, 38, 56,
44, 44, 42, 38, 38, 42, 34, 42, 36, 38, 36, 28, 46, 34, 44, 36,
60, 32, 52, 24, 34, 30, 32, 32, 30, 34, 34, 28, 30, 26, 28, 24,
32, 26, 20, 36, 38, 48, 36, 28, 28, 38, 34, 38, 40, 38, 34, 28,
40, 26, 32, 40, 36, 36, 36, 30, 26, 24, 16, 22, 24, 32, 22, 16,
26, 26, 26, 18, 22, 16, 30, 32, 22, 26, 26, 18, 22, 18, 24, 44,
24, 18, 18, 26, 36, 26, 14, 14, 20, 16, 16), L = c("c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "ac", "ac", "ac", "ac",
"ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac", "ac",
"ab", "ab", "ab", "ab", "ab", "ab", "ab", "ab", "ab", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c", "c",
"c", "c", "c", "c", "c", "b", "b", "b", "b", "b", "b", "b", "b",
"b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b",
"b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b", "b",
"b")), class = "data.frame", row.names = c(NA, -128L))

This is the plot and associated code I have so far, which has basal area on the y-axis, treatment on the x-axis and the letters showing significance. But the letters are not grouped by survey year. Is there a way I can do this?

maxy <- 66 # set where I want the letters to be on the y-axis
ggplot(hab, aes(x=treatment, y = basal_area, colour=survey_year)) +
  geom_boxplot(outlier.shape = NA, fill="white", outlier.colour=NA, position=position_dodge(width=0.9)) +
  geom_point(position=position_jitterdodge()) +
  geom_text(aes(x=treatment, y = maxy, label = L, group=survey_year)) +
  ylab("Basal area")+
  xlab("Treatment") +
  theme_classic()

As you can see the plot doesn't separate the letters by survey year, as Early Transitioning Irregular should have letters ac for 2019 and c for 2021, but right now they are overlapping.

Any ideas how to fix this?

Thanks!

Body:
You need to also specify position = position_dodge(width = 0.9) to geom_text().

library(tidyverse)

ggplot(hab, aes(treatment,
                basal_area,
                colour = survey_year,
                label = L)) +
  geom_boxplot(outlier.shape = NA,
               fill = "white",
               outlier.colour = NA,
               position = position_dodge(width = 0.9)) +
  geom_point(position = position_jitterdodge()) +
  geom_text(aes(y = maxy,
                group = survey_year),
            check_overlap = T,
            position = position_dodge(width = 0.9), col = "black") +
  ylab("Basal area") +
  xlab("Treatment") +
  theme_classic()


问:
len function gives two excess length
i have my length  function to calculate the length of array, but it is giving two excess garbage numbers(negative). It must return 6 but it returns 8 due to garbage values.</p>
```<code>#include<stdio.h>

int length(int *arr) {
    int _length = 0;
    while (*arr) {
        _length++;
        arr++;
    }
    return _length;
}

int main() {
    int arr[] = {2, 1, 3, 4, 5, 6};
    printf("%d\n", length(arr));
    return 0;
}
</code>```

答:
You need some manner of termination condition. while (*arr) assumes that the array ends with zero which isn't the case, so you simply can't have a loop like that.

The size of this array is known at compile time so there's no need to calculate anything in run-time.

(sizeof arr / sizeof *arr) gives you the number of items in the array, as long as you place that code in the same scope as the array declaration.

Also, using that sizeof trick (which is an idiomatic way of determining the size) inside a function-like macro is a common solution:

```<code>#include <stdio.h>

#define length(arr) (sizeof(arr)/sizeof(*arr))

int main() {
    int arr[] = {2, 1, 3, 4, 5, 6};
    printf("%zu\n", length(arr));
    return 0;
}
</code>```

Title: len function gives two excess length

Body:
i have my length  function to calculate the length of array, but it is giving two excess garbage numbers(negative). It must return 6 but it returns 8 due to garbage values.

#include<stdio.h>

int length(int *arr) {
    int _length = 0;
    while (*arr) {
        _length++;
        arr++;
    }
    return _length;
}

int main() {
    int arr[] = {2, 1, 3, 4, 5, 6};
    printf("%d\n", length(arr));
    return 0;
}

Body:
You need some manner of termination condition. while (*arr) assumes that the array ends with zero which isn't the case, so you simply can't have a loop like that.

The size of this array is known at compile time so there's no need to calculate anything in run-time.

(sizeof arr / sizeof *arr) gives you the number of items in the array, as long as you place that code in the same scope as the array declaration.

Also, using that sizeof trick (which is an idiomatic way of determining the size) inside a function-like macro is a common solution:

#include <stdio.h>

#define length(arr) (sizeof(arr)/sizeof(*arr))

int main() {
    int arr[] = {2, 1, 3, 4, 5, 6};
    printf("%zu\n", length(arr));
    return 0;
}


问:
Laravel Mix generate fonts into another directory
I'm using laravel-mix which is built on the top of the webpack. I'm facing a problem with fonts directory. For Example, font-awesome package has a scss file and a font directory where all fonts are placed.

```<code>font-awesome:.
├───scss
│       fontawesome.scss
└───webfonts
        fa-regular-400.eot
        fa-regular-400.svg
        fa-regular-400.ttf
        fa-regular-400.woff
        fa-regular-400.woff2
</code>```

So i place this package in my resources/assets/sass directory.

```<code>resources:.
└───asset
    └───sass
        │   main.scss
        │
        └───font-awesome (directory)
</code>```

main.scss contains code:

```<code>@import 'font-awesome/scss/fontawesome';
</code>```

webpack.mix.js contains:

```<code>mix.sass('resources/assets/sass/main.scss', 'public/css/frontend.css');
</code>```

All assets are compiled successfully. Now public directory has a css and font directory, which has all fonts like this.

```<code>public:.
│   index.php
│
├───css
│       frontend.css
│
├───fonts
│       fa-regular-400.eot
│       fa-regular-400.svg
│       fa-regular-400.ttf
│       fa-regular-400.woff
│       fa-regular-400.woff2
</code>```

But What I want is, I don't want to compile all fonts into public/fonts directory i want to compile as following structure public/fonts/vendor/font-awesome

```<code>public:.
├───css
│       frontend.css
│
└───fonts
    └───vendor
        └───font-awesome
                fa-regular-400.eot
                fa-regular-400.svg
                fa-regular-400.ttf
                fa-regular-400.woff
                fa-regular-400.woff2
</code>```

What changes that i need to change in webpack.mix.js file.

答:
Mix options have changed. Use instead:

mix.options({
    fileLoaderDirs:  {
        fonts: 'assets/fonts'
    }
});
```

Body:
I'm using laravel-mix which is built on the top of the webpack. I'm facing a problem with fonts directory. For Example, font-awesome package has a scss file and a font directory where all fonts are placed.

font-awesome:.
├───scss
│       fontawesome.scss
└───webfonts
        fa-regular-400.eot
        fa-regular-400.svg
        fa-regular-400.ttf
        fa-regular-400.woff
        fa-regular-400.woff2

So i place this package in my resources/assets/sass directory.

resources:.
└───asset
    └───sass
        │   main.scss
        │
        └───font-awesome (directory)

main.scss contains code:

@import 'font-awesome/scss/fontawesome';

webpack.mix.js contains:

mix.sass('resources/assets/sass/main.scss', 'public/css/frontend.css');

All assets are compiled successfully. Now public directory has a css and font directory, which has all fonts like this.

public:.
│   index.php
│
├───css
│       frontend.css
│
├───fonts
│       fa-regular-400.eot
│       fa-regular-400.svg
│       fa-regular-400.ttf
│       fa-regular-400.woff
│       fa-regular-400.woff2

But What I want is, I don't want to compile all fonts into public/fonts directory i want to compile as following structure public/fonts/vendor/font-awesome

public:.
├───css
│       frontend.css
│
└───fonts
    └───vendor
        └───font-awesome
                fa-regular-400.eot
                fa-regular-400.svg
                fa-regular-400.ttf
                fa-regular-400.woff
                fa-regular-400.woff2

What changes that i need to change in webpack.mix.js file.


问:
how do you change the php version that your app uses in heroku platform?
I am trying to change the PHP version that my heroku application uses from the default 7.1 to 7.0. When I try to define it in composer.json it is ignored. What do I need to do?

答: Yo dont need to downgrade the heroku stack to 18 or anything, You can just change the required version of PHP in composer.json then run composer update against your project and finally deploy /build it to the cloud</p>


问:
Illegal State Exception in mediaplayer.prepare android
I am using a method in asynctask in the class VideoSurfaceView.

But I am getting crash.

I tried other ways too but didn't worked. Below is the code:

......

```<code>     public class VideoSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "VideoSurfaceView";

    private MediaPlayer mMediaPlayer;

    private String mVideoPath = "";
    private ScreenSaverView.OnVideoPrepareListener onVideoPrepareListener;

    private Bitmap mPreviewBitmap;

    private boolean locking = false;
    private boolean lockResult = false;
    private boolean reading = false;

    public VideoSurfaceView(Context context) {
        super(context);
        init();
    }

    private void init() {
        LogD.i(TAG, "init");
        SurfaceHolder mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        LogD.i(TAG, "surfaceCreated");
        if (!getVideoPath().isEmpty()) {
            initVideoPlayer();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        LogD.i(TAG, "surfaceChanged");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        LogD.i(TAG, "surfaceDestroyed");
        if (mMediaPlayer != null) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.stop();
            }
            mMediaPlayer.release();
            mMediaPlayer = null;
        }

    }

    private void initVideoPlayer() {
        Canvas canvas = getHolder().lockCanvas();
        if (mPreviewBitmap != null && canvas != null) {
            int w = getWidth();
            int h = getHeight();
            Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
            Rect dst = new Rect(0, 0, w, h);
            LogD.d(TAG, "drawFirstFrame:view w: " + getWidth() + " h:" + getHeight());
            canvas.drawBitmap(mPreviewBitmap, src, dst, null);
            getHolder().unlockCanvasAndPost(canvas);
        } else if (canvas != null){
            canvas.drawColor(Color.WHITE);
            getHolder().unlockCanvasAndPost(canvas);
        }

        boolean needClose = onVideoPrepareListener.onPrepare();
        if (needClose) {
            LogD.d(TAG, "initVideoPlayer needClose return: ");
            return;
        }

        LogD.i(TAG, "initFirstPlayer()");
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setVolume(0, 0);
        mMediaPlayer.setDisplay(getHolder());
        startPlayFirstVideo();
    }

    private void startPlayFirstVideo() {

        new AsyncTask<Void, Void, FileCacheMediaDataSource>() {

            @Override
            protected FileCacheMediaDataSource doInBackground(Void... voids) {
                locking = true;
                lockResult = false;
                reading = true;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        LockResult result = LockManager.getInstance().lock(LockReason.DISK_SCREENSAVER_READ_ACCESS);
                        lockResult = result.isLockSuccess();
                        if (!reading && lockResult) {
                            LockManager.getInstance().unlock(LockReason.DISK_SCREENSAVER_READ_ACCESS);
                        }
                        locking = false;
                    }
                }).start();

                String path = AppConst.SCREEN_SAVER_MEDIA_PATH + mVideoPath;
                FileCacheMediaDataSource dataSource = new FileCacheMediaDataSource(path);
                if (!locking && lockResult) {
                    LockManager.getInstance().unlock(LockReason.DISK_SCREENSAVER_READ_ACCESS);
                }
                reading = false;

                return dataSource;
            }

            @Override
            protected void onPostExecute(FileCacheMediaDataSource dataSource) {
                super.onPostExecute(dataSource);
                if (mMediaPlayer == null) {
                    return;
                }
                if (dataSource.getSize() == -1) {
                    LogD.d(TAG, "showErrorScreenSaver");
                    screenSaverError();
                    return;
                }
                try {
                    // stop and reset media player
                    mMediaPlayer.stop();
                    mMediaPlayer.reset();
                    mMediaPlayer.setDataSource(dataSource);
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mMediaPlayer.start();
                        }
                    });
                    mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                        @Override
                        public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
                            return false;
                        }
                    });
                    mMediaPlayer.prepare();
                } catch (IOException e) {
                    LogD.i(TAG, "startPlayFirstVideo = " + e.toString());
                }
            }
        };
    }

    private void screenSaverError() {
        if (videoSurfaceCallBack != null) {
            videoSurfaceCallBack.onError();
        }
    }

    public String getVideoPath() {
        return mVideoPath;
    }

    public void setOnVideoPrepareListener(ScreenSaverView.OnVideoPrepareListener onVideoPrepareListener) {
        this.onVideoPrepareListener = onVideoPrepareListener;
    }

    public void setPreviewBitmap(Bitmap bitmap){
        mPreviewBitmap = bitmap;
    }

    public void setVideoPath(String videoPath) {
        mVideoPath = videoPath;

        Bitmap bitmap = mPreviewBitmap;
        if (bitmap != null) {
            int videoWidth = bitmap.getWidth();
            int videoHeight = bitmap.getHeight();
            float max = Math.max((float) videoWidth / (float) 1024,(float) videoHeight / (float) 520);
            videoWidth = (int) Math.ceil((float) videoWidth / max);
            videoHeight = (int) Math.ceil((float) videoHeight / max);
            LogD.d(TAG, "setVideoPath LayoutParams videoWidth:"+videoWidth+" videoHeight:"+videoHeight);
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(videoWidth, videoHeight);
            layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
            setLayoutParams(layoutParams);
        }
    }

    private VideoSurfaceCallBack videoSurfaceCallBack;

    public void setVideoSurfaceCallBack(VideoSurfaceCallBack videoSurfaceCallBack) {
        this.videoSurfaceCallBack = videoSurfaceCallBack;
    }

    interface VideoSurfaceCallBack {
        void onError();
    }
}
</code>```

I am getting error as,

```<code>   12-23 08:28:11.108  7759  7759 E AndroidRuntime: Process: com.example.custom, PID: 7759
    12-23 08:28:11.108  7759  7759 E AndroidRuntime: java.lang.IllegalStateException
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.media.MediaPlayer._prepare(Native Method)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.media.MediaPlayer.prepare(MediaPlayer.java:1274)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.example.custom.view.VideoSurfaceView$1.onPostExecute(VideoSurfaceView.java:155)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.example.custom.view.VideoSurfaceView$1.onPostExecute(VideoSurfaceView.java:106)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.AsyncTask.finish(AsyncTask.java:755)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.AsyncTask.access$900(AsyncTask.java:192)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:107)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:214)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:7356)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
</code>```

I am getting error in mMediaPlayer.prepare();. Kindly let me know where exactly I need to fix this issue.

I tried using mMeiaPlayer.perpareAsync too but didn't worked.

答:
According to exception, mediaPlayer in wrong state. Since i cannot see how you have defined the mediaPlayer, i assume you reuse the mediaPlayer. If so, make sure to stop and reset mediaPlayer before set a new dataSource like following in onPostExecute;

Read more on here: mediaPlayer

```<code>            @Override
            protected void onPostExecute(FileCacheMediaDataSource dataSource) {
                super.onPostExecute(dataSource);
                if (mMediaPlayer == null) {
                    return;
                }
                if (dataSource.getSize() == -1) {
                    LogD.d(TAG, "showErrorScreenSaver");
                    screenSaverError();
                    return;
                }
                try {
                    // stop and reset media player
                    mMediaPlayer.stop();
                    mMediaPlayer.reset();

                    // set datasource
                    mMediaPlayer.setDataSource(dataSource);
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mp.start();
                        }
                    });
                    mMediaPlayer.prepareAsync();
                } catch (IOException e) {
                    LogD.i(TAG, "startPlayFirstVideo = " + e.toString());
                }
            }
</code>```

Body:
I am using a method in asynctask in the class VideoSurfaceView.

But I am getting crash.

I tried other ways too but didn't worked. Below is the code:

......

     public class VideoSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "VideoSurfaceView";

    private MediaPlayer mMediaPlayer;

    private String mVideoPath = "";
    private ScreenSaverView.OnVideoPrepareListener onVideoPrepareListener;

    private Bitmap mPreviewBitmap;

    private boolean locking = false;
    private boolean lockResult = false;
    private boolean reading = false;

    public VideoSurfaceView(Context context) {
        super(context);
        init();
    }

    private void init() {
        LogD.i(TAG, "init");
        SurfaceHolder mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        LogD.i(TAG, "surfaceCreated");
        if (!getVideoPath().isEmpty()) {
            initVideoPlayer();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        LogD.i(TAG, "surfaceChanged");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        LogD.i(TAG, "surfaceDestroyed");
        if (mMediaPlayer != null) {
            if (mMediaPlayer.isPlaying()) {
                mMediaPlayer.stop();
            }
            mMediaPlayer.release();
            mMediaPlayer = null;
        }

    }

    private void initVideoPlayer() {
        Canvas canvas = getHolder().lockCanvas();
        if (mPreviewBitmap != null && canvas != null) {
            int w = getWidth();
            int h = getHeight();
            Rect src = new Rect(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
            Rect dst = new Rect(0, 0, w, h);
            LogD.d(TAG, "drawFirstFrame:view w: " + getWidth() + " h:" + getHeight());
            canvas.drawBitmap(mPreviewBitmap, src, dst, null);
            getHolder().unlockCanvasAndPost(canvas);
        } else if (canvas != null){
            canvas.drawColor(Color.WHITE);
            getHolder().unlockCanvasAndPost(canvas);
        }

        boolean needClose = onVideoPrepareListener.onPrepare();
        if (needClose) {
            LogD.d(TAG, "initVideoPlayer needClose return: ");
            return;
        }

        LogD.i(TAG, "initFirstPlayer()");
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setVolume(0, 0);
        mMediaPlayer.setDisplay(getHolder());
        startPlayFirstVideo();
    }

    private void startPlayFirstVideo() {

        new AsyncTask<Void, Void, FileCacheMediaDataSource>() {

            @Override
            protected FileCacheMediaDataSource doInBackground(Void... voids) {
                locking = true;
                lockResult = false;
                reading = true;
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        LockResult result = LockManager.getInstance().lock(LockReason.DISK_SCREENSAVER_READ_ACCESS);
                        lockResult = result.isLockSuccess();
                        if (!reading && lockResult) {
                            LockManager.getInstance().unlock(LockReason.DISK_SCREENSAVER_READ_ACCESS);
                        }
                        locking = false;
                    }
                }).start();

                String path = AppConst.SCREEN_SAVER_MEDIA_PATH + mVideoPath;
                FileCacheMediaDataSource dataSource = new FileCacheMediaDataSource(path);
                if (!locking && lockResult) {
                    LockManager.getInstance().unlock(LockReason.DISK_SCREENSAVER_READ_ACCESS);
                }
                reading = false;

                return dataSource;
            }

            @Override
            protected void onPostExecute(FileCacheMediaDataSource dataSource) {
                super.onPostExecute(dataSource);
                if (mMediaPlayer == null) {
                    return;
                }
                if (dataSource.getSize() == -1) {
                    LogD.d(TAG, "showErrorScreenSaver");
                    screenSaverError();
                    return;
                }
                try {
                    // stop and reset media player
                    mMediaPlayer.stop();
                    mMediaPlayer.reset();
                    mMediaPlayer.setDataSource(dataSource);
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mMediaPlayer.start();
                        }
                    });
                    mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                        @Override
                        public boolean onError(MediaPlayer mediaPlayer, int i, int i1) {
                            return false;
                        }
                    });
                    mMediaPlayer.prepare();
                } catch (IOException e) {
                    LogD.i(TAG, "startPlayFirstVideo = " + e.toString());
                }
            }
        };
    }

    private void screenSaverError() {
        if (videoSurfaceCallBack != null) {
            videoSurfaceCallBack.onError();
        }
    }

    public String getVideoPath() {
        return mVideoPath;
    }

    public void setOnVideoPrepareListener(ScreenSaverView.OnVideoPrepareListener onVideoPrepareListener) {
        this.onVideoPrepareListener = onVideoPrepareListener;
    }

    public void setPreviewBitmap(Bitmap bitmap){
        mPreviewBitmap = bitmap;
    }

    public void setVideoPath(String videoPath) {
        mVideoPath = videoPath;

        Bitmap bitmap = mPreviewBitmap;
        if (bitmap != null) {
            int videoWidth = bitmap.getWidth();
            int videoHeight = bitmap.getHeight();
            float max = Math.max((float) videoWidth / (float) 1024,(float) videoHeight / (float) 520);
            videoWidth = (int) Math.ceil((float) videoWidth / max);
            videoHeight = (int) Math.ceil((float) videoHeight / max);
            LogD.d(TAG, "setVideoPath LayoutParams videoWidth:"+videoWidth+" videoHeight:"+videoHeight);
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(videoWidth, videoHeight);
            layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
            setLayoutParams(layoutParams);
        }
    }

    private VideoSurfaceCallBack videoSurfaceCallBack;

    public void setVideoSurfaceCallBack(VideoSurfaceCallBack videoSurfaceCallBack) {
        this.videoSurfaceCallBack = videoSurfaceCallBack;
    }

    interface VideoSurfaceCallBack {
        void onError();
    }
}

I am getting error as,

   12-23 08:28:11.108  7759  7759 E AndroidRuntime: Process: com.example.custom, PID: 7759
    12-23 08:28:11.108  7759  7759 E AndroidRuntime: java.lang.IllegalStateException
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.media.MediaPlayer._prepare(Native Method)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.media.MediaPlayer.prepare(MediaPlayer.java:1274)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.example.custom.view.VideoSurfaceView$1.onPostExecute(VideoSurfaceView.java:155)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.example.custom.view.VideoSurfaceView$1.onPostExecute(VideoSurfaceView.java:106)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.AsyncTask.finish(AsyncTask.java:755)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.AsyncTask.access$900(AsyncTask.java:192)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:772)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.Handler.dispatchMessage(Handler.java:107)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.os.Looper.loop(Looper.java:214)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at android.app.ActivityThread.main(ActivityThread.java:7356)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at java.lang.reflect.Method.invoke(Native Method)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
    12-23 08:28:11.108  7759  7759 E AndroidRuntime:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

I am getting error in mMediaPlayer.prepare();. Kindly let me know where exactly I need to fix this issue.

I tried using mMeiaPlayer.perpareAsync too but didn't worked.

Body:
According to exception, mediaPlayer in wrong state. Since i cannot see how you have defined the mediaPlayer, i assume you reuse the mediaPlayer. If so, make sure to stop and reset mediaPlayer before set a new dataSource like following in onPostExecute;

Read more on here: mediaPlayer

            @Override
            protected void onPostExecute(FileCacheMediaDataSource dataSource) {
                super.onPostExecute(dataSource);
                if (mMediaPlayer == null) {
                    return;
                }
                if (dataSource.getSize() == -1) {
                    LogD.d(TAG, "showErrorScreenSaver");
                    screenSaverError();
                    return;
                }
                try {
                    // stop and reset media player
                    mMediaPlayer.stop();
                    mMediaPlayer.reset();

                    // set datasource
                    mMediaPlayer.setDataSource(dataSource);
                    mMediaPlayer.setLooping(true);
                    mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                        @Override
                        public void onPrepared(MediaPlayer mp) {
                            mp.start();
                        }
                    });
                    mMediaPlayer.prepareAsync();
                } catch (IOException e) {
                    LogD.i(TAG, "startPlayFirstVideo = " + e.toString());
                }
            }