问:
Multiple canActivate guards all run when first fails
I have a route with two canActivate guards (AuthGuard and RoleGuard). The first (AuthGuard) checks to see if the user is logged in and, if not, redirects to the login page. The second checks to see if the user has a role defined that is allowed to view the page and, if not, redirects to the un-authorized page.

```<code>canActivate: [ AuthGuard, RoleGuard ]
...
export class AuthGuard implements CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        ...
        this.router.navigate(['/login']);
        resolve(false);
}

export class RoleGuard implements CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        ...
        this.router.navigate(['/unauthorized']);
        resolve(false);
}
</code>```

The problem is that when I access the route and I am not logged in I hit the AuthGuard, which fails and tells the router to navigate to /login. However, even though the AuthGuard failed, the RoleGuard runs anyway which then navigates to /unauthorized.

In my opinion it is pointless to run the next guard if the first fails. Is there any way to enforce this behavior?

答:
As mentioned by @PierreDuc data property in Route Class along with a Master Guard can be used to solve this problem.

Problem

First of all, angular doesn't support the feature to call the guards in tandem. So if first guard is asynchronous and is trying to make ajax calls, all the remaining guards will get fired even before completion of the ajax request in guard 1.

I faced the similar problem and this is how I solved it -

Solution

The idea is to create a master guard and let the master guard handle the execution of other guards.

The routing configuration in this case, will contain master guard as the only guard.

To let master guard know about the guards to be triggered for specific routes, add a data property in Route.

The data property is a key value pair that allows us to attach data with the routes.

The data can then be accessed in the guards using ActivatedRouteSnapshot parameter of canActivate method in the guard.

The solution looks complicated but it will assure proper working of guards once it is integrated in the application.

Following example explains this approach -

Example

1. Constants Object to map all application guards -

```<code>export const GUARDS = {
    GUARD1: "GUARD1",
    GUARD2: "GUARD2",
    GUARD3: "GUARD3",
    GUARD4: "GUARD4",
}
</code>```

2. Application Guard -

```<code>import { Injectable } from "@angular/core";
import { Guard4DependencyService } from "./guard4dependency";

@Injectable()
export class Guard4 implements CanActivate {
    //A  guard with dependency
    constructor(private _Guard4DependencyService:  Guard4DependencyService) {}

    canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return new Promise((resolve: Function, reject: Function) => {
            //logic of guard 4 here
            if (this._Guard4DependencyService.valid()) {
                resolve(true);
            } else {
                reject(false);
            }
        });
    }
}
</code>```

3. Routing Configuration -

```<code>import { Route } from "@angular/router";
import { View1Component } from "./view1";
import { View2Component } from "./view2";
import { MasterGuard, GUARDS } from "./master-guard";
export const routes: Route[] = [
    {
        path: "view1",
        component: View1Component,
        //attach master guard here
        canActivate: [MasterGuard],
        //this is the data object which will be used by
        //masteer guard to execute guard1 and guard 2
        data: {
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2
            ]
        }
    },
    {
        path: "view2",
        component: View2Component,
        //attach master guard here
        canActivate: [MasterGuard],
        //this is the data object which will be used by
        //masteer guard to execute guard1, guard 2, guard 3 & guard 4
        data: {
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2,
                GUARDS.GUARD3,
                GUARDS.GUARD4
            ]
        }
    }
];
</code>```

4. Master Guard -

```<code>import { Injectable } from "@angular/core";
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";

//import all the guards in the application
import { Guard1 } from "./guard1";
import { Guard2 } from "./guard2";
import { Guard3 } from "./guard3";
import { Guard4 } from "./guard4";

import { Guard4DependencyService } from "./guard4dependency";

@Injectable()
export class MasterGuard implements CanActivate {

    //you may need to include dependencies of individual guards if specified in guard constructor
    constructor(private _Guard4DependencyService:  Guard4DependencyService) {}

    private route: ActivatedRouteSnapshot;
    private state: RouterStateSnapshot;

    //This method gets triggered when the route is hit
    public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {

        this.route = route;
        this.state = state;

        if (!route.data) {
            Promise.resolve(true);
            return;
        }

        //this.route.data.guards is an array of strings set in routing configuration

        if (!this.route.data.guards || !this.route.data.guards.length) {
            Promise.resolve(true);
            return;
        }
        return this.executeGuards();
    }

    //Execute the guards sent in the route data
    private executeGuards(guardIndex: number = 0): Promise<boolean> {
        return this.activateGuard(this.route.data.guards[guardIndex])
            .then(() => {
                if (guardIndex < this.route.data.guards.length - 1) {
                    return this.executeGuards(guardIndex + 1);
                } else {
                    return Promise.resolve(true);
                }
            })
            .catch(() => {
                return Promise.reject(false);
            });
    }

    //Create an instance of the guard and fire canActivate method returning a promise
    private activateGuard(guardKey: string): Promise<boolean> {

        let guard: Guard1 | Guard2 | Guard3 | Guard4;

        switch (guardKey) {
            case GUARDS.GUARD1:
                guard = new Guard1();
                break;
            case GUARDS.GUARD2:
                guard = new Guard2();
                break;
            case GUARDS.GUARD3:
                guard = new Guard3();
                break;
            case GUARDS.GUARD4:
                guard = new Guard4(this._Guard4DependencyService);
                break;
            default:
                break;
        }
        return guard.canActivate(this.route, this.state);
    }
}
</code>```

Challenges

One of the challenges  in this  approach is refactoring of existing routing model. However, it can be done in parts as the changes are non-breaking.

I hope this helps.

Body:
I have a route with two canActivate guards (AuthGuard and RoleGuard). The first (AuthGuard) checks to see if the user is logged in and, if not, redirects to the login page. The second checks to see if the user has a role defined that is allowed to view the page and, if not, redirects to the un-authorized page.

canActivate: [ AuthGuard, RoleGuard ]
...
export class AuthGuard implements CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        ...
        this.router.navigate(['/login']);
        resolve(false);
}

export class RoleGuard implements CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        ...
        this.router.navigate(['/unauthorized']);
        resolve(false);
}

The problem is that when I access the route and I am not logged in I hit the AuthGuard, which fails and tells the router to navigate to /login. However, even though the AuthGuard failed, the RoleGuard runs anyway which then navigates to /unauthorized.

In my opinion it is pointless to run the next guard if the first fails. Is there any way to enforce this behavior?

Body:
As mentioned by @PierreDuc data property in Route Class along with a Master Guard can be used to solve this problem.

Problem

First of all, angular doesn't support the feature to call the guards in tandem. So if first guard is asynchronous and is trying to make ajax calls, all the remaining guards will get fired even before completion of the ajax request in guard 1.

I faced the similar problem and this is how I solved it -

Solution

The idea is to create a master guard and let the master guard handle the execution of other guards.

The routing configuration in this case, will contain master guard as the only guard.

To let master guard know about the guards to be triggered for specific routes, add a data property in Route.

The data property is a key value pair that allows us to attach data with the routes.

The data can then be accessed in the guards using ActivatedRouteSnapshot parameter of canActivate method in the guard.

The solution looks complicated but it will assure proper working of guards once it is integrated in the application.

Following example explains this approach -

Example

1. Constants Object to map all application guards -

export const GUARDS = {
    GUARD1: "GUARD1",
    GUARD2: "GUARD2",
    GUARD3: "GUARD3",
    GUARD4: "GUARD4",
}

2. Application Guard -

import { Injectable } from "@angular/core";
import { Guard4DependencyService } from "./guard4dependency";

@Injectable()
export class Guard4 implements CanActivate {
    //A  guard with dependency
    constructor(private _Guard4DependencyService:  Guard4DependencyService) {}

    canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
        return new Promise((resolve: Function, reject: Function) => {
            //logic of guard 4 here
            if (this._Guard4DependencyService.valid()) {
                resolve(true);
            } else {
                reject(false);
            }
        });
    }
}

3. Routing Configuration -

import { Route } from "@angular/router";
import { View1Component } from "./view1";
import { View2Component } from "./view2";
import { MasterGuard, GUARDS } from "./master-guard";
export const routes: Route[] = [
    {
        path: "view1",
        component: View1Component,
        //attach master guard here
        canActivate: [MasterGuard],
        //this is the data object which will be used by
        //masteer guard to execute guard1 and guard 2
        data: {
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2
            ]
        }
    },
    {
        path: "view2",
        component: View2Component,
        //attach master guard here
        canActivate: [MasterGuard],
        //this is the data object which will be used by
        //masteer guard to execute guard1, guard 2, guard 3 & guard 4
        data: {
            guards: [
                GUARDS.GUARD1,
                GUARDS.GUARD2,
                GUARDS.GUARD3,
                GUARDS.GUARD4
            ]
        }
    }
];

4. Master Guard -

import { Injectable } from "@angular/core";
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from "@angular/router";

//import all the guards in the application
import { Guard1 } from "./guard1";
import { Guard2 } from "./guard2";
import { Guard3 } from "./guard3";
import { Guard4 } from "./guard4";

import { Guard4DependencyService } from "./guard4dependency";

@Injectable()
export class MasterGuard implements CanActivate {

    //you may need to include dependencies of individual guards if specified in guard constructor
    constructor(private _Guard4DependencyService:  Guard4DependencyService) {}

    private route: ActivatedRouteSnapshot;
    private state: RouterStateSnapshot;

    //This method gets triggered when the route is hit
    public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {

        this.route = route;
        this.state = state;

        if (!route.data) {
            Promise.resolve(true);
            return;
        }

        //this.route.data.guards is an array of strings set in routing configuration

        if (!this.route.data.guards || !this.route.data.guards.length) {
            Promise.resolve(true);
            return;
        }
        return this.executeGuards();
    }

    //Execute the guards sent in the route data
    private executeGuards(guardIndex: number = 0): Promise<boolean> {
        return this.activateGuard(this.route.data.guards[guardIndex])
            .then(() => {
                if (guardIndex < this.route.data.guards.length - 1) {
                    return this.executeGuards(guardIndex + 1);
                } else {
                    return Promise.resolve(true);
                }
            })
            .catch(() => {
                return Promise.reject(false);
            });
    }

    //Create an instance of the guard and fire canActivate method returning a promise
    private activateGuard(guardKey: string): Promise<boolean> {

        let guard: Guard1 | Guard2 | Guard3 | Guard4;

        switch (guardKey) {
            case GUARDS.GUARD1:
                guard = new Guard1();
                break;
            case GUARDS.GUARD2:
                guard = new Guard2();
                break;
            case GUARDS.GUARD3:
                guard = new Guard3();
                break;
            case GUARDS.GUARD4:
                guard = new Guard4(this._Guard4DependencyService);
                break;
            default:
                break;
        }
        return guard.canActivate(this.route, this.state);
    }
}

Challenges

One of the challenges  in this  approach is refactoring of existing routing model. However, it can be done in parts as the changes are non-breaking.

I hope this helps.


来源: stackexchange

问:
MYSQL Table design help
I have  a table called teams (id, name, ...)   I have a table called divisions (id, name, ......)   I want the diviosn to hold the teams.id  for each team in a divsion  and Teams can be in more than one divsion.  How do I set this up?</p>

答:
You create what's called a relationship table. It's an intermediary table between the Teams tables and the Divisions table. Then we say that there is a many-to-many relationship between the Teams table (tbl_teams) and Divisions table (tbl_divisions). You can have many teams in one division, one team in many divisions, or many teams in many divisions.

tbl_teams_divisions_rel

ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT

Team_ID INT NOT NULL

Division_ID INT NOT NULL

Then you establish a relationship between tbl_teams_divisions_rel.Team_ID and tbl_team.ID, and then between tbl_teams_divisions_rel.Division_ID and tbl_divisions.ID

If you ask the question, how to list all teams in a particular division with ID 13, you would do the following:

```<code>SELECT tbl_teams.*
FROM
    tbl_teams
    INNER JOIN tbl_teams_divisions_rel ON tbl_teams_divisions_rel.Team_ID = tbl_teams.ID
WHERE tbl_teams_divisions_rel.Division_ID = 13
</code>```

Hope it helps!

ContentLicense: CC BY-SA 2.5

Title: MYSQL Table design help

Body:
You create what's called a relationship table. It's an intermediary table between the Teams tables and the Divisions table. Then we say that there is a many-to-many relationship between the Teams table (tbl_teams) and Divisions table (tbl_divisions). You can have many teams in one division, one team in many divisions, or many teams in many divisions.

tbl_teams_divisions_rel

ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT

Team_ID INT NOT NULL

Division_ID INT NOT NULL

Then you establish a relationship between tbl_teams_divisions_rel.Team_ID and tbl_team.ID, and then between tbl_teams_divisions_rel.Division_ID and tbl_divisions.ID

If you ask the question, how to list all teams in a particular division with ID 13, you would do the following:

SELECT tbl_teams.*
FROM
    tbl_teams
    INNER JOIN tbl_teams_divisions_rel ON tbl_teams_divisions_rel.Team_ID = tbl_teams.ID
WHERE tbl_teams_divisions_rel.Division_ID = 13

Hope it helps!


问:
Fastest way to create Dictionary from pyspark DF
I'm using Snappydata with pyspark to run my sql queries and convert the output DF into a dictionary to bulk insert it into mongo.
I've gone through many similar quertions to test the convertion of a spark DF to Dictionary.

Currently I'm using map(lambda row: row.asDict(), x.collect()) this method to convert my bulk DF to dictionary. And it is taking 2-3sec for 10K records.

I've stated below how I impliment my idea:

```<code>x = snappySession.sql("select * from test")
df = map(lambda row: row.asDict(), x.collect())
db.collection.insert_many(df)
</code>```

Is there any faster way?

答:
I'd recommend using foreachPartition:

```<code>(snappySession
    .sql("select * from test")
    .foreachPartition(insert_to_mongo))
</code>```

where insert_to_mongo:

```<code>def insert_to_mongo(rows):
    client  = ...
    db = ...
    db.collection.insert_many((row.asDict() for row in rows))
</code>```

ContentLicense: CC BY-SA 3.0

Body:
I'm using Snappydata with pyspark to run my sql queries and convert the output DF into a dictionary to bulk insert it into mongo.
I've gone through many similar quertions to test the convertion of a spark DF to Dictionary.

Currently I'm using map(lambda row: row.asDict(), x.collect()) this method to convert my bulk DF to dictionary. And it is taking 2-3sec for 10K records.

I've stated below how I impliment my idea:

x = snappySession.sql("select * from test")
df = map(lambda row: row.asDict(), x.collect())
db.collection.insert_many(df)

Is there any faster way?

Body:
I'd recommend using foreachPartition:

(snappySession
    .sql("select * from test")
    .foreachPartition(insert_to_mongo))

where insert_to_mongo:

def insert_to_mongo(rows):
    client  = ...
    db = ...
    db.collection.insert_many((row.asDict() for row in rows))


问:
App client authentication (login) and CQRS
I'm interested in practical scenarios of authentication/login in web application when CQRS pattern is used to build the system.

Say we using HTTP services for commands/queries. And authentication with JWT (or any other authentication token)

We send command LogInUser with credentials (HTTP request).

Server command handler checks credentials, writes events in the store (if using Event Sourcing).

What then? What should we return as the result of the command? Just ok result with authToken? Then client should query the state in the read service? In this case we just make the whole process longer. And this concern actually refers not only to authentication scenarios but also other scenarios when we send a command and expect to get the result of it execution as soon as possible.

I just would like to hear from people who implemented such things. Want to understand possible practical data/requests flows for authentication using CQRS.

答:
Since you are using CQRS, you have decided to separate writing to the application from reading from the application.

To write to the application, you use commands.

To read from the application, you either wait for events, or you query the read model.

This diagram shows the relation between the different options:

(The diagram is taken from the documentation of wolkenkit, a CQRS and event-sourcing framework for JavaScript and Node.js.)

So, when you send your LogInUser command, the command itself does not return anything (of course, when using HTTP there must be a response, but it should just be a 200 OK, so that you can verify that the server received the command and will care about it sooner or later).

Now the server process the login, verifies the sent credentials, and so on, and generates an appropriate UserLoggedIn event. This event gets stored in the event store, and is then sent to the read model.

The read model does two things with this event:

It simply forwards it to the client.

It updates any denormalized tables you may have that are interested in this event, so you can query them later.

So your client has two options:

It can wait for the event after having sent the command. Once the event is being received, the client has the JWT.

It can query the read model, until a given record was updated.

As you need to make sure that only the sender of the command is able to receive the JWT, option 1 is actually the only viable way. You can make sure that an event gets only delivered to the client that sent the appropriate command, but you can't have a table that contains all JWTs where people can only read their JWTs before being authenticated. With the read model, you have a chicken-and-egg problem here.

So, to cut a long story short: The client should wait for the appropriate event, and the event contains the JWT. That's it.


问:
Is there an elegant way to read a binary file and copy its content to a vector<int>
I tried this method:

```<code>void read(vector<int> &vec, string filename)
{
    std::ifstream file(filename, std::ios::binary | std::fstream::binary);
    if (!file.is_open()) throw runtime_error("could not open file");
    //std::istreambuf_iterator<char> start(file), end;
    std::istream_iterator<int> start(file), end;
    //std::istreambuf_iterator<char> start(file), end;
    vec = vector<int>(start, end);
    file.close();
}
void write(vector<int> &vec, string filename) {
    std::ofstream file(filename, std::ios::binary | std::fstream::binary);
    if (!file.is_open()) throw runtime_error("could not open file");
    copy(
        vec.begin(),
        vec.end(),
        //std::ostreambuf_iterator<char>(file)
        std::ostream_iterator<int>(file)
    );
    file.close();
}
int main(){
    vector<int> vec =
    {124,5,543,6,756,6,3,234,5,5,765}, vec2;
    write(vec, "thing.bin");
    read(vec2, "thing.bin");
    for (auto&a : vec2) cout << a << endl;
    system("PAUSE");
}
</code>```

The commented code are alternative iterators I tried.

The problem is that std::ostreambuf_iterator<int>(file) is an invalid iterator to a file. Do I need to do a reinterpret_cast? Am I obligated to use fstream .write() and read() ?

答:
```<code>void read(vector<int> &vec, string filename)
{
    std::ifstream file(filename, std::ios::binary | std::fstream::binary);
    if (!file.is_open()) throw runtime_error("could not open file");

    file.seekg(0, ios_base::end);
    int size = file.tellg() / sizeof(int);
    vec = vector<int>(size);
    file.seekg(0, file.beg);
    file.read(reinterpret_cast<char*>(vec.data()), size*sizeof(int));
    file.close();
}
void write(vector<int> &vec, string filename) {
    std::ofstream file(filename, std::ios::binary | std::fstream::binary);
    if (!file.is_open()) throw runtime_error("could not open file");
    file.write(reinterpret_cast<const char*>(vec.data()), vec.size() * sizeof(int));
    file.close();
}
int main(){
    vector<int> vec =
    {0,1,2,3,-1,127,128,1023,1024}, vec2;
    write(vec, "thing.bin");
    read(vec2, "thing.bin");
    for (auto&a : vec2) cout << a << endl;
    return 0;
}
</code>```

Body:
I tried this method:

void read(vector<int> &vec, string filename)
{
    std::ifstream file(filename, std::ios::binary | std::fstream::binary);
    if (!file.is_open()) throw runtime_error("could not open file");
    //std::istreambuf_iterator<char> start(file), end;
    std::istream_iterator<int> start(file), end;
    //std::istreambuf_iterator<char> start(file), end;
    vec = vector<int>(start, end);
    file.close();
}
void write(vector<int> &vec, string filename) {
    std::ofstream file(filename, std::ios::binary | std::fstream::binary);
    if (!file.is_open()) throw runtime_error("could not open file");
    copy(
        vec.begin(),
        vec.end(),
        //std::ostreambuf_iterator<char>(file)
        std::ostream_iterator<int>(file)
    );
    file.close();
}
int main(){
    vector<int> vec =
    {124,5,543,6,756,6,3,234,5,5,765}, vec2;
    write(vec, "thing.bin");
    read(vec2, "thing.bin");
    for (auto&a : vec2) cout << a << endl;
    system("PAUSE");
}

The commented code are alternative iterators I tried.

The problem is that std::ostreambuf_iterator<int>(file) is an invalid iterator to a file. Do I need to do a reinterpret_cast? Am I obligated to use fstream .write() and read() ?


问:
Using identical list comprehensions on two separate lists

This feels like a simple question, but I haven't been able to figure it out and I haven't been able to find the answer anywhere.

In one line, how can I use two identical list comprehensions on two different lists, and return the results as two seperate lists?

I am trying to do this:

```<code>listx = [x for x in listx if x != None]
listy = [y for y in listy if y != None]
</code>```

Is there a way to do this in one line? Perhaps using map() or a list comprehension?

答:
I think the original one and nested list comprehension is just fine and very readable.

However, if you want to think in terms of functions having an input and output:

You want to filter some contents from a list, so it can be written as:

```<code>listx = filter(None, listx)
listy = filter(None, listy)
</code>```

There is a repeated pattern. The pattern here is we are changing multiple lists at once.

```<code>map(function, collection)
</code>```

So you can break down your original problem to map multiple lists using a filter.

```<code>listx, listy = map(lambda x: filter(None, x), [listx, listy])
</code>```

Body:
This feels like a simple question, but I haven't been able to figure it out and I haven't been able to find the answer anywhere.

In one line, how can I use two identical list comprehensions on two different lists, and return the results as two seperate lists?

I am trying to do this:

listx = [x for x in listx if x != None]
listy = [y for y in listy if y != None]

Is there a way to do this in one line? Perhaps using map() or a list comprehension?

Body:
I think the original one and nested list comprehension is just fine and very readable.

However, if you want to think in terms of functions having an input and output:

You want to filter some contents from a list, so it can be written as:

listx = filter(None, listx)
listy = filter(None, listy)

There is a repeated pattern. The pattern here is we are changing multiple lists at once.

map(function, collection)

So you can break down your original problem to map multiple lists using a filter.

listx, listy = map(lambda x: filter(None, x), [listx, listy])


问:
"ReferenceError: StackTrace is not defined" in Vue app with "stackdriver-errors-js"

I am trying to integrate the stackdriver-error-js library into my Vue project as a module.

The code and the setup:

in package.json

```<code>    "stackdriver-errors-js": "^0.2.0"
</code>```

in bootstrap.js

```<code>   import errorHandler from './error/error-reporting';
</code>```

in error-reporting.js

```<code>import { StackdriverErrorReporter } from 'stackdriver-errors-js';

let errorHandler;

errorHandler = new StackdriverErrorReporter();
errorHandler.start({
    key: "{{.Config.StackDriverApiKey}}",
    projectId: "{{.Config.StackDriverProject}}",
    service: "{{.Config.GoogleCloudProjectID}}",
    version: "{{.Copacknfig.GaeEnv}}",
    disabled: false
});

export default errorHandler;
</code>```

The actual error

The error I got now is (console output and test)

```<code>[vue-devtools] Ready. Detected Vue v2.4.2
(function testErrorReporting() {window.onerror(null, null, null, null, new Error('Test: Something broke!'));})();

stackdriver-errors.js:109 Uncaught ReferenceError: StackTrace is not defined
    at StackdriverErrorReporter.webpackJsonp.556.StackdriverErrorReporter.report (stackdriver-errors.js:109)
    at window.onerror (stackdriver-errors.js:67)
    at testErrorReporting (<anonymous>:1:40)
    at <anonymous>:1:111
</code>```

and line (stackdriver-errors.js:109)

```<code>...
StackTrace.fromError(err).then(function(stack){
...
</code>```

答:
If you do not load the stackdriver-errors-concat.min.js file, you also manually need to also the stacktrace-js module.

stackdriver-errors expects a StackTrace object to be present.

Body:
I am trying to integrate the stackdriver-error-js library into my Vue project as a module.

The code and the setup:

in package.json

    "stackdriver-errors-js": "^0.2.0"

in bootstrap.js

   import errorHandler from './error/error-reporting';

in error-reporting.js

import { StackdriverErrorReporter } from 'stackdriver-errors-js';

let errorHandler;

errorHandler = new StackdriverErrorReporter();
errorHandler.start({
    key: "{{.Config.StackDriverApiKey}}",
    projectId: "{{.Config.StackDriverProject}}",
    service: "{{.Config.GoogleCloudProjectID}}",
    version: "{{.Copacknfig.GaeEnv}}",
    disabled: false
});

export default errorHandler;

The actual error

The error I got now is (console output and test)

[vue-devtools] Ready. Detected Vue v2.4.2
(function testErrorReporting() {window.onerror(null, null, null, null, new Error('Test: Something broke!'));})();

stackdriver-errors.js:109 Uncaught ReferenceError: StackTrace is not defined
    at StackdriverErrorReporter.webpackJsonp.556.StackdriverErrorReporter.report (stackdriver-errors.js:109)
    at window.onerror (stackdriver-errors.js:67)
    at testErrorReporting (<anonymous>:1:40)
    at <anonymous>:1:111

and line (stackdriver-errors.js:109)

...
StackTrace.fromError(err).then(function(stack){
...


问:
How to reset sequence in postgres and fill id column with new data?
I have a table with over million rows. I need to reset sequence and reassign id column with new values (1, 2, 3, 4... etc...). Is any easy way to do that?</p>

答:
The best way to reset a sequence to start back with number 1 is to execute the following:

```<code>ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1
</code>```

So, for example for the users table it would be:

```<code>ALTER SEQUENCE users_id_seq RESTART WITH 1
</code>```

Body:
The best way to reset a sequence to start back with number 1 is to execute the following:

ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1

So, for example for the users table it would be:

ALTER SEQUENCE users_id_seq RESTART WITH 1


问:
How to make an api call inside an api with a url obtained from first api?
I need to make two api calls. The first call obtains the url I need for the second call.

I need data from both api calls. From the first call, I need data from multiple endpoints. For the second api call, I only need data from one endpoint.

Right now, I am making my second api call inside the for loop of my first call. Obviously my code does not work and I am not even sure if that's the correct way to go about getting what I need. Here is what I have so far:

```<code>    var url= "https://api.propublica.org/congress/v1/members/xxx/votes.json";
    $.ajax({
        url: url,
        type: "GET",
        dataType: 'json',
        headers: {'X-API-Key': 'xxx'},
        success: function(data){
            var votes = data.results[0].votes;

            for (var i=0; i<votes.length;++i){
                var api2 = votes[i].bill.bill_uri;

                $.ajax({
                    url: 'api2',
                    type: "GET",
                    dataType: 'json',
                    headers: {'X-API-Key': 'xxx'},
                    success: function(moreData){

                        var billUrl = moreData.results[0].congressdotgov_url;

                        for (var a=0;a<billUrl.length;++i)
                        {
                            $('.recent-votes tbody').append('<tr><td><a href="'+billUrl[a]+'">'+votes[i].bill.number+'</a></td></tr>');
                        }
                    }
                });
            }
        }
    });
</code>```

edit: Here is the response I am getting from the api calls:

votes.json:

```<code>{
    "status": "OK",
    "copyright": "Copyright (c) 2017 Pro Publica Inc. All Rights Reserved.",
    "results": [{
        "member_id": "xxx",
        "num_results": "20",
        "offset": "0",
        "votes": [{
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "664",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/664.json",
                "bill": {
                    "bill_id": "hconres90-115",
                    "number": "H CON RES 90",
                    "sponsor_id": "C001038",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hconres90.json",
                    "title": "Condemning ethnic cleansing of the Rohingya and calling for an end to the attacks in and an immediate restoration of humanitarian access to the state of Rakhine in Burma.",
                    "latest_action": "The title of the measure was amended. Agreed to without objection."
                },
                "amendment": {},
                "description": "Condemning ethnic cleansing of the Rohingya and calling for an end to the attacks in and an immediate restoration of humanitarian access to the state of Rakhine in Burma",
                "question": "On Motion to Suspend the Rules and Agree, as Amended",
                "result": "Passed",
                "date": "2017-12-06",
                "time": "16:50:00",
                "total": {
                    "yes": 423,
                    "no": 3,
                    "present": 0,
                    "not_voting": 6
                },
                "position": "Yes"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "662",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/662.json",
                "bill": {
                    "bill_id": "hr38-115",
                    "number": "H R 38",
                    "sponsor_id": "H001067",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hr38.json",
                    "title": "To amend title 18, United States Code, to provide a means by which nonresidents of a State whose residents may carry concealed firearms may also do so in the State.",
                    "latest_action": "Motion to reconsider laid on the table Agreed to without objection."
                },
                "amendment": {},
                "description": "Concealed Carry Reciprocity Act of 2017",
                "question": "On Motion to Recommit with Instructions",
                "result": "Failed",
                "date": "2017-12-06",
                "time": "16:34:00",
                "total": {
                    "yes": 190,
                    "no": 236,
                    "present": 0,
                    "not_voting": 6
                },
                "position": "No"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "661",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/661.json",
                "bill": {
                    "bill_id": "s1266-115",
                    "number": "S 1266",
                    "sponsor_id": "I000024",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/s1266.json",
                    "title": "A bill to authorize the Secretary of Veterans Affairs to enter into contracts with nonprofit organizations to investigate medical centers of the Department of Veterans Affairs.",
                    "latest_action": "Motion to reconsider laid on the table Agreed to without objection."
                },
                "amendment": {},
                "description": "Enhancing Veteran Care Act",
                "question": "On Motion to Suspend the Rules and Pass",
                "result": "Passed",
                "date": "2017-12-06",
                "time": "14:35:00",
                "total": {
                    "yes": 423,
                    "no": 0,
                    "present": 0,
                    "not_voting": 9
                },
                "position": "Yes"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "653",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/653.json",
                "bill": {
                    "bill_id": "hr1-115",
                    "number": "H R 1",
                    "sponsor_id": "B000755",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hr1.json",
                    "title": "To provide for reconciliation pursuant to title II of the concurrent resolution on the budget for fiscal year 2018.",
                    "latest_action": "Motion by Senator Booker to instruct Senate conferees (health insurance) rejected in Senate by Yea-Nay Vote. 47 - 51. Record Vote Number: 309."
                },
                "amendment": {},
                "description": "Tax Cuts and Jobs Act",
                "question": "On Motion to go to Conference",
                "result": "Passed",
                "date": "2017-12-04",
                "time": "19:04:00",
                "total": {
                    "yes": 222,
                    "no": 192,
                    "present": 0,
                    "not_voting": 19
                },
                "position": "Yes"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "645",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/645.json",
                "bill": {
                    "bill_id": "hres635-115",
                    "number": "H RES 635",
                    "sponsor_id": "W000810",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hres635.json",
                    "title": "Providing for consideration of the bill (H.R. 4182) to amend title 5, United States Code, to modify probationary periods with respect to positions within the competitive service and the Senior Executive Service, and for other purposes, and providing for consideration of the bill (H.R. 1699) to amend the Truth in Lending Act to modify the definitions of a mortgage originator and a high-cost mortgage, to amend the Secure and Fair Enforcement for Mortgage Licensing Act of 2008 to modify the definition of a loan originator, and for other purposes.",
                    "latest_action": "Motion to reconsider laid on the table Agreed to without objection."
                },
                "amendment": {},
                "description": "Providing for consideration of H.R. 4182, the Ensuring a Qualified Civil Service Act of 2017; and H.R. 1699, the Preserving Access to Manufactured Housing Act of 2017",
                "question": "On Agreeing to the Resolution",
                "result": "Passed",
                "date": "2017-11-30",
                "time": "14:15:00",
                "total": {
                    "yes": 226,
                    "no": 186,
                    "present": 0,
                    "not_voting": 21
                },
                "position": "Yes"
            }
        ]
    }]
}
</code>```

For each individual bill uri api call, I'm seeing the header status code is 200 but the response tab is showing "This request has no response data available".

The end result html should look like:

$('.recent-votes tbody').append(''+votes[i].bill.number+'');

```<code><tr><td><a href="www.billurl.com/1">Bill 1</a></td></tr>
<tr><td><a href="www.billurl.com/2">Bill 2</a></td></tr>
<tr><td><a href="www.billurl.com/3">Bill 3</a></td></tr>
etc.
etc.
</code>```

答:
Your code actually looks mostly sound. This is a viable way to achieve what you are trying to do. However, It looks like you have a typo in your inner loop. You are incrementing i, when you should be incrementing a. That's in this line:

```<code>    for (var a=0;a<billUrl.length;++i)
</code>```

Secondly, change your ++i to i++ (do the same for a). Otherwise, you will be skipping the very first item in each loop. Thirdly, it looks like you are not using the assigned api2 variable in your inner loop calls. Remove the quotes from that.

Finally, your i variable is out of scope when you get to success function of your inner loop. This is the trickiest part. There are numerous ways to handle this, and some examples are here: jQuery ajax loop and iteration scope. In my opinion, the simplest way is to use closures and wrap your i variable.

Try this:

```<code>var url= "https://api.propublica.org/congress/v1/members/xxx/votes.json";
$.ajax({
    url: url,
    type: "GET",
    dataType: 'json',
    headers: {'X-API-Key': 'xxx'},
    success: function(data){
        var votes = data.results[0].votes;
        for (var i=0; i<votes.length;i++){
            var api2 = votes[i].bill.bill_uri;
            (function(i) {
                $.ajax({
                    url: api2,
                    type: "GET",
                    dataType: 'json',
                    headers: {'X-API-Key': 'xxx'},
                    success: function(moreData){
                        var billUrl = moreData.results[0].congressdotgov_url;
                        for (var a=0;a<billUrl.length;a++)
                        {
                            $('.recent-votes tbody').append('<tr><td><a href="'+billUrl[a]+'">'+votes[i].bill.number+'</a></td></tr>');
                        }
                    }
                });
            })(i);
        }
    }
});
</code>```

There are other ways to do this as well. As others have suggested, you can return everything you need from your first api call (if you have control of the backend). Obviously, this would be the best and most efficient thing to do, if it's possible. However, if you don't have control over the backend, then these fixes should get you going.

Body:
I need to make two api calls. The first call obtains the url I need for the second call.

I need data from both api calls. From the first call, I need data from multiple endpoints. For the second api call, I only need data from one endpoint.

Right now, I am making my second api call inside the for loop of my first call. Obviously my code does not work and I am not even sure if that's the correct way to go about getting what I need. Here is what I have so far:

    var url= "https://api.propublica.org/congress/v1/members/xxx/votes.json";
    $.ajax({
        url: url,
        type: "GET",
        dataType: 'json',
        headers: {'X-API-Key': 'xxx'},
        success: function(data){
            var votes = data.results[0].votes;

            for (var i=0; i<votes.length;++i){
                var api2 = votes[i].bill.bill_uri;

                $.ajax({
                    url: 'api2',
                    type: "GET",
                    dataType: 'json',
                    headers: {'X-API-Key': 'xxx'},
                    success: function(moreData){

                        var billUrl = moreData.results[0].congressdotgov_url;

                        for (var a=0;a<billUrl.length;++i)
                        {
                            $('.recent-votes tbody').append('
'+votes[i].bill.number+'
');
                        }
                    }
                });
            }
        }
    });

edit: Here is the response I am getting from the api calls:

votes.json:

{
    "status": "OK",
    "copyright": "Copyright (c) 2017 Pro Publica Inc. All Rights Reserved.",
    "results": [{
        "member_id": "xxx",
        "num_results": "20",
        "offset": "0",
        "votes": [{
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "664",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/664.json",
                "bill": {
                    "bill_id": "hconres90-115",
                    "number": "H CON RES 90",
                    "sponsor_id": "C001038",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hconres90.json",
                    "title": "Condemning ethnic cleansing of the Rohingya and calling for an end to the attacks in and an immediate restoration of humanitarian access to the state of Rakhine in Burma.",
                    "latest_action": "The title of the measure was amended. Agreed to without objection."
                },
                "amendment": {},
                "description": "Condemning ethnic cleansing of the Rohingya and calling for an end to the attacks in and an immediate restoration of humanitarian access to the state of Rakhine in Burma",
                "question": "On Motion to Suspend the Rules and Agree, as Amended",
                "result": "Passed",
                "date": "2017-12-06",
                "time": "16:50:00",
                "total": {
                    "yes": 423,
                    "no": 3,
                    "present": 0,
                    "not_voting": 6
                },
                "position": "Yes"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "662",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/662.json",
                "bill": {
                    "bill_id": "hr38-115",
                    "number": "H R 38",
                    "sponsor_id": "H001067",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hr38.json",
                    "title": "To amend title 18, United States Code, to provide a means by which nonresidents of a State whose residents may carry concealed firearms may also do so in the State.",
                    "latest_action": "Motion to reconsider laid on the table Agreed to without objection."
                },
                "amendment": {},
                "description": "Concealed Carry Reciprocity Act of 2017",
                "question": "On Motion to Recommit with Instructions",
                "result": "Failed",
                "date": "2017-12-06",
                "time": "16:34:00",
                "total": {
                    "yes": 190,
                    "no": 236,
                    "present": 0,
                    "not_voting": 6
                },
                "position": "No"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "661",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/661.json",
                "bill": {
                    "bill_id": "s1266-115",
                    "number": "S 1266",
                    "sponsor_id": "I000024",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/s1266.json",
                    "title": "A bill to authorize the Secretary of Veterans Affairs to enter into contracts with nonprofit organizations to investigate medical centers of the Department of Veterans Affairs.",
                    "latest_action": "Motion to reconsider laid on the table Agreed to without objection."
                },
                "amendment": {},
                "description": "Enhancing Veteran Care Act",
                "question": "On Motion to Suspend the Rules and Pass",
                "result": "Passed",
                "date": "2017-12-06",
                "time": "14:35:00",
                "total": {
                    "yes": 423,
                    "no": 0,
                    "present": 0,
                    "not_voting": 9
                },
                "position": "Yes"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "653",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/653.json",
                "bill": {
                    "bill_id": "hr1-115",
                    "number": "H R 1",
                    "sponsor_id": "B000755",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hr1.json",
                    "title": "To provide for reconciliation pursuant to title II of the concurrent resolution on the budget for fiscal year 2018.",
                    "latest_action": "Motion by Senator Booker to instruct Senate conferees (health insurance) rejected in Senate by Yea-Nay Vote. 47 - 51. Record Vote Number: 309."
                },
                "amendment": {},
                "description": "Tax Cuts and Jobs Act",
                "question": "On Motion to go to Conference",
                "result": "Passed",
                "date": "2017-12-04",
                "time": "19:04:00",
                "total": {
                    "yes": 222,
                    "no": 192,
                    "present": 0,
                    "not_voting": 19
                },
                "position": "Yes"
            },
            {
                "member_id": "xxx",
                "chamber": "House",
                "congress": "115",
                "session": "1",
                "roll_call": "645",
                "vote_uri": "https://api.propublica.org/congress/v1/115/house/sessions/1/votes/645.json",
                "bill": {
                    "bill_id": "hres635-115",
                    "number": "H RES 635",
                    "sponsor_id": "W000810",
                    "bill_uri": "https://api.propublica.org/congress/v1/115/bills/hres635.json",
                    "title": "Providing for consideration of the bill (H.R. 4182) to amend title 5, United States Code, to modify probationary periods with respect to positions within the competitive service and the Senior Executive Service, and for other purposes, and providing for consideration of the bill (H.R. 1699) to amend the Truth in Lending Act to modify the definitions of a mortgage originator and a high-cost mortgage, to amend the Secure and Fair Enforcement for Mortgage Licensing Act of 2008 to modify the definition of a loan originator, and for other purposes.",
                    "latest_action": "Motion to reconsider laid on the table Agreed to without objection."
                },
                "amendment": {},
                "description": "Providing for consideration of H.R. 4182, the Ensuring a Qualified Civil Service Act of 2017; and H.R. 1699, the Preserving Access to Manufactured Housing Act of 2017",
                "question": "On Agreeing to the Resolution",
                "result": "Passed",
                "date": "2017-11-30",
                "time": "14:15:00",
                "total": {
                    "yes": 226,
                    "no": 186,
                    "present": 0,
                    "not_voting": 21
                },
                "position": "Yes"
            }
        ]
    }]
}

For each individual bill uri api call, I'm seeing the header status code is 200 but the response tab is showing "This request has no response data available".

The end result html should look like:

$('.recent-votes tbody').append(''+votes[i].bill.number+'');

Bill 1

Bill 2

Bill 3

etc.
etc.

Body:
Your code actually looks mostly sound. This is a viable way to achieve what you are trying to do. However, It looks like you have a typo in your inner loop. You are incrementing i, when you should be incrementing a. That's in this line:

    for (var a=0;a<billUrl.length;++i)

Secondly, change your ++i to i++ (do the same for a). Otherwise, you will be skipping the very first item in each loop. Thirdly, it looks like you are not using the assigned api2 variable in your inner loop calls. Remove the quotes from that.

Finally, your i variable is out of scope when you get to success function of your inner loop. This is the trickiest part. There are numerous ways to handle this, and some examples are here: jQuery ajax loop and iteration scope. In my opinion, the simplest way is to use closures and wrap your i variable.

Try this:

var url= "https://api.propublica.org/congress/v1/members/xxx/votes.json";
$.ajax({
    url: url,
    type: "GET",
    dataType: 'json',
    headers: {'X-API-Key': 'xxx'},
    success: function(data){
        var votes = data.results[0].votes;
        for (var i=0; i<votes.length;i++){
            var api2 = votes[i].bill.bill_uri;
            (function(i) {
                $.ajax({
                    url: api2,
                    type: "GET",
                    dataType: 'json',
                    headers: {'X-API-Key': 'xxx'},
                    success: function(moreData){
                        var billUrl = moreData.results[0].congressdotgov_url;
                        for (var a=0;a<billUrl.length;a++)
                        {
                            $('.recent-votes tbody').append('<tr><td><a href="'+billUrl[a]+'">'+votes[i].bill.number+'</a></td></tr>');
                        }
                    }
                });
            })(i);
        }
    }
});

There are other ways to do this as well. As others have suggested, you can return everything you need from your first api call (if you have control of the backend). Obviously, this would be the best and most efficient thing to do, if it's possible. However, if you don't have control over the backend, then these fixes should get you going.


问:
creating a customer login function using the prestashop webservice
I'm currently working on an application that makes use of the prestashop webservice. This means that the application i'm building is an extension of an existing prestashop application. The connection between both applications is through the prestashop webservice

Currently i'm trying to create a login script for thecustomers. The email and password are obtained from the database through the webservice and i'm able to filter the inputs with the existing row's. So when filling in login@test.com. The filter will only obtain the row with that email address.

The problem i'm having is with the password. Prestashop uses a _COOKIE_KEY_ together with anmd5() to encrypt passwords. See this link for more information: link

So i've been trying some different things for a while to check the inputted password with the customers password but i haven't found the solution yet.

Take a look at the code below:

```<code><?php

require_once('./PSWebServiceLibrary.php');

/**
 * get information from PrestaShop
 */

$webService = new PrestaShopWebservice($url, $key, $debug);

define('_COOKIE_KEY_', '...');
$email = "login@test.nl";
define('password', "test");
$md5passwd = md5(_COOKIE_KEY_ . password);

$opt = array(
    "resource" => "customers",
    "display" => "[email , passwd]",
    "filter[email]" => "$email"
);

$optPass = array(
    "resource" => "customers",
    "display" => "[email]",
    "filter[email]" => "$email",
    "filter[passwd]" => "$md5passwd"
);

$jsonPass = ($webService->get( $optPass ));

//json encode it
$jsonPasswd = json_encode($jsonPass);

echo($jsonPasswd);

if(password_verify($md5passwd, $jsonPasswd)) {
    echo "password is valid";
} else {
    echo "password is not valid";
}

$jsonUrl = ($webService->get( $opt ));

//json encode it
$json = json_encode($jsonUrl);

echo($json);
</code>```

As you can see i've been trying out things like the password_verify and the md5() but i can't quite get it. So is there anyone who has done this or who knows how to create a correct login script on the prestashop webservice?

Update -- 12/1/2017
So after doing some research i've come up with a new way of checking the user input. First the code checks the email and if it's true it will continue with checking the password input. But the problem i'm having is with the password and the password encryption of prestashop. I'm not able to compare the two hashes together. The first hash would be the hash from the database were the second hash is the user input password. The input would need a hash() function from prestashop. But i can't quite get to the right hash sequence of prestashop.

I've searched all over the internet for this but couldn't find a decent solution for logging in through the prestashop webservice. The script i've created for logging in is shown below.

```<code>require_once('./PSWebServiceLibrary.php');

/**
 * get information from PrestaShop
 */

$webService = new PrestaShopWebservice($url, $key, $debug);

$COOKIE_KEY = '_key';
$email = $_REQUEST['email'];
$password = md5('_key' . $_REQUEST['password']);

// The database hash for testing (random)
$passwordString = '$2y$10$UsYrIFQUOr5LBUZBoqSdxODuhbToEc.2QEqfAVB1r\/fhO5EfOyO96';

$opt = array(
    'resource'       => 'customers',
    'filter[email]'  => '['.$email.']',
    'display' => '[email,lastname,firstname, passwd]'
);

$result = ($webService->get( $opt ));

$json = json_encode($result);

$optUser = array(
    'resource'       => 'customers',
    'filter[email]'  => '['.$email.']',
    'display' => '[email,lastname,firstname,passwd]'
);

$resultUser = ($webService->get( $optUser ));

$userResult = json_encode($resultUser);

// Check the email
function hasEmail($string, $email)
{
    return strpos($string, $email) !== false;
}

// Check the Password
function hasPassword($string, $password)
{
    return strpos($string, $password) !== false;
}

if(hasEmail($userResult, $email) == true and hasPassword($userResult, $password) == true)  {
    session_start();
    $_SESSION['user'] = $email;
    // redirect is kut.
    echo
        '<html>
         <head>
           <meta content="text/html; charset=utf-8">
         </head>
         </html>';
} else {
// Here, we use single quotes for PHP and double quotes for JavaScript
    echo '<script type="text/javascript">';
    echo 'alert("Wrong username or password!")';
    echo '</script>';
}
</code>```

Small second question: How would i be able to run a -> go to url in the success statement, Currently the echo ""; isn't working and since the header() can't be used i'm having some trouble redirecting on succes.

As always, Thanks in advance!

答:
To generate the cookie key prestashop uses:

```<code>array('_COOKIE_KEY_', Tools::passwdGen(56)),
array('_COOKIE_IV_', Tools::passwdGen(8)),
</code>```

So that cookie key is different everytime. In order to verify if the password is good you should get existing password from database and compare with your user-submitted password:

```<code>//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
$resultZC = Db::getInstance()->getRow('
SELECT `password`
FROM `zc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

 if (!$resultZC)
return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

if ($ZCpassword != $resultZC['password'])
return false; //<- WRONG ZEN-CART/OSCOMMERCE PASSWORD GIVEN
</code>```

This is the part that you're asking for:

```<code>//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;
</code>```

where $resultZC['password'] is the password stored in the database and, $passwd is your password

Body:
I'm currently working on an application that makes use of the prestashop webservice. This means that the application i'm building is an extension of an existing prestashop application. The connection between both applications is through the prestashop webservice

Currently i'm trying to create a login script for thecustomers. The email and password are obtained from the database through the webservice and i'm able to filter the inputs with the existing row's. So when filling in login@test.com. The filter will only obtain the row with that email address.

The problem i'm having is with the password. Prestashop uses a _COOKIE_KEY_ together with anmd5() to encrypt passwords. See this link for more information: link

So i've been trying some different things for a while to check the inputted password with the customers password but i haven't found the solution yet.

Take a look at the code below:

<?php

require_once('./PSWebServiceLibrary.php');

/**
 * get information from PrestaShop
 */

$webService = new PrestaShopWebservice($url, $key, $debug);

define('_COOKIE_KEY_', '...');
$email = "login@test.nl";
define('password', "test");
$md5passwd = md5(_COOKIE_KEY_ . password);

$opt = array(
    "resource" => "customers",
    "display" => "[email , passwd]",
    "filter[email]" => "$email"
);

$optPass = array(
    "resource" => "customers",
    "display" => "[email]",
    "filter[email]" => "$email",
    "filter[passwd]" => "$md5passwd"
);

$jsonPass = ($webService->get( $optPass ));

//json encode it
$jsonPasswd = json_encode($jsonPass);

echo($jsonPasswd);

if(password_verify($md5passwd, $jsonPasswd)) {
    echo "password is valid";
} else {
    echo "password is not valid";
}

$jsonUrl = ($webService->get( $opt ));

//json encode it
$json = json_encode($jsonUrl);

echo($json);

As you can see i've been trying out things like the password_verify and the md5() but i can't quite get it. So is there anyone who has done this or who knows how to create a correct login script on the prestashop webservice?

Update -- 12/1/2017
So after doing some research i've come up with a new way of checking the user input. First the code checks the email and if it's true it will continue with checking the password input. But the problem i'm having is with the password and the password encryption of prestashop. I'm not able to compare the two hashes together. The first hash would be the hash from the database were the second hash is the user input password. The input would need a hash() function from prestashop. But i can't quite get to the right hash sequence of prestashop.

I've searched all over the internet for this but couldn't find a decent solution for logging in through the prestashop webservice. The script i've created for logging in is shown below.

require_once('./PSWebServiceLibrary.php');

/**
 * get information from PrestaShop
 */

$webService = new PrestaShopWebservice($url, $key, $debug);

$COOKIE_KEY = '_key';
$email = $_REQUEST['email'];
$password = md5('_key' . $_REQUEST['password']);

// The database hash for testing (random)
$passwordString = '$2y$10$UsYrIFQUOr5LBUZBoqSdxODuhbToEc.2QEqfAVB1r\/fhO5EfOyO96';

$opt = array(
    'resource'       => 'customers',
    'filter[email]'  => '['.$email.']',
    'display' => '[email,lastname,firstname, passwd]'
);

$result = ($webService->get( $opt ));

$json = json_encode($result);

$optUser = array(
    'resource'       => 'customers',
    'filter[email]'  => '['.$email.']',
    'display' => '[email,lastname,firstname,passwd]'
);

$resultUser = ($webService->get( $optUser ));

$userResult = json_encode($resultUser);

// Check the email
function hasEmail($string, $email)
{
    return strpos($string, $email) !== false;
}

// Check the Password
function hasPassword($string, $password)
{
    return strpos($string, $password) !== false;
}

if(hasEmail($userResult, $email) == true and hasPassword($userResult, $password) == true)  {
    session_start();
    $_SESSION['user'] = $email;
    // redirect is kut.
    echo
        '

           <meta content="text/html; charset=utf-8">

         ';
} else {
// Here, we use single quotes for PHP and double quotes for JavaScript
    echo '';
}

Small second question: How would i be able to run a -> go to url in the success statement, Currently the echo ""; isn't working and since the header() can't be used i'm having some trouble redirecting on succes.

As always, Thanks in advance!

Body:
To generate the cookie key prestashop uses:

array('_COOKIE_KEY_', Tools::passwdGen(56)),
array('_COOKIE_IV_', Tools::passwdGen(8)),

So that cookie key is different everytime. In order to verify if the password is good you should get existing password from database and compare with your user-submitted password:

//CHECK IF THE GIVEN EMAIL MATCHES A ROW IN OUR LEGACY TABLE AND RETRIEVES THE LEGACY PASSWORD
$resultZC = Db::getInstance()->getRow('
SELECT `password`
FROM `zc_legacy_passwords`
WHERE `email` = \''.pSQL($email).'\'
AND `updated` = 0');

 if (!$resultZC)
return false; //<- EMAIL NOT FOUND IN NONE OF THE TABLES, SO IT IS AN INVALID LOGIN

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

if ($ZCpassword != $resultZC['password'])
return false; //<- WRONG ZEN-CART/OSCOMMERCE PASSWORD GIVEN

This is the part that you're asking for:

//ENCRYPTS THE GIVEN PASSWORD IN ZEN-CART / OSCOMMERCE FORMAT
$salt = substr($resultZC['password'], strrpos($resultZC['password'],':')+1, 2);
$ZCpassword = md5($salt . $passwd) . ':' . $salt;

where $resultZC['password'] is the password stored in the database and, $passwd is your password


问:
Android:Kotlin TypeCastException: null cannot be cast to non-null type kotlin.String
I am new to Kotlin and I'm trying to develop a music app.

I'm getting this bug which I'm not able to solve. When I open my app the song list is displayed ,on clicking a song its redirecting to nowplaying screen but on clicking next or previous button my app crashes.

The logcat is giving an TypeCast error which I dont understand.

The Code is below:

```<code>class SongPlayingFragment : Fragment() {

var myActivity: Activity? = null
var mediaplayer: MediaPlayer? = null
var startTimeText: TextView? = null
var endTimeText: TextView? = null
var playpauseImageButton: ImageButton? = null
var previousImageButton: ImageButton? = null
var nextImageButton: ImageButton? = null
var loopImageButton: ImageButton? = null
var seekbar: SeekBar? = null
var songArtistView: TextView? = null
var songTitleView: TextView? = null
var shuffleImageButton: ImageButton? = null
var currentPosition: Int = 0
var fetchSongs: ArrayList<Songs>? = null
var currentSongHelper: CurrentSongHelper? = null
var audioVisualization: AudioVisualization? = null
var g1view: GLAudioVisualizationView? = null

object Staticated {
    var MY_PREFS_SHUFFLE = "Shuffle Feature"
    var MY_PREFS_LOOP = "Loop Feature"
}

var updateSongTime = object : Runnable {
    override fun run() {
        val getcurrent = mediaplayer?.currentPosition
        startTimeText?.setText(String.format("%d:%d",
                TimeUnit.MILLISECONDS.toMinutes(getcurrent?.toLong() as Long),
                TimeUnit.MILLISECONDS.toSeconds(getcurrent?.toLong() as Long) -
                        TimeUnit.MILLISECONDS.toSeconds(TimeUnit.MILLISECONDS.toMinutes(getcurrent?.toLong() as Long)
                        )))
        seekbar?.setProgress(getcurrent?.toInt() as Int)
        Handler().postDelayed(this, 1000)
    }
}

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {

    var view = inflater!!.inflate(R.layout.fragment_song_playing, container, false)
    seekbar = view?.findViewById(R.id.seekBar)
    startTimeText = view?.findViewById(R.id.startTime)
    endTimeText = view?.findViewById(R.id.endTime)
    playpauseImageButton = view?.findViewById(R.id.playPauseButton)
    nextImageButton = view?.findViewById(R.id.nextButton)
    previousImageButton = view?.findViewById(R.id.previousButton)
    loopImageButton = view?.findViewById(R.id.LoopButton)
    shuffleImageButton = view?.findViewById(R.id.shuffleButton)
    songArtistView = view?.findViewById(R.id.songArtist)
    songTitleView = view?.findViewById(R.id.songTitle)
    g1view = view?.findViewById(R.id.visualizer_view)

    return view
}

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    audioVisualization = g1view as AudioVisualization
}

override fun onAttach(context: Context?) {
    super.onAttach(context)
    myActivity = context as Activity
}

override fun onAttach(activity: Activity?) {
    super.onAttach(activity)
    myActivity = activity
}

override fun onResume() {
    super.onResume()
    audioVisualization?.onResume()
}

override fun onPause() {
    audioVisualization?.onPause()
    super.onPause()
}

override fun onDestroyView() {
    audioVisualization?.release()
    super.onDestroyView()
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    currentSongHelper = CurrentSongHelper()
    currentSongHelper?.isPlaying = true
    currentSongHelper?.isLoop = false
    currentSongHelper?.isShuffle = false
    var path: String? = null
    var songTitle: String? = null
    var songArtist: String? = null
    var songId: Long = 0
    try {
        path = arguments.getString("path")
        songTitle = arguments.getString("songTitle")
        songArtist = arguments.getString("songArtist")
        songId = arguments.getInt("songId").toLong()
        currentPosition = arguments.getInt("songPosition")
        fetchSongs = arguments.getParcelableArrayList("songData")

        currentSongHelper?.songPath = path
        currentSongHelper?.songTitle = songTitle
        currentSongHelper?.songArtist = songArtist
        currentSongHelper?.songId = songId
        currentSongHelper?.currentPosition = currentPosition

        updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)
    } catch(e: Exception) {
        e.printStackTrace()
    }
    mediaplayer = MediaPlayer()
    mediaplayer?.setAudioStreamType(AudioManager.STREAM_MUSIC)
    try {
        mediaplayer?.setDataSource(myActivity, Uri.parse(path))
        mediaplayer?.prepare()
    } catch (e: Exception) {
        e.printStackTrace()
    }

    mediaplayer?.start()
    processInformation(mediaplayer as MediaPlayer)
    if (currentSongHelper?.isPlaying as Boolean) {
        playpauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
    } else {
        playpauseImageButton?.setBackgroundResource(R.drawable.play_icon)
    }
    mediaplayer?.setOnCompletionListener {
        onSongComplete()

    }
    clickHandler()
    var visualizationHandler = DbmHandler.Factory.newVisualizerHandler(myActivity as Context, 0)
    audioVisualization?.linkTo(visualizationHandler)

    var prefsForShuffle = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)
    var isShuffleAllowed = prefsForShuffle?.getBoolean("feature", false)
    if (isShuffleAllowed as Boolean) {
        currentSongHelper?.isShuffle = true
        currentSongHelper?.isLoop = false
        shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_icon)

        loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
    } else {
        currentSongHelper?.isShuffle = false
        shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
    }
    var prefsForLoop = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)
    var isLoopAllowed = prefsForShuffle?.getBoolean("feature", false)
    if (isLoopAllowed as Boolean) {
        currentSongHelper?.isShuffle = false
        currentSongHelper?.isLoop = true
        shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)

        loopImageButton?.setBackgroundResource(R.drawable.loop_icon)
    } else {
        loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
        currentSongHelper?.isLoop = false

    }
enter code here
}

fun clickHandler() {

    shuffleImageButton?.setOnClickListener({
        var editorShuffle = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)?.edit()
        var editorLoop = myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
        if (currentSongHelper?.isShuffle as Boolean) {
            shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
            currentSongHelper?.isShuffle = false
            editorShuffle?.putBoolean("feature", false)
            editorShuffle?.apply()
        } else {
            currentSongHelper?.isShuffle = true
            currentSongHelper?.isLoop = false
            shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_icon)
            loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
            editorShuffle?.putBoolean("feature", true)
            editorShuffle?.apply()
            editorLoop?.putBoolean("feature", false)
            editorLoop?.apply()
        }
    })
    nextImageButton?.setOnClickListener({
        currentSongHelper?.isPlaying = true
        if (currentSongHelper?.isShuffle as Boolean) {
            playNext("PlayNextLikeNormalShuffle")
        } else {
            playNext("PlayNextNormal")
        }
    })
    previousImageButton?.setOnClickListener({
        currentSongHelper?.isPlaying = true
        if (currentSongHelper?.isLoop as Boolean) {
            loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
        }
        playPrevious()
    })
    loopImageButton?.setOnClickListener({
        var editorShuffle = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)?.edit()
        var editorLoop = myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
        if (currentSongHelper?.isLoop as Boolean) {
            currentSongHelper?.isLoop = false
            loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
            editorLoop?.putBoolean("feature", false)
            editorLoop?.apply()
        } else {
            currentSongHelper?.isLoop = true
            currentSongHelper?.isShuffle = false
            loopImageButton?.setBackgroundResource(R.drawable.loop_icon)
            shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
            editorShuffle?.putBoolean("feature", false)
            editorShuffle?.apply()
            editorLoop?.putBoolean("feature", true)
            editorLoop?.apply()
        }
    })
    playpauseImageButton?.setOnClickListener({
        if (mediaplayer?.isPlaying as Boolean) {
            mediaplayer?.pause()
            currentSongHelper?.isPlaying = false
            playpauseImageButton?.setBackgroundResource(R.drawable.play_icon)
        } else {
            mediaplayer?.start()
            currentSongHelper?.isPlaying = true
            playpauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
        }

    })

}

fun playNext(check: String) {
    if (check.equals("PlayNextNormal", true)) {
        currentPosition = currentPosition + 1

    } else if (check.equals("PlayNextLikeNormalShuffle", true)) {
        var randomObject = Random()
        var randomPosition = randomObject.nextInt(fetchSongs?.size?.plus(1) as Int)
        currentPosition = randomPosition

    }
    if (currentPosition == fetchSongs?.size) {
        currentPosition = 0
    }
    currentSongHelper?.isLoop = false
    var nextSong = fetchSongs?.get(currentPosition)
    currentSongHelper?.songPath = nextSong?.songData
    currentSongHelper?.songTitle = nextSong?.songTitle
    currentSongHelper?.currentPosition = currentPosition
    currentSongHelper?.songId = nextSong?.songId as Long

    updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)
    mediaplayer?.reset()
    try {
        mediaplayer?.setDataSource(myActivity, Uri.parse(currentSongHelper?.songPath))
        mediaplayer?.prepare()
        mediaplayer?.start()
        processInformation(mediaplayer as MediaPlayer)
    } catch (e: Exception) {
        e.printStackTrace()
    }

}

fun playPrevious() {
    currentPosition = currentPosition - 1

    if (currentPosition == -1) {
        currentPosition = 0
    }
    if (currentSongHelper?.isPlaying as Boolean) {
        playpauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
    } else {
        playpauseImageButton?.setBackgroundResource(R.drawable.play_icon)
    }
    currentSongHelper?.isLoop = false
    var nextSong = fetchSongs?.get(currentPosition)
    currentSongHelper?.songPath = nextSong?.songData
    currentSongHelper?.songTitle = nextSong?.songTitle
    currentSongHelper?.currentPosition = currentPosition
    currentSongHelper?.songId = nextSong?.songId as Long

    updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)

    mediaplayer?.reset()
    try {
        mediaplayer?.setDataSource(activity, Uri.parse(currentSongHelper?.songPath))
        mediaplayer?.prepare()
        mediaplayer?.start()
        processInformation(mediaplayer as MediaPlayer)
    } catch (e: Exception) {
        e.printStackTrace()
    }

}

fun onSongComplete() {
    if (currentSongHelper?.isShuffle as Boolean) {
        playNext("PlayNextLikeNormalShuffle")
        currentSongHelper?.isPlaying = true
    } else {
        if (currentSongHelper?.isLoop as Boolean) {
            currentSongHelper?.isPlaying = true
            var nextSong = fetchSongs?.get(currentPosition)

            currentSongHelper?.songTitle = nextSong?.songTitle
            currentSongHelper?.songPath = nextSong?.songData
            currentSongHelper?.currentPosition = currentPosition
            currentSongHelper?.songId = nextSong?.songId as Long

            updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)
            mediaplayer?.reset()
            try {
                mediaplayer?.setDataSource(myActivity, Uri.parse(currentSongHelper?.songPath))
                mediaplayer?.prepare()
                mediaplayer?.start()

            } catch (e: Exception) {
                e.printStackTrace()
            }

        } else {
            playNext("PlayNextNormal")
            currentSongHelper?.isPlaying = true
        }
    }

}

fun updateTextViews(songtitle: String, songArtist: String) {
    songTitleView?.setText(songtitle)
    songArtistView?.setText(songArtist)
}

fun processInformation(mediaPlayer: MediaPlayer) {
    val finalTime = mediaPlayer.duration
    val startTime = mediaPlayer.currentPosition
    seekbar?.max = finalTime
    startTimeText?.setText(String.format("%d: %d",
            TimeUnit.MILLISECONDS.toMinutes(startTime.toLong()),
            TimeUnit.MILLISECONDS.toSeconds(startTime.toLong()) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(startTime?.toLong()))
    ))
    endTimeText?.setText(String.format("%d:%d",
            TimeUnit.MILLISECONDS.toMinutes(finalTime.toLong()),
            TimeUnit.MILLISECONDS.toSeconds(finalTime.toLong()) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(finalTime?.toLong())))
    )
    seekbar?.setProgress(startTime)
    Handler().postDelayed(updateSongTime, 1000)
}
</code>```

}

LOGS:

```<code>12-07 20:30:27.447 28230-28230/com.example.sanjanaadmin.echo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.sanjanaadmin.echo, PID: 28230
    kotlin.TypeCastException: null cannot be cast to non-null type kotlin.String
        at com.example.sanjanaadmin.echo.fragments.SongPlayingFragment.playNext(SongPlayingFragment.kt:314)
        at com.example.sanjanaadmin.echo.fragments.SongPlayingFragment$clickHandler$2.onClick(SongPlayingFragment.kt:250)
        at android.view.View.performClick(View.java:5268)
        at android.view.View$PerformClick.run(View.java:21550)
        at android.os.Handler.handleCallback(Handler.java:822)
        at android.os.Handler.dispatchMessage(Handler.java:104)
        at android.os.Looper.loop(Looper.java:207)
        at android.app.ActivityThread.main(ActivityThread.java:5811)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:681)
</code>```

答:
You are trying to cast a nullable value produced by a safe call (?.) to the not-null type String:

```<code>currentSongHelper?.songTitle as String
</code>```

(and a few more places)

This cast will fail if the value is null. To fix this, cast to the nullable type instead String?:

```<code>currentSongHelper?.songTitle as String?
</code>```

(fix the other such cases as well)

Body:
I am new to Kotlin and I'm trying to develop a music app.

I'm getting this bug which I'm not able to solve. When I open my app the song list is displayed ,on clicking a song its redirecting to nowplaying screen but on clicking next or previous button my app crashes.

The logcat is giving an TypeCast error which I dont understand.

The Code is below:

class SongPlayingFragment : Fragment() {

var myActivity: Activity? = null
var mediaplayer: MediaPlayer? = null
var startTimeText: TextView? = null
var endTimeText: TextView? = null
var playpauseImageButton: ImageButton? = null
var previousImageButton: ImageButton? = null
var nextImageButton: ImageButton? = null
var loopImageButton: ImageButton? = null
var seekbar: SeekBar? = null
var songArtistView: TextView? = null
var songTitleView: TextView? = null
var shuffleImageButton: ImageButton? = null
var currentPosition: Int = 0
var fetchSongs: ArrayList<Songs>? = null
var currentSongHelper: CurrentSongHelper? = null
var audioVisualization: AudioVisualization? = null
var g1view: GLAudioVisualizationView? = null

object Staticated {
    var MY_PREFS_SHUFFLE = "Shuffle Feature"
    var MY_PREFS_LOOP = "Loop Feature"
}

var updateSongTime = object : Runnable {
    override fun run() {
        val getcurrent = mediaplayer?.currentPosition
        startTimeText?.setText(String.format("%d:%d",
                TimeUnit.MILLISECONDS.toMinutes(getcurrent?.toLong() as Long),
                TimeUnit.MILLISECONDS.toSeconds(getcurrent?.toLong() as Long) -
                        TimeUnit.MILLISECONDS.toSeconds(TimeUnit.MILLISECONDS.toMinutes(getcurrent?.toLong() as Long)
                        )))
        seekbar?.setProgress(getcurrent?.toInt() as Int)
        Handler().postDelayed(this, 1000)
    }
}

override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?,
                          savedInstanceState: Bundle?): View? {

    var view = inflater!!.inflate(R.layout.fragment_song_playing, container, false)
    seekbar = view?.findViewById(R.id.seekBar)
    startTimeText = view?.findViewById(R.id.startTime)
    endTimeText = view?.findViewById(R.id.endTime)
    playpauseImageButton = view?.findViewById(R.id.playPauseButton)
    nextImageButton = view?.findViewById(R.id.nextButton)
    previousImageButton = view?.findViewById(R.id.previousButton)
    loopImageButton = view?.findViewById(R.id.LoopButton)
    shuffleImageButton = view?.findViewById(R.id.shuffleButton)
    songArtistView = view?.findViewById(R.id.songArtist)
    songTitleView = view?.findViewById(R.id.songTitle)
    g1view = view?.findViewById(R.id.visualizer_view)

    return view
}

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    audioVisualization = g1view as AudioVisualization
}

override fun onAttach(context: Context?) {
    super.onAttach(context)
    myActivity = context as Activity
}

override fun onAttach(activity: Activity?) {
    super.onAttach(activity)
    myActivity = activity
}

override fun onResume() {
    super.onResume()
    audioVisualization?.onResume()
}

override fun onPause() {
    audioVisualization?.onPause()
    super.onPause()
}

override fun onDestroyView() {
    audioVisualization?.release()
    super.onDestroyView()
}

override fun onActivityCreated(savedInstanceState: Bundle?) {
    super.onActivityCreated(savedInstanceState)

    currentSongHelper = CurrentSongHelper()
    currentSongHelper?.isPlaying = true
    currentSongHelper?.isLoop = false
    currentSongHelper?.isShuffle = false
    var path: String? = null
    var songTitle: String? = null
    var songArtist: String? = null
    var songId: Long = 0
    try {
        path = arguments.getString("path")
        songTitle = arguments.getString("songTitle")
        songArtist = arguments.getString("songArtist")
        songId = arguments.getInt("songId").toLong()
        currentPosition = arguments.getInt("songPosition")
        fetchSongs = arguments.getParcelableArrayList("songData")

        currentSongHelper?.songPath = path
        currentSongHelper?.songTitle = songTitle
        currentSongHelper?.songArtist = songArtist
        currentSongHelper?.songId = songId
        currentSongHelper?.currentPosition = currentPosition

        updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)
    } catch(e: Exception) {
        e.printStackTrace()
    }
    mediaplayer = MediaPlayer()
    mediaplayer?.setAudioStreamType(AudioManager.STREAM_MUSIC)
    try {
        mediaplayer?.setDataSource(myActivity, Uri.parse(path))
        mediaplayer?.prepare()
    } catch (e: Exception) {
        e.printStackTrace()
    }

    mediaplayer?.start()
    processInformation(mediaplayer as MediaPlayer)
    if (currentSongHelper?.isPlaying as Boolean) {
        playpauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
    } else {
        playpauseImageButton?.setBackgroundResource(R.drawable.play_icon)
    }
    mediaplayer?.setOnCompletionListener {
        onSongComplete()

    }
    clickHandler()
    var visualizationHandler = DbmHandler.Factory.newVisualizerHandler(myActivity as Context, 0)
    audioVisualization?.linkTo(visualizationHandler)

    var prefsForShuffle = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)
    var isShuffleAllowed = prefsForShuffle?.getBoolean("feature", false)
    if (isShuffleAllowed as Boolean) {
        currentSongHelper?.isShuffle = true
        currentSongHelper?.isLoop = false
        shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_icon)

        loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
    } else {
        currentSongHelper?.isShuffle = false
        shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
    }
    var prefsForLoop = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)
    var isLoopAllowed = prefsForShuffle?.getBoolean("feature", false)
    if (isLoopAllowed as Boolean) {
        currentSongHelper?.isShuffle = false
        currentSongHelper?.isLoop = true
        shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)

        loopImageButton?.setBackgroundResource(R.drawable.loop_icon)
    } else {
        loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
        currentSongHelper?.isLoop = false

    }
enter code here
}

fun clickHandler() {

    shuffleImageButton?.setOnClickListener({
        var editorShuffle = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)?.edit()
        var editorLoop = myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
        if (currentSongHelper?.isShuffle as Boolean) {
            shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
            currentSongHelper?.isShuffle = false
            editorShuffle?.putBoolean("feature", false)
            editorShuffle?.apply()
        } else {
            currentSongHelper?.isShuffle = true
            currentSongHelper?.isLoop = false
            shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_icon)
            loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
            editorShuffle?.putBoolean("feature", true)
            editorShuffle?.apply()
            editorLoop?.putBoolean("feature", false)
            editorLoop?.apply()
        }
    })
    nextImageButton?.setOnClickListener({
        currentSongHelper?.isPlaying = true
        if (currentSongHelper?.isShuffle as Boolean) {
            playNext("PlayNextLikeNormalShuffle")
        } else {
            playNext("PlayNextNormal")
        }
    })
    previousImageButton?.setOnClickListener({
        currentSongHelper?.isPlaying = true
        if (currentSongHelper?.isLoop as Boolean) {
            loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
        }
        playPrevious()
    })
    loopImageButton?.setOnClickListener({
        var editorShuffle = myActivity?.getSharedPreferences(Staticated.MY_PREFS_SHUFFLE, Context.MODE_PRIVATE)?.edit()
        var editorLoop = myActivity?.getSharedPreferences(Staticated.MY_PREFS_LOOP, Context.MODE_PRIVATE)?.edit()
        if (currentSongHelper?.isLoop as Boolean) {
            currentSongHelper?.isLoop = false
            loopImageButton?.setBackgroundResource(R.drawable.loop_white_icon)
            editorLoop?.putBoolean("feature", false)
            editorLoop?.apply()
        } else {
            currentSongHelper?.isLoop = true
            currentSongHelper?.isShuffle = false
            loopImageButton?.setBackgroundResource(R.drawable.loop_icon)
            shuffleImageButton?.setBackgroundResource(R.drawable.shuffle_white_icon)
            editorShuffle?.putBoolean("feature", false)
            editorShuffle?.apply()
            editorLoop?.putBoolean("feature", true)
            editorLoop?.apply()
        }
    })
    playpauseImageButton?.setOnClickListener({
        if (mediaplayer?.isPlaying as Boolean) {
            mediaplayer?.pause()
            currentSongHelper?.isPlaying = false
            playpauseImageButton?.setBackgroundResource(R.drawable.play_icon)
        } else {
            mediaplayer?.start()
            currentSongHelper?.isPlaying = true
            playpauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
        }

    })

}

fun playNext(check: String) {
    if (check.equals("PlayNextNormal", true)) {
        currentPosition = currentPosition + 1

    } else if (check.equals("PlayNextLikeNormalShuffle", true)) {
        var randomObject = Random()
        var randomPosition = randomObject.nextInt(fetchSongs?.size?.plus(1) as Int)
        currentPosition = randomPosition

    }
    if (currentPosition == fetchSongs?.size) {
        currentPosition = 0
    }
    currentSongHelper?.isLoop = false
    var nextSong = fetchSongs?.get(currentPosition)
    currentSongHelper?.songPath = nextSong?.songData
    currentSongHelper?.songTitle = nextSong?.songTitle
    currentSongHelper?.currentPosition = currentPosition
    currentSongHelper?.songId = nextSong?.songId as Long

    updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)
    mediaplayer?.reset()
    try {
        mediaplayer?.setDataSource(myActivity, Uri.parse(currentSongHelper?.songPath))
        mediaplayer?.prepare()
        mediaplayer?.start()
        processInformation(mediaplayer as MediaPlayer)
    } catch (e: Exception) {
        e.printStackTrace()
    }

}

fun playPrevious() {
    currentPosition = currentPosition - 1

    if (currentPosition == -1) {
        currentPosition = 0
    }
    if (currentSongHelper?.isPlaying as Boolean) {
        playpauseImageButton?.setBackgroundResource(R.drawable.pause_icon)
    } else {
        playpauseImageButton?.setBackgroundResource(R.drawable.play_icon)
    }
    currentSongHelper?.isLoop = false
    var nextSong = fetchSongs?.get(currentPosition)
    currentSongHelper?.songPath = nextSong?.songData
    currentSongHelper?.songTitle = nextSong?.songTitle
    currentSongHelper?.currentPosition = currentPosition
    currentSongHelper?.songId = nextSong?.songId as Long

    updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)

    mediaplayer?.reset()
    try {
        mediaplayer?.setDataSource(activity, Uri.parse(currentSongHelper?.songPath))
        mediaplayer?.prepare()
        mediaplayer?.start()
        processInformation(mediaplayer as MediaPlayer)
    } catch (e: Exception) {
        e.printStackTrace()
    }

}

fun onSongComplete() {
    if (currentSongHelper?.isShuffle as Boolean) {
        playNext("PlayNextLikeNormalShuffle")
        currentSongHelper?.isPlaying = true
    } else {
        if (currentSongHelper?.isLoop as Boolean) {
            currentSongHelper?.isPlaying = true
            var nextSong = fetchSongs?.get(currentPosition)

            currentSongHelper?.songTitle = nextSong?.songTitle
            currentSongHelper?.songPath = nextSong?.songData
            currentSongHelper?.currentPosition = currentPosition
            currentSongHelper?.songId = nextSong?.songId as Long

            updateTextViews(currentSongHelper?.songTitle as String, currentSongHelper?.songArtist as String)
            mediaplayer?.reset()
            try {
                mediaplayer?.setDataSource(myActivity, Uri.parse(currentSongHelper?.songPath))
                mediaplayer?.prepare()
                mediaplayer?.start()

            } catch (e: Exception) {
                e.printStackTrace()
            }

        } else {
            playNext("PlayNextNormal")
            currentSongHelper?.isPlaying = true
        }
    }

}

fun updateTextViews(songtitle: String, songArtist: String) {
    songTitleView?.setText(songtitle)
    songArtistView?.setText(songArtist)
}

fun processInformation(mediaPlayer: MediaPlayer) {
    val finalTime = mediaPlayer.duration
    val startTime = mediaPlayer.currentPosition
    seekbar?.max = finalTime
    startTimeText?.setText(String.format("%d: %d",
            TimeUnit.MILLISECONDS.toMinutes(startTime.toLong()),
            TimeUnit.MILLISECONDS.toSeconds(startTime.toLong()) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(startTime?.toLong()))
    ))
    endTimeText?.setText(String.format("%d:%d",
            TimeUnit.MILLISECONDS.toMinutes(finalTime.toLong()),
            TimeUnit.MILLISECONDS.toSeconds(finalTime.toLong()) -
                    TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(finalTime?.toLong())))
    )
    seekbar?.setProgress(startTime)
    Handler().postDelayed(updateSongTime, 1000)
}

}

LOGS:

12-07 20:30:27.447 28230-28230/com.example.sanjanaadmin.echo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.sanjanaadmin.echo, PID: 28230
    kotlin.TypeCastException: null cannot be cast to non-null type kotlin.String
        at com.example.sanjanaadmin.echo.fragments.SongPlayingFragment.playNext(SongPlayingFragment.kt:314)
        at com.example.sanjanaadmin.echo.fragments.SongPlayingFragment$clickHandler$2.onClick(SongPlayingFragment.kt:250)
        at android.view.View.performClick(View.java:5268)
        at android.view.View$PerformClick.run(View.java:21550)
        at android.os.Handler.handleCallback(Handler.java:822)
        at android.os.Handler.dispatchMessage(Handler.java:104)
        at android.os.Looper.loop(Looper.java:207)
        at android.app.ActivityThread.main(ActivityThread.java:5811)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:681)

Body:
You are trying to cast a nullable value produced by a safe call (?.) to the not-null type String:

currentSongHelper?.songTitle as String

(and a few more places)

This cast will fail if the value is null. To fix this, cast to the nullable type instead String?:

currentSongHelper?.songTitle as String?

(fix the other such cases as well)


问:
BYTE, WORD and DWORD macros definition
I am trying to understand, what would be the best way to define BYTE, WORD and DWORD macros, which are mentioned in answers of this question.

```<code>#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))
</code>```

Would it be correct to assume, that:

BYTE is macro defined as
#define BYTE __uint8_t

WORD is macro defined as
#define WORD __uint16_t

DWORD is macro defined as
#define DWORD __uint32_t

If yes, why cast to another macro instead of casting to __uint8_t, __uint16_t or __uint32_t? Is it written like that to increase clarity?

I also found another question which answers include typedef, with little bit more of research I've found answers to question about comparing #define and typedef. Would typedef be better to use in this case?

答:
You have it defined at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx, and that is already defined in Windows Data Type headers for WinAPI:

```<code>typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
</code>```

and it is a type, and not a macro.

ContentLicense: CC BY-SA 4.0

Title: BYTE, WORD and DWORD macros definition

Body:
I am trying to understand, what would be the best way to define BYTE, WORD and DWORD macros, which are mentioned in answers of this question.

#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))

Would it be correct to assume, that:

BYTE is macro defined as
#define BYTE __uint8_t

WORD is macro defined as
#define WORD __uint16_t

DWORD is macro defined as
#define DWORD __uint32_t

If yes, why cast to another macro instead of casting to __uint8_t, __uint16_t or __uint32_t? Is it written like that to increase clarity?

I also found another question which answers include typedef, with little bit more of research I've found answers to question about comparing #define and typedef. Would typedef be better to use in this case?

Body:
You have it defined at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx, and that is already defined in Windows Data Type headers for WinAPI:

typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned long DWORD;

and it is a type, and not a macro.