问:
Recyclerview duplicates items from firebase becuase of a nested SingleValueEvent
Basically I'm receiving these items across the app on other tabs properly.
This tab is actually the "new" tab. It should display all of the items from the server.

The code of receiving all of the data:

```<code> private void pullDataFromFirebase(String dataType) {

    switch (dataType) {
        case "Audio":
            database = FirebaseDatabase.getInstance().getReference("Audio Categories");
            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    audioCategories = new ArrayList<Category>();

                    Category category = new Category();

                    for (DataSnapshot catData : dataSnapshot.getChildren()) {
                            category = catData.getValue(Category.class);
                        audioCategories.add(new Category(category.getImageUrl(), category.getTitle(), category.getDateOfPublish()));
                    }
                    for (int i = 0; i < audioCategories.size(); i++) {
                        catTitle = audioCategories.get(i).getTitle();
                        catRef = database.child(catTitle).child("Items");

                        catRef.addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                for (DataSnapshot data : dataSnapshot.getChildren()) {
                                    Item item = data.getValue(Item.class);
                                    item.setKindOfItem("Audio");
                                    item.setLinkToEvent("Audio item doesn't have a link");
                                    items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(),item.getLinkToEvent(),item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                                }
                                pullDataFromFirebase("Video");
                            }

                            @Override
                            public void onCancelled(DatabaseError databaseError) {
                            }
                        });
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }

            });

            break;
        case "Video":

            database = FirebaseDatabase.getInstance().getReference("Video Categories");
            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    videoCategories = new ArrayList<Category>();

                    Category category = new Category();

                    for (DataSnapshot catData : dataSnapshot.getChildren()) {
                        category = catData.getValue(Category.class);
                        videoCategories.add(new Category(category.getImageUrl(), category.getTitle(), category.getDateOfPublish()));
                    }
                    for (int i = 0; i < videoCategories.size(); i++) {
                        catTitle = videoCategories.get(i).getTitle();
                        catRef = database.child(catTitle).child("Items");

                        catRef.addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                if (dataSnapshot.exists()){
                                    for (DataSnapshot data : dataSnapshot.getChildren()) {
                                        Item item = data.getValue(Item.class);
                                        item.setKindOfItem("Video");
                                        item.setLinkToEvent("Video item doesn't have a link");
                                        items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(),item.getLinkToEvent(),item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                                    }
                                    pullDataFromFirebase("Event");
                                } else {
                                    Log.i("VIDEO_CAT_EMPTY","One of the video categories is empty.");
                                }
                            }

                            @Override
                            public void onCancelled(DatabaseError databaseError) {
                            }
                        });
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }

            });

            break;
        case "Event":
            DatabaseReference database;
            database = FirebaseDatabase.getInstance().getReference("Events");

            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    for (DataSnapshot data : dataSnapshot.getChildren()) {
                        Item item = data.getValue(Item.class);
                        item.setKindOfItem("Event");
                        items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(),item.getLinkToEvent(),item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                    }
                    setNewsRecyclerView();

                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }
            });
            break;
    }
}
</code>```

While writing this post I was investigating even further and now I know that after I'm uploading a new Audio Category in my app this is happening.
The first audio category is just duplicating the event items, and from 2 and above I can see that the video items in the list are duplicating themselves as well. **NOTE: Audio isn't duplicating itself.

I can understand that this is happening due to the nature of the function. I'm calling on OnCreateView to the

pullDataFromFirebase("Audio")

which is the first function in the series.
These are firebase functions and to populate my local RecyclerView I MUST call them this way since they are A-synchronous.
I think this is happening because of the order. (Audio first then Video then Event) it is replicating the behavior of a nested for loop.

Maybe I'm wrong.
Suggestions?

EDIT: I might found a way, I can add to the Item object a String which is a unique ID to each member of the array list... this is not optimal but It can solve the problem. (didn't check that yet.)

答:
Oh My God!
I cannot believe it that it was so simple and it slipped away from me.
The answer is :

To understand the logic:

The nested OnDataChange has two places to execute the desired function (that will work on the local recyclerview) which are after the "for" that I'm gathering with it the information from the server and populating the Item.class and the array list.
I have executed both of the pullDataFromFirebase("Video")
and pullDataFromFirebase("Event")
on the 2nd OnDataChange, it was actually a syntax error which in some cases(depends on the current data situation in the server) led to multiplying of both of these functions.

Example from the code:

```<code>            case "Video":

            database = FirebaseDatabase.getInstance().getReference("Video Categories");
            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    if (dataSnapshot.exists()) {
                        videoCategories = new ArrayList<Category>();
                        Category category = new Category();

                        for (DataSnapshot catData : dataSnapshot.getChildren()) {
                            category = catData.getValue(Category.class);
                            videoCategories.add(new Category(category.getImageUrl(), category.getTitle(), category.getDateOfPublish()));
                        }
                        for (int i = 0; i < videoCategories.size(); i++) {
                            catTitle = videoCategories.get(i).getTitle();
                            catRef = database.child(catTitle).child("Items");

                            catRef.addListenerForSingleValueEvent(new ValueEventListener() {
                                @Override
                                public void onDataChange(DataSnapshot dataSnapshot) {
                                    if (dataSnapshot.exists()) {
                                        for (DataSnapshot data : dataSnapshot.getChildren()) {
                                            Item item = data.getValue(Item.class);
                                            item.setKindOfItem("Video");
                                            item.setLinkToEvent("Video item doesn't have a link");
                                            items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(), item.getLinkToEvent(), item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                                        }
           **************THE FUNCTION WAS LOCATED HERE ***************

                                    } else {
                                        Log.i("ONE_OR_MORE_VIDEO_EMPTY", "One or more of the categories are empty.");
                                    }
                                }

                                @Override
                                public void onCancelled(DatabaseError databaseError) {
                                }
                            });
                        }
                    } else {
                        Log.i("VIDEO_CAT_EMPTY", "There are no video categories to show");
                    }

      **************Actually the Function Should Be here ***************

                    pullDataFromFirebase("Event");
                }
                @Override
                public void onCancelled(DatabaseError databaseError) {
                }

            });
</code>```

So what can we learn from that?
When you "play" with nested SingleValueEventListener or actually any nested-style function, BE EXTREMELY CAREFUL.

Thanks Again Alex.

Body:
Basically I'm receiving these items across the app on other tabs properly.
This tab is actually the "new" tab. It should display all of the items from the server.

The code of receiving all of the data:

 private void pullDataFromFirebase(String dataType) {

    switch (dataType) {
        case "Audio":
            database = FirebaseDatabase.getInstance().getReference("Audio Categories");
            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    audioCategories = new ArrayList<Category>();

                    Category category = new Category();

                    for (DataSnapshot catData : dataSnapshot.getChildren()) {
                            category = catData.getValue(Category.class);
                        audioCategories.add(new Category(category.getImageUrl(), category.getTitle(), category.getDateOfPublish()));
                    }
                    for (int i = 0; i < audioCategories.size(); i++) {
                        catTitle = audioCategories.get(i).getTitle();
                        catRef = database.child(catTitle).child("Items");

                        catRef.addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                for (DataSnapshot data : dataSnapshot.getChildren()) {
                                    Item item = data.getValue(Item.class);
                                    item.setKindOfItem("Audio");
                                    item.setLinkToEvent("Audio item doesn't have a link");
                                    items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(),item.getLinkToEvent(),item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                                }
                                pullDataFromFirebase("Video");
                            }

                            @Override
                            public void onCancelled(DatabaseError databaseError) {
                            }
                        });
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }

            });

            break;
        case "Video":

            database = FirebaseDatabase.getInstance().getReference("Video Categories");
            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    videoCategories = new ArrayList<Category>();

                    Category category = new Category();

                    for (DataSnapshot catData : dataSnapshot.getChildren()) {
                        category = catData.getValue(Category.class);
                        videoCategories.add(new Category(category.getImageUrl(), category.getTitle(), category.getDateOfPublish()));
                    }
                    for (int i = 0; i < videoCategories.size(); i++) {
                        catTitle = videoCategories.get(i).getTitle();
                        catRef = database.child(catTitle).child("Items");

                        catRef.addListenerForSingleValueEvent(new ValueEventListener() {
                            @Override
                            public void onDataChange(DataSnapshot dataSnapshot) {
                                if (dataSnapshot.exists()){
                                    for (DataSnapshot data : dataSnapshot.getChildren()) {
                                        Item item = data.getValue(Item.class);
                                        item.setKindOfItem("Video");
                                        item.setLinkToEvent("Video item doesn't have a link");
                                        items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(),item.getLinkToEvent(),item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                                    }
                                    pullDataFromFirebase("Event");
                                } else {
                                    Log.i("VIDEO_CAT_EMPTY","One of the video categories is empty.");
                                }
                            }

                            @Override
                            public void onCancelled(DatabaseError databaseError) {
                            }
                        });
                    }
                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }

            });

            break;
        case "Event":
            DatabaseReference database;
            database = FirebaseDatabase.getInstance().getReference("Events");

            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {

                    for (DataSnapshot data : dataSnapshot.getChildren()) {
                        Item item = data.getValue(Item.class);
                        item.setKindOfItem("Event");
                        items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(),item.getLinkToEvent(),item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                    }
                    setNewsRecyclerView();

                }

                @Override
                public void onCancelled(DatabaseError databaseError) {
                }
            });
            break;
    }
}

While writing this post I was investigating even further and now I know that after I'm uploading a new Audio Category in my app this is happening.
The first audio category is just duplicating the event items, and from 2 and above I can see that the video items in the list are duplicating themselves as well. **NOTE: Audio isn't duplicating itself.

I can understand that this is happening due to the nature of the function. I'm calling on OnCreateView to the

pullDataFromFirebase("Audio")

which is the first function in the series.
These are firebase functions and to populate my local RecyclerView I MUST call them this way since they are A-synchronous.
I think this is happening because of the order. (Audio first then Video then Event) it is replicating the behavior of a nested for loop.

Maybe I'm wrong.
Suggestions?

EDIT: I might found a way, I can add to the Item object a String which is a unique ID to each member of the array list... this is not optimal but It can solve the problem. (didn't check that yet.)

Body:
Oh My God!
I cannot believe it that it was so simple and it slipped away from me.
The answer is :

To understand the logic:

The nested OnDataChange has two places to execute the desired function (that will work on the local recyclerview) which are after the "for" that I'm gathering with it the information from the server and populating the Item.class and the array list.
I have executed both of the pullDataFromFirebase("Video")
and pullDataFromFirebase("Event")
on the 2nd OnDataChange, it was actually a syntax error which in some cases(depends on the current data situation in the server) led to multiplying of both of these functions.

Example from the code:

            case "Video":

            database = FirebaseDatabase.getInstance().getReference("Video Categories");
            database.addListenerForSingleValueEvent(new ValueEventListener() {
                @Override
                public void onDataChange(DataSnapshot dataSnapshot) {
                    if (dataSnapshot.exists()) {
                        videoCategories = new ArrayList<Category>();
                        Category category = new Category();

                        for (DataSnapshot catData : dataSnapshot.getChildren()) {
                            category = catData.getValue(Category.class);
                            videoCategories.add(new Category(category.getImageUrl(), category.getTitle(), category.getDateOfPublish()));
                        }
                        for (int i = 0; i < videoCategories.size(); i++) {
                            catTitle = videoCategories.get(i).getTitle();
                            catRef = database.child(catTitle).child("Items");

                            catRef.addListenerForSingleValueEvent(new ValueEventListener() {
                                @Override
                                public void onDataChange(DataSnapshot dataSnapshot) {
                                    if (dataSnapshot.exists()) {
                                        for (DataSnapshot data : dataSnapshot.getChildren()) {
                                            Item item = data.getValue(Item.class);
                                            item.setKindOfItem("Video");
                                            item.setLinkToEvent("Video item doesn't have a link");
                                            items.add(new Item(item.getImageUrl(), item.getTitle(), item.getSummary(), item.getembeddedIDOrPowerLinkID(), item.getLinkToEvent(), item.getKey(), item.getDateOfPublish(), item.getKindOfItem()));
                                        }
           **************THE FUNCTION WAS LOCATED HERE ***************

                                    } else {
                                        Log.i("ONE_OR_MORE_VIDEO_EMPTY", "One or more of the categories are empty.");
                                    }
                                }

                                @Override
                                public void onCancelled(DatabaseError databaseError) {
                                }
                            });
                        }
                    } else {
                        Log.i("VIDEO_CAT_EMPTY", "There are no video categories to show");
                    }

      **************Actually the Function Should Be here ***************

                    pullDataFromFirebase("Event");
                }
                @Override
                public void onCancelled(DatabaseError databaseError) {
                }

            });

So what can we learn from that?
When you "play" with nested SingleValueEventListener or actually any nested-style function, BE EXTREMELY CAREFUL.

Thanks Again Alex.


来源: stackexchange

问:
Changing application.properties in AWS for a Spring Boot webapp
I've made a spring project using Boot. the project runs fine locally. It's a simple webapp connected to a mysql database. The configuration path is:

src/main/resources/application.properties

With parameters like this:

```<code>spring.datasource.url = xxx
spring.datasource.username = xxx
spring.datasource.password = xxx
</code>```

Now, I've deployed the app in AWS without problems. I've configured the database already but when the app tries to start I'm getting this error:

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

I guess that is using my local configuratión file that was packed in the war file. Now, how can I change those values in the AWS? O do I need to pack the war with the correct application.properties in that server?

Thanks!

答:
From personal experience, best way of handling this is by creating properties files for each environment. I.e:

```<code>application-dev.properties
application-prod.properties
application-test.properties
</code>```

and then prior to build just switch spring.profiles.active in your application.properties file to dev, prod or test.

If your are still getting this error once your configuration is ok, my advice is to check does ip address of your deployment server should be authorized on production db instance in order to connect.

ContentLicense: CC BY-SA 3.0

Body:
I've made a spring project using Boot. the project runs fine locally. It's a simple webapp connected to a mysql database. The configuration path is:

src/main/resources/application.properties

With parameters like this:

spring.datasource.url = xxx
spring.datasource.username = xxx
spring.datasource.password = xxx

Now, I've deployed the app in AWS without problems. I've configured the database already but when the app tries to start I'm getting this error:

The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.

I guess that is using my local configuratión file that was packed in the war file. Now, how can I change those values in the AWS? O do I need to pack the war with the correct application.properties in that server?

Thanks!

Body:
From personal experience, best way of handling this is by creating properties files for each environment. I.e:

application-dev.properties
application-prod.properties
application-test.properties

and then prior to build just switch spring.profiles.active in your application.properties file to dev, prod or test.

If your are still getting this error once your configuration is ok, my advice is to check does ip address of your deployment server should be authorized on production db instance in order to connect.


问:
Disable scientific notation in python json.dumps output
json.dumps outputs small float or decimal values using scientific notation, which is unacceptable to the json-rpc application this output is sent to.

```<code>>>> import json
>>> json.dumps({"x": 0.0000001})
'{"x": 1e-07}'
</code>```

I want this output instead:

```<code>'{"x": 0.0000001}'
</code>```

It would be ideal to avoid introducing additional dependencies.

答:
found somewhere on the internet

```<code>import json
from json import encoder
encoder.FLOAT_REPR = lambda o: format(o, '.2f')
</code>```

after this

```<code>>>> json.dumps({'gps': [51.5, 17.5]})
'{"gps": [51.5, 17.5]}'
</code>```

Body:
json.dumps outputs small float or decimal values using scientific notation, which is unacceptable to the json-rpc application this output is sent to.

>>> import json
>>> json.dumps({"x": 0.0000001})
'{"x": 1e-07}'

I want this output instead:

'{"x": 0.0000001}'

It would be ideal to avoid introducing additional dependencies.

Body:
found somewhere on the internet

import json
from json import encoder
encoder.FLOAT_REPR = lambda o: format(o, '.2f')

after this

>>> json.dumps({'gps': [51.5, 17.5]})
'{"gps": [51.5, 17.5]}'


问:
Python 2.7, MySQL, JSON, & DateTime - How can I remove the T between the Date and Time in the timestamp field?
I have a MySQL database with a few tables. I wrote a python script to dump some of the tables data into a JSON file. I am a bit confused with dumping the date and time stamp.

Here is the code sample, conversion.py:

```<code>import MySQLdb
import json
import collections
from datetime import date, datetime

#connect to database
conn = MySQLdb.connect(host= "localhost", user="root", passwd="root", db="testdb")

#Fetch rows
sql  = "SELECT * from offices"
cursor = conn.cursor()
cursor.execute(sql)
rows = cursor.fetchall()

data = []

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

for row in rows:
    d = collections.OrderedDict()
    d['officeCode'] = row[0]
    d['city'] = row[1]
    d['phone'] = row[2]
    d['eff_date'] = row[3]
    d['lastupdatedby'] = row[4]
    d['state'] = row[5]
    d['country'] = row[6]
    d['postalcode'] = row[7]
    d['territory'] = row[8]
    data.append(d)

with open('data.json', 'w') as outfile:

    json.dump(data, outfile, default=json_serial)

conn.close()
</code>```

When I execute this code, a JSON file is created which is fine. I have a problem with two fields, eff_date which is a date type in database and lastupdatedby is a timestamp type in the database.

```<code>"eff_date": "2015-09-23"

"lastupdatedby": "2016-08019T08:13:53"
</code>```

So, in my JSON file, eff_time is created fine but lastupdatedby is getting a T in middle of date and time as shown above. But, in my actual database there is no T between the date and time. I would like to get rid of that T because I am planning to dump this file into a different database and I don't think it will accept that format.

Any help will be much appreciated.

答:
The T between the date and time is per the ISO 8601 format.

And that's format returned by the datetime.isoformat function, found in the code here:

```<code>return obj.isoformat()
</code>```

(That happens to be the format that Javascript is expecting.)

If we want to return a string different format, we probably need to use a different function, e.g. strftime function in place of isoformat.

If isoformat is working for the date objects, leave that alone. Just do the strftime for a datetime object.

The format string "%Y-%m-%d %H:%M:%S" might suit your needs.

https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior

Body:
I have a MySQL database with a few tables. I wrote a python script to dump some of the tables data into a JSON file. I am a bit confused with dumping the date and time stamp.

Here is the code sample, conversion.py:

import MySQLdb
import json
import collections
from datetime import date, datetime

#connect to database
conn = MySQLdb.connect(host= "localhost", user="root", passwd="root", db="testdb")

#Fetch rows
sql  = "SELECT * from offices"
cursor = conn.cursor()
cursor.execute(sql)
rows = cursor.fetchall()

data = []

def json_serial(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, (datetime, date)):
        return obj.isoformat()
    raise TypeError ("Type %s not serializable" % type(obj))

for row in rows:
    d = collections.OrderedDict()
    d['officeCode'] = row[0]
    d['city'] = row[1]
    d['phone'] = row[2]
    d['eff_date'] = row[3]
    d['lastupdatedby'] = row[4]
    d['state'] = row[5]
    d['country'] = row[6]
    d['postalcode'] = row[7]
    d['territory'] = row[8]
    data.append(d)

with open('data.json', 'w') as outfile:

    json.dump(data, outfile, default=json_serial)

conn.close()

When I execute this code, a JSON file is created which is fine. I have a problem with two fields, eff_date which is a date type in database and lastupdatedby is a timestamp type in the database.

"eff_date": "2015-09-23"

"lastupdatedby": "2016-08019T08:13:53"

So, in my JSON file, eff_time is created fine but lastupdatedby is getting a T in middle of date and time as shown above. But, in my actual database there is no T between the date and time. I would like to get rid of that T because I am planning to dump this file into a different database and I don't think it will accept that format.

Any help will be much appreciated.

Body:
The T between the date and time is per the ISO 8601 format.

And that's format returned by the datetime.isoformat function, found in the code here:

return obj.isoformat()

(That happens to be the format that Javascript is expecting.)

If we want to return a string different format, we probably need to use a different function, e.g. strftime function in place of isoformat.

If isoformat is working for the date objects, leave that alone. Just do the strftime for a datetime object.

The format string "%Y-%m-%d %H:%M:%S" might suit your needs.

https://docs.python.org/2/library/datetime.html#strftime-strptime-behavior


问:
Design pattern for self-referencing ordered tree of objects (C#/ASP.Net Core/EFCore)
First I apologise if I should have been able to find this myself through search... I'm rusty and learning a lot of new stuff so I'm not even sure if I'm using the right terms to describe what I want - don't kick the noob please :)

Question: Part 1 - Specific scenario
I am trying to build classes to produce a tree of "goal objects", where

a) order matters and needs to be retained,

b) each goal object in the tree may stand alone as a single object, or comprise a collection of subgoals (and those subgoals further subgoals etc - let's say to a depth of 5 levels),

c) ability to edit the tree efficiently is necessary (including changing the order or index of any goal object, adding / removing / reordering / moving  subgoals, pruning/adding branches to the tree).
I can certainly work out a way to do this, but I strongly suspect my way will be highly inefficient both in terms of memory / processing and in terms of quantity of code required to manage the editing etc.

My question therefor: Can anyone point me to a design pattern or tutorial that will show me an efficient way to do this - or something similar that I can adapt?
(I am currently working in C# & ASP.NET Core with EFCore pointing to SQLserver)

Part 2: Recommendations for a book / site that has an excellent set of fundamental design patterns suitable for C# would also be welcome.

Many thanks for any help you can offer.
Chris

答:
Attempt to answer my own questions:

Part 1: The closest I have found so far is the Composite design pattern, using an abstract class from which leaf and composite classes inherit. However, I think I would have to add to this a) mechanism to convert a leaf to a composite and vice versa, and b) from what I can see this pattern doesn't solve the "order matters and changes" constraint so I would have to implement some order index and manage changes in order - anyone has an efficient way to do these things?

Part 2: Found Gang of Four, and http://www.dofactory.com/net/design-patterns, so consider part 2 closed but welcome any other suggestions obviously.


问:
Cordova: Error: The WIFI_SERVICE must be looked up on the Application context or memory will leak on devices < Android N
I'm getting the follwoing error when trying to build my app:

```<code>Error: The WIFI_SERVICE must be looked up on the Application context or memory will leak on devices < Android N. Try changing this.cordova.getActivity() to this.cordova.getActivity().getApplicationContext() [WifiManagerLeak]
    Intent settingsIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
                 ^

Explanation for issues of type "WifiManagerLeak":
On versions prior to Android N (24), initializing the WifiManager via
Context#getSystemService can cause a memory leak if the context is not the
application context. Change context.getSystemService(...) to
context.getApplicationContext().getSystemService(...).

2 errors, 0 warnings
</code>```

I'm using node v6.11.2, cordova 6.5.0 and cordova-android 6.4.0 and gradle 4.1

答:
EDIT: as said by @DaveAlden updating cordova-diagnostic-plugin to current version and cordova-android to 6.4.0 worked.

WORKAROUND (in case that you can't update plugins):
Same situation is happening to me. My workaround was downgrading to Android Cordova < 6.4:

cordova platform rm android

And then:

cordova platform add android@6.3 (or 6.2, depending on your plugins)

I'm still getting what causes the problem, but that worked for me as solution.

My analysis:

Cordova Android 6.4.0 uses inside the project Gradle 4.1 and it is used for Android Plugin for Gradle 3.3.0+

Cordova Android <6.4 uses Gradle 2.14.1, and it is used for Android Plugin for Gradle 2.3.0+

(Source: https://developer.android.com/studio/releases/gradle-plugin.html)

Edit: seems to be a legit posible memory leak in the source file, exposed by Gradle or Android Plugin for Gradle.
In my case, was due the plugin cordova.plugins.diagnostic.api-22 when running the task :lintVitalRelease. I left an issue in the plugin Github.

Which file of yours is marked with error? Is that due a plugin?

Body:
I'm getting the follwoing error when trying to build my app:

Error: The WIFI_SERVICE must be looked up on the Application context or memory will leak on devices < Android N. Try changing this.cordova.getActivity() to this.cordova.getActivity().getApplicationContext() [WifiManagerLeak]
    Intent settingsIntent = new Intent(Settings.ACTION_WIFI_SETTINGS);
                 ^

Explanation for issues of type "WifiManagerLeak":
On versions prior to Android N (24), initializing the WifiManager via
Context#getSystemService can cause a memory leak if the context is not the
application context. Change context.getSystemService(...) to
context.getApplicationContext().getSystemService(...).

2 errors, 0 warnings

I'm using node v6.11.2, cordova 6.5.0 and cordova-android 6.4.0 and gradle 4.1


问:
Java - possible to modify and parse gzipped xml files without unzipping?
I have an arraylist of gzipped xml files. Is it possible to view and manipulate the contents of these xml files all without unzipping them and taking up disk space? If so, what would be the correct class(es) to use for this task?

I know I can create a gzipinputstream from a fileinputstream of the zip file but from there I'm not sure what to do. I have only this written:

```<code> GZIPInputStream in = new GZIPInputStream(new FileInputStream(zippedFiles.get(i)));
</code>```

I need some way to parse text within the xml files and modify the xml itself but again, extracting all of them would take up too much disk space.

答: What exactly are you going to achieve? You can extract the file into memory using a ByteArrayOutputStream and convert it into a byte-Array that you forward to your XML parser library (converting it to String and passing that is not recommended as the encoding is specified inside the XML file itself and the conversion to String must therefore be done by the XML parser internally). Most XML parsers also support reading directly from any InputStream, so you could pass yours directly to it which will probably further reduce your memory consumption. Disk space will only be occupied when writing data back to it by simply reversing the described procedure. Still, as you directly replace the source file by overwriting it, there is nowhere any disk space wasted.

Body:
I have an arraylist of gzipped xml files. Is it possible to view and manipulate the contents of these xml files all without unzipping them and taking up disk space? If so, what would be the correct class(es) to use for this task?

I know I can create a gzipinputstream from a fileinputstream of the zip file but from there I'm not sure what to do. I have only this written:

 GZIPInputStream in = new GZIPInputStream(new FileInputStream(zippedFiles.get(i)));

I need some way to parse text within the xml files and modify the xml itself but again, extracting all of them would take up too much disk space.


问:
How to scroll the page smoothly?
I need to scroll the page on load to a certain position on the page in an animated manner.  And it works fine (using jQuery's animate):

```<code>$(document).ready(function () {
    $('html, body').animate({
        scrollTop: $('#today').offset().top - 50
    }, 800, "linear");
});
</code>```

However, one thing that it is not is smooth.  Particularly on a mobile device it feels very jerky.

I've seen some CSS animations (using transition and transform) that are very smooth but can't figure out how to apply it to page scrolling.  Is it possible to do what I want using CSS?

答:
Try setting the following css:

```<code><style type="text/css">
    html {
      scroll-behavior: smooth !important;
    }
</style>
</code>```

You could also try using vanilla JavaScript instead of jQuery:

```<code>function showIt(el_id) {
    var el = document.getElementById(el_id);
    el.scrollIntoView(true, {behavior: "smooth"});
}
showIt('today')
</code>```

Also consider adding an itermediary element in the middle of the page, example:

```<code><div id="middle" style="display: none;"></div>

function showIt(el_id) {
    var middle_el = document.getElementById('middle');
    var el = document.getElementById(el_id);
    middle_el.scrollIntoView(true, {behavior: "instant"});  // Go to middle directly and then scroll slowly to #today.
    el.scrollIntoView(true, {behavior: "smooth"});
}
showIt('today')
</code>```

More info on scrollIntoView: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

Also you might be interest in: Scrolling slow on mobile/ios when using overflow:Scroll if you are on iOS

Title: How to scroll the page smoothly?

Body:
I need to scroll the page on load to a certain position on the page in an animated manner.  And it works fine (using jQuery's animate):

$(document).ready(function () {
    $('html, body').animate({
        scrollTop: $('#today').offset().top - 50
    }, 800, "linear");
});

However, one thing that it is not is smooth.  Particularly on a mobile device it feels very jerky.

I've seen some CSS animations (using transition and transform) that are very smooth but can't figure out how to apply it to page scrolling.  Is it possible to do what I want using CSS?

Body:
Try setting the following css:

<style type="text/css">
    html {
      scroll-behavior: smooth !important;
    }
</style>

You could also try using vanilla JavaScript instead of jQuery:

function showIt(el_id) {
    var el = document.getElementById(el_id);
    el.scrollIntoView(true, {behavior: "smooth"});
}
showIt('today')

Also consider adding an itermediary element in the middle of the page, example:

<div id="middle" style="display: none;"></div>

function showIt(el_id) {
    var middle_el = document.getElementById('middle');
    var el = document.getElementById(el_id);
    middle_el.scrollIntoView(true, {behavior: "instant"});  // Go to middle directly and then scroll slowly to #today.
    el.scrollIntoView(true, {behavior: "smooth"});
}
showIt('today')

More info on scrollIntoView: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView

Also you might be interest in: Scrolling slow on mobile/ios when using overflow:Scroll if you are on iOS


问:
android app unable run in Motorola droid
Hi i am new to android. i developed an android app using 2.1 version in eclipse Ganymede.
i used SQLite data base to store data and it will show the stored values when loading page My app is running perfectly in Sony Ericsson Xperia but it was not working in motorola droid which is having os Android 2.1 i dont know what is the cause. is there need to give any special permissions in manifest file to run app in droid or other mobile comapanies or any other issue occured by using the SQLite database?

Please respond for my request

答: The short answer is no, there's nothing about SQLite databases that requires any permission.  I have a published app in the market that uses a database and requests no permissions.  I also happen to know it runs fine on the original Droid because that's the phone I carry.</p>

ContentLicense: CC BY-SA 2.5


问:
How to toggle a button to an active state using vanilla JS?
I have a list of 20 buttons on a page. When I click on a button I want it to switch to an "active" state. In this active state it will be a different color. I would like to do this using only vanilla javascript and css.

I have the following code to create the buttons:

```<code>var button;
createButtons();

function createButtons() {
  for (i = 0; i < 20; i++) {
    //creates a new button
    button = document.createElement('Button');

    //sets correct button number and button text
    var index = i + 1;
    var text = document.createTextNode('Button ' + index);
    button.appendChild(text);
    button.className += "button";
    button.className += " default-button";
    document.body.appendChild(button);
  }
}
</code>```

答:
Assuming you only want one button "active" at a time, I would just use the CSS :focus / :active pseudo-class. For example

for (let i = 1; i <= 20; i++) {
  let btn = document.createElement('button')
  btn.textContent = `Button ${i}`
  btn.classList.add('button', 'default-button')
  document.body.appendChild(btn)
}```
<pre class="snippet-code-css lang-css prettyprint-override"><code>.button {
  background-color: blue;
  color: white;
  font-weight: bold;
}
.button:active, .button:focus {
  background-color: red;
}</code>```

Body:
I have a list of 20 buttons on a page. When I click on a button I want it to switch to an "active" state. In this active state it will be a different color. I would like to do this using only vanilla javascript and css.

I have the following code to create the buttons:

var button;
createButtons();

function createButtons() {
  for (i = 0; i < 20; i++) {
    //creates a new button
    button = document.createElement('Button');

    //sets correct button number and button text
    var index = i + 1;
    var text = document.createTextNode('Button ' + index);
    button.appendChild(text);
    button.className += "button";
    button.className += " default-button";
    document.body.appendChild(button);
  }
}

Body:
Assuming you only want one button "active" at a time, I would just use the CSS :focus / :active pseudo-class. For example

for (let i = 1; i <= 20; i++) {
  let btn = document.createElement('button')
  btn.textContent = `Button ${i}`
  btn.classList.add('button', 'default-button')
  document.body.appendChild(btn)
}

.button {
  background-color: blue;
  color: white;
  font-weight: bold;
}
.button:active, .button:focus {
  background-color: red;
}


问:
SSRS adding percentages to the end of the line
So I have a report that looks like this

I am trying to add a percentage of total in the last column that works the same way the current Total is working right now.  For instance nest to the total for email I would like to see 88% (Total types, 214 emails divided by the Total of 244).   How do I do that in SSRS?  Here is the groupings

答:
Basically it should look something like this.

```<code>=SWITCH (
        Count(Fields!Customer.Value) = 0, 0 ,
        True, Count(Fields!Customer.Value, "Type")/Count(Fields!Customer.Value, "Employee")
        )
</code>```

I'm using SWITCH here as it stops evaluateing when the first true condition is met, if not you can run into divide by zero issues.

So, we're saying.... if the count of the customer fields is zero then just return 0, then the True just acts like an else it catches anything not caught by any previous condition/result pairs. So if we have something to count then count the number of non-NULL values in the Type group and divide by the number of non-NULL values at the employee level (in the Employee group scope).

There is no need to multiple the result up by 100, all you need to do is format the cell as P0 or P2 or however many decimal places you want to show. So in your case the returned value would be 0.87704 but would be formatted assuming you used p1, as "87.7%"

Body:
Basically it should look something like this.

=SWITCH (
        Count(Fields!Customer.Value) = 0, 0 ,
        True, Count(Fields!Customer.Value, "Type")/Count(Fields!Customer.Value, "Employee")
        )

I'm using SWITCH here as it stops evaluateing when the first true condition is met, if not you can run into divide by zero issues.

So, we're saying.... if the count of the customer fields is zero then just return 0, then the True just acts like an else it catches anything not caught by any previous condition/result pairs. So if we have something to count then count the number of non-NULL values in the Type group and divide by the number of non-NULL values at the employee level (in the Employee group scope).

There is no need to multiple the result up by 100, all you need to do is format the cell as P0 or P2 or however many decimal places you want to show. So in your case the returned value would be 0.87704 but would be formatted assuming you used p1, as "87.7%"


问:
How do I reliably determine file type when FileMagic is not an option?
I'm using Rails 5.0.3.  How do I reliably determine file type (this is from a file on my computer, not one I just downloaded from the Internet) without relying on file extensions?  I would like a cross-platform way to do this only because I'm using Mac for development and Linux for test/prod.  Also, the gem file magic is not an option because of this error</p>

```<code>Bundler could not find compatible versions for gem "rails":
  In Gemfile:
    rails (~> 5.0.1)

    filemagic was resolved to 0.3.5.0, which depends on
      rails (< 5, >= 4.2.0)
</code>```

答:
filemagic isn't the gem you're looking for. This appears to be someone's project not intended for public consumption (the rubygems page links to a company's website, and no source code is available).

Instead, install the ruby-filemagic gem. Here's the source and documentation. We can use the library like so:

```<code>begin
  fm = FileMagic.new(FileMagic::MAGIC_MIME)
  puts fm.file("foo.txt", true)
ensure
  fm.close
end
</code>```

...or by using the open() helper method, which automatically closes the resource for us:

```<code>FileMagic.open(FileMagic::MAGIC_MIME) { |fm| puts fm.file("foo.txt", true) }
</code>```

This also works with yet another helper, mime(), which additionally sets the flag for us:

```<code>FileMagic.mime { |fm| puts fm.file("foo.txt", true) }
</code>```

This gem relies on libmagic, a library used to identify file types using the file's magic number. The file command, commonly found on Unix/Linux systems, uses the same library:

```<code>$ file --mime-type foo.txt
foo.txt: text/plain
</code>```

We can also invoke this command from the Ruby application to get a file's MIME type:

```<code>IO.popen(["file", "--mime-type", "--brief", "foo.txt"]) { |io| puts io.read.chomp }
</code>```

MimeMagic is an alternative to FileMagic.

Body:
I'm using Rails 5.0.3.  How do I reliably determine file type (this is from a file on my computer, not one I just downloaded from the Internet) without relying on file extensions?  I would like a cross-platform way to do this only because I'm using Mac for development and Linux for test/prod.  Also, the gem file magic is not an option because of this error

Bundler could not find compatible versions for gem "rails":
  In Gemfile:
    rails (~> 5.0.1)

    filemagic was resolved to 0.3.5.0, which depends on
      rails (< 5, >= 4.2.0)

Body:
filemagic isn't the gem you're looking for. This appears to be someone's project not intended for public consumption (the rubygems page links to a company's website, and no source code is available).

Instead, install the ruby-filemagic gem. Here's the source and documentation. We can use the library like so:

begin
  fm = FileMagic.new(FileMagic::MAGIC_MIME)
  puts fm.file("foo.txt", true)
ensure
  fm.close
end

...or by using the open() helper method, which automatically closes the resource for us:

FileMagic.open(FileMagic::MAGIC_MIME) { |fm| puts fm.file("foo.txt", true) }

This also works with yet another helper, mime(), which additionally sets the flag for us:

FileMagic.mime { |fm| puts fm.file("foo.txt", true) }

This gem relies on libmagic, a library used to identify file types using the file's magic number. The file command, commonly found on Unix/Linux systems, uses the same library:

$ file --mime-type foo.txt
foo.txt: text/plain

We can also invoke this command from the Ruby application to get a file's MIME type:

IO.popen(["file", "--mime-type", "--brief", "foo.txt"]) { |io| puts io.read.chomp }

MimeMagic is an alternative to FileMagic.


问:
Change cell height by the content of the textView inside the cell
I have a Table View called todoTableView with cells that created by the user.
Each cell has Text View.
I want to change the height of the cell by the content of the Text View.
This is what I tried:

```<code>func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell: TableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! TableViewCell
        cell.bounds.size.height = cell.textView.bounds.size.height

        return cell
    }
</code>```

答:
Irfan's answer didn't work for me.

It works after I go to Size Inspector and check "Automatic" for "Row Height".

Body:
I have a Table View called todoTableView with cells that created by the user.
Each cell has Text View.
I want to change the height of the cell by the content of the Text View.
This is what I tried:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell: TableViewCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath:indexPath) as! TableViewCell
        cell.bounds.size.height = cell.textView.bounds.size.height

        return cell
    }


问:
How to set layout_columnWeight for a GridLayout child when added programmatically?
I'd like to use a GridLayout (not GridView) as board for a game like chess or checkers. As I'm a little reluctant to use an xml file with 64 child Views, I've tried adding them programmatically.

To keep things simple, I started with using TextViews as child Views for the GridLayout.

My problem is that the Views are not distributed evenly, and that I don't know how to get an even distribution in my java code. There is no method like "setWeight()" for setting layout_columnWeight and layout_rowWeight.

At present, this is my activity_dynamic_grid_layout.xml:

```<code><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

<ImageView
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:id="@+id/ivLogo"
    android:background="#ff0000"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"/>

<android.support.v7.widget.GridLayout
    android:id="@+id/grid_layout"
    android:background="#004080"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/ivLogo"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginTop="36dp">

</android.support.v7.widget.GridLayout>
</code>```

I've set the GridLayout width and height to match_parent here, but I'm changing them at runtime using a ViewTreeObserver.OnPreDrawListener in order to get a square board. This works, the colored background is showing a square space as intended.

My onCreate()

```<code>@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_dynamic_grid_layout);

    GridLayout gl = (GridLayout) findViewById(R.id.grid_layout);
    gl.setColumnCount(8);
    gl.setRowCount(8);

    for(int i=0; i<gl.getRowCount(); i++)
    {
        GridLayout.Spec rowSpec = GridLayout.spec(i, 1, GridLayout.FILL);

        for(int j=0;j<gl.getColumnCount();j++)
        {
            GridLayout.Spec colSpec = GridLayout.spec(j,1, GridLayout.FILL);

            TextView tvChild = new TextView(this);
            tvChild.setText("[ " + i + " | " + j + " ]");
            tvChild.setTextSize(18f);
            tvChild.setTextColor(Color.WHITE);
            tvChild.setGravity(Gravity.CENTER);

            GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams();
            myGLP.rowSpec = rowSpec;
            myGLP.columnSpec = colSpec;

            gl.addView(tvChild, myGLP );
        }
    }

    final View rootView = findViewById(R.id.dynamic_root);

    rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
    {
        @Override
        public boolean onPreDraw()
        {
            int w = rootView.getMeasuredWidth();
            int h = rootView.getMeasuredHeight();
            int min = Math.min(w, h);

            ViewGroup.LayoutParams lp = gl.getLayoutParams();
            lp.width = min - min % 9;
            lp.height = lp.width;
            gl.setLayoutParams(lp);

            rootView.getViewTreeObserver().removeOnPreDrawListener(this);

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

What I've tried already:

I put one TextView child in the layout file and tried to copy the layout_columnWeight and layout_rowWeight from its GridLayout.LayoutParams:

```<code> <android.support.v7.widget.GridLayout
 ...>
    <TextView
        android:id="@+id/clone_my_params"
        android:text="[ 0 | 0 ]"
        android:textColor="#ffffff"
        android:textSize="18sp"
        app:layout_column="0"
        app:layout_row="0"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
    />
</android.support.v7.widget.GridLayout>
</code>```

Additional code in onCreate(), before the double loop:

```<code>TextView v = (TextView)gl.findViewById(R.id.clone_my_params);
v.setGravity(Gravity.CENTER);
GridLayout.LayoutParams gridLayoutParamsToCopy = new GridLayout.LayoutParams(v.getLayoutParams());
</code>```

Inside the loop, I skipped (i,j) = (0,0) and changed

```<code> GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams();
</code>```

to

```<code> GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams(gridLayoutParamsToCopy);
</code>```

Before the change, all elements were in the upper left corner, the excess space was given to the last row/ column. After the change, the first row/ column had the excess space, no change for the other elements.

Calling gl.invalidate() and/or gl.requestLayout() after the double loop had no effect.

So it seems that I did not manage to set the desired weight by using the copy constructor.

答:
-Here you are ! :> </p>

```<code>Button button = new Button(this);
GridLayout.LayoutParams param= new GridLayout.LayoutParams(GridLayout.spec(
            GridLayout.UNDEFINED,GridLayout.FILL,1f),
            GridLayout.spec(GridLayout.UNDEFINED,GridLayout.FILL,1f));
param.height = 0;
param.width  = 0;
button.setLayoutParams(param);
</code>```

Body:
I'd like to use a GridLayout (not GridView) as board for a game like chess or checkers. As I'm a little reluctant to use an xml file with 64 child Views, I've tried adding them programmatically.

To keep things simple, I started with using TextViews as child Views for the GridLayout.

My problem is that the Views are not distributed evenly, and that I don't know how to get an even distribution in my java code. There is no method like "setWeight()" for setting layout_columnWeight and layout_rowWeight.

At present, this is my activity_dynamic_grid_layout.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

<ImageView
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:id="@+id/ivLogo"
    android:background="#ff0000"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"/>

<android.support.v7.widget.GridLayout
    android:id="@+id/grid_layout"
    android:background="#004080"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/ivLogo"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginTop="36dp">

</android.support.v7.widget.GridLayout>

I've set the GridLayout width and height to match_parent here, but I'm changing them at runtime using a ViewTreeObserver.OnPreDrawListener in order to get a square board. This works, the colored background is showing a square space as intended.

My onCreate()

@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_dynamic_grid_layout);

    GridLayout gl = (GridLayout) findViewById(R.id.grid_layout);
    gl.setColumnCount(8);
    gl.setRowCount(8);

    for(int i=0; i<gl.getRowCount(); i++)
    {
        GridLayout.Spec rowSpec = GridLayout.spec(i, 1, GridLayout.FILL);

        for(int j=0;j<gl.getColumnCount();j++)
        {
            GridLayout.Spec colSpec = GridLayout.spec(j,1, GridLayout.FILL);

            TextView tvChild = new TextView(this);
            tvChild.setText("[ " + i + " | " + j + " ]");
            tvChild.setTextSize(18f);
            tvChild.setTextColor(Color.WHITE);
            tvChild.setGravity(Gravity.CENTER);

            GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams();
            myGLP.rowSpec = rowSpec;
            myGLP.columnSpec = colSpec;

            gl.addView(tvChild, myGLP );
        }
    }

    final View rootView = findViewById(R.id.dynamic_root);

    rootView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
    {
        @Override
        public boolean onPreDraw()
        {
            int w = rootView.getMeasuredWidth();
            int h = rootView.getMeasuredHeight();
            int min = Math.min(w, h);

            ViewGroup.LayoutParams lp = gl.getLayoutParams();
            lp.width = min - min % 9;
            lp.height = lp.width;
            gl.setLayoutParams(lp);

            rootView.getViewTreeObserver().removeOnPreDrawListener(this);

            return true;
        }
    });
}

What I've tried already:

I put one TextView child in the layout file and tried to copy the layout_columnWeight and layout_rowWeight from its GridLayout.LayoutParams:

 <android.support.v7.widget.GridLayout
 ...>
    <TextView
        android:id="@+id/clone_my_params"
        android:text="[ 0 | 0 ]"
        android:textColor="#ffffff"
        android:textSize="18sp"
        app:layout_column="0"
        app:layout_row="0"
        app:layout_columnWeight="1"
        app:layout_rowWeight="1"
    />
</android.support.v7.widget.GridLayout>

Additional code in onCreate(), before the double loop:

TextView v = (TextView)gl.findViewById(R.id.clone_my_params);
v.setGravity(Gravity.CENTER);
GridLayout.LayoutParams gridLayoutParamsToCopy = new GridLayout.LayoutParams(v.getLayoutParams());

Inside the loop, I skipped (i,j) = (0,0) and changed

 GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams();

to

 GridLayout.LayoutParams myGLP = new GridLayout.LayoutParams(gridLayoutParamsToCopy);

Before the change, all elements were in the upper left corner, the excess space was given to the last row/ column. After the change, the first row/ column had the excess space, no change for the other elements.

Calling gl.invalidate() and/or gl.requestLayout() after the double loop had no effect.

So it seems that I did not manage to set the desired weight by using the copy constructor.

Body:
-Here you are ! :>

Button button = new Button(this);
GridLayout.LayoutParams param= new GridLayout.LayoutParams(GridLayout.spec(
            GridLayout.UNDEFINED,GridLayout.FILL,1f),
            GridLayout.spec(GridLayout.UNDEFINED,GridLayout.FILL,1f));
param.height = 0;
param.width  = 0;
button.setLayoutParams(param);

ContentLicense: CC BY-SA 4.0


问:
How to define display order of edit view in Flask appbuilder?
According to document of flask appbuilder, the display order of Model detail view can be defined as following:

```<code>class DeviceView(ModelView):
    datamodel = SQLAInterface(Device)
    related_views = [ApplicationView, EventView]

    label_columns = {'snr':'SNR', 'api_dev_id':'Device ID', 'api_dev_key':'Device Key','owner_id':'Owner'}
    list_columns = ['name','snr','addr','owner']

    show_fieldsets = [
        ('Summary',
            {'fields':['name','snr','owner']}
        ),
        ('Device Info',
            {'fields':    ['addr','latitude','longitude','status','api_id','api_key','api_dev_id','api_dev_key'],'expanded':True}
        ),
    ]
</code>```

And it works for detail view. But I can not find the definition for edit view. Here is my snapshot for Device edit page. The order seems random.

Have I missed any part inside the document?

答:
I found the answer from another question:

Ordering data in a Flask Appbuilder view

```<code>class RegistrationTestView(ModelView ):
    datamodel = SQLAInterface(RegistrationTest)
    name = "RegistrationTestView"
    page_size=1000
    label_columns = {'CarNo':'Car #', 'FirstName':'First Name','LastName':'Last Name'}
    list_columns = ['CarNo','FirstName','LastName']
    edit_columns = ['FirstName','LastName']
    show_columns = edit_columns
    add_columns = edit_columns
    order_columns = ['FirstName']
</code>```

Display in edit/list/show are ordered seperately.

Body:
According to document of flask appbuilder, the display order of Model detail view can be defined as following:

class DeviceView(ModelView):
    datamodel = SQLAInterface(Device)
    related_views = [ApplicationView, EventView]

    label_columns = {'snr':'SNR', 'api_dev_id':'Device ID', 'api_dev_key':'Device Key','owner_id':'Owner'}
    list_columns = ['name','snr','addr','owner']

    show_fieldsets = [
        ('Summary',
            {'fields':['name','snr','owner']}
        ),
        ('Device Info',
            {'fields':    ['addr','latitude','longitude','status','api_id','api_key','api_dev_id','api_dev_key'],'expanded':True}
        ),
    ]

And it works for detail view. But I can not find the definition for edit view. Here is my snapshot for Device edit page. The order seems random.

Have I missed any part inside the document?

Body:
I found the answer from another question:

Ordering data in a Flask Appbuilder view

class RegistrationTestView(ModelView ):
    datamodel = SQLAInterface(RegistrationTest)
    name = "RegistrationTestView"
    page_size=1000
    label_columns = {'CarNo':'Car #', 'FirstName':'First Name','LastName':'Last Name'}
    list_columns = ['CarNo','FirstName','LastName']
    edit_columns = ['FirstName','LastName']
    show_columns = edit_columns
    add_columns = edit_columns
    order_columns = ['FirstName']

Display in edit/list/show are ordered seperately.


问:
Http redirects to https but it's not support in post request method
i am newer in firebase and i done firebase hosting first time but facing one issue regarding redirection

firebase hosting redirects http:// to https:// directly but i tried it with post request and it's working fine but posted json data is not there to process over on it

This is my firebase.json redirection rule
http://prntscr.com/han083

here is the screenshot of it

This is my code
http://prntscr.com/hamzv9

Without https://
http://prntscr.com/hamybm

With https://
http://prntscr.com/hamyxh

答:
This is because a POST body won't survive a redirect in general. This may be a small bug on Firebase Hosting's part (or perhaps on the part of whatever tool you're using to make the request) -- the HTTP response should be a 301 redirect, which must then be retried with the full POST body by the client.

In general, for any request other than GET you'll need to make sure you properly point at HTTP/HTTPS up front, since redirects don't preserve all request information in most user agents.


问:
Issues writing htaccess rewrite that allows period
I am trying to modify the htaccess of my social network website to allow period (.) and other symbols, just like instagram and twitter. Here is the one I have already.

```<code>RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)$ shop.php?u=$1
RewriteRule ^([a-zA-Z0-9_-]+)/$ shop.php?u=$1
</code>```

Anytime a user (with e.g website.com/b.i.scol, as profile link, tries to enter his profile, what we see next is error.)

答:
I assume the error is a 404? The character class [] of your regex doesn't allow for .s, add it in and you should be good to go. Additionally you can use a ? to make a character/group optional which will cut down the number of expressions you need.

```<code>RewriteRule ^([a-zA-Z0-9_.-]+)/?$ shop.php?u=$1
</code>```

You also need the - to be last (or first) in a character class to be literal, if it is between 2 characters it creates a range.

Also a-zA-Z0-9_ can be shortened to \w. So

```<code>RewriteRule ^([\w.-]+)/?$ shop.php?u=$1
</code>```

also should work.

Body:
I am trying to modify the htaccess of my social network website to allow period (.) and other symbols, just like instagram and twitter. Here is the one I have already.

RewriteEngine On
RewriteRule ^([a-zA-Z0-9_-]+)$ shop.php?u=$1
RewriteRule ^([a-zA-Z0-9_-]+)/$ shop.php?u=$1

Anytime a user (with e.g website.com/b.i.scol, as profile link, tries to enter his profile, what we see next is error.)

Body:
I assume the error is a 404? The character class [] of your regex doesn't allow for .s, add it in and you should be good to go. Additionally you can use a ? to make a character/group optional which will cut down the number of expressions you need.

RewriteRule ^([a-zA-Z0-9_.-]+)/?$ shop.php?u=$1

You also need the - to be last (or first) in a character class to be literal, if it is between 2 characters it creates a range.

Also a-zA-Z0-9_ can be shortened to \w. So

RewriteRule ^([\w.-]+)/?$ shop.php?u=$1

also should work.


答:
Modern browsers support the classList API now.

In order to use the classList API, try adding the following to your code:

```<code>var buttons = document.getElementsByClassName('button')

Array.prototype.forEach.call(buttons, function (button) {
  button.addEventListener('click', function (event) {
    button.classList.toggle('button-active')
  })
})
</code>```

If you want to only turn the active state on, switch the toggle method of classList to add. Read more on classList.

Breakdown of code example:

First I select all .button elements and store them in a NodeList data type.
Then I call array's forEach function (another way of doing the same would be [].forEach.call() but that creates new Array instance every time it runs). I add an event listener for click event upon which I toggle a new class name.

For a direct CSS manipulation, you can use button.style.color = 'red' - but I discourage you from this approach to keep your code maintainable.

Note from Phil (in the comments to this answer):
You can use NodeList.prototype.forEach() which shortens the line into buttons.forEach(function (button) {. Bear in mind that Internet Explorer does not support this.

Title: How to toggle a button to an active state using vanilla JS?

Body:
Modern browsers support the classList API now.

In order to use the classList API, try adding the following to your code:

var buttons = document.getElementsByClassName('button')

Array.prototype.forEach.call(buttons, function (button) {
  button.addEventListener('click', function (event) {
    button.classList.toggle('button-active')
  })
})

If you want to only turn the active state on, switch the toggle method of classList to add. Read more on classList.

Breakdown of code example:

First I select all .button elements and store them in a NodeList data type.
Then I call array's forEach function (another way of doing the same would be [].forEach.call() but that creates new Array instance every time it runs). I add an event listener for click event upon which I toggle a new class name.

For a direct CSS manipulation, you can use button.style.color = 'red' - but I discourage you from this approach to keep your code maintainable.

Note from Phil (in the comments to this answer):
You can use NodeList.prototype.forEach() which shortens the line into buttons.forEach(function (button) {. Bear in mind that Internet Explorer does not support this.


问:
Why is XPath returning nodes from my entire document, and not just the select node
Given:

```<code>public class XPathTest {

    public static void main(String args[]) throws Exception {
        String xmlString
                = "<a>"
                + "<b c=\"1\"/>"
                + "<b c=\"2\"/>"
                + "</a>";

        ByteArrayInputStream bis = new ByteArrayInputStream(xmlString.getBytes());
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(bis));

        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("//b");

        NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
        dumpNodeList(nl);
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i);
            NodeList nl2 = (NodeList) expr.evaluate(n, XPathConstants.NODESET);
            dumpNodeList(nl2);
        }

    }

    public static void dumpNodeList(NodeList nl) {
        System.out.println("NodeList length = " + nl.getLength());
        for (int i = 0; i < nl.getLength(); i++) {
            System.out.println("Node #" + i);
            Element e = (Element) nl.item(i);
            System.out.println("Name = " + e.getTagName());
            System.out.println("Attr = " + e.getAttribute("c"));
        }
        System.out.println();
    }
}
</code>```

Sample result:

```<code>NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2
</code>```

I evaluate the XPath expression //b, passing in the root document node to the evaluator. It, expectedly, returns the two b nodes.

What I'm confused about is when I evaluate the same expression, but instead of passing in the root node as he parameter I pass in one of the children nodes I located earlier. According to XPathExpression.evaluate(Object item), it says Evaluate the compiled XPath expression in the specified context and return the result as the specified type.

The expression, //b, means "give me all of the b nodes".

Intuitively, I would think that if I pass in a Node to XPathExpression.evalute(Object item), that the expression would be evaluated starting with that node as its root for the "give me all" part, rather than the entire document. So I would expect a resulting NodeList of one node, not two.

But instead, I get the same two nodes as if from the entire document.

So, the two questions are:

Why is the expression being evaluated relative to the entire document, and not to just using the pass Node as a synthetic root for the evaluation?

How can I get the expression to evaluate using the passed in Node as the synthetic root for the evaluation?

答:
An expression starting with /, like //b, starts by navigating upwards from the context node to the root of the containing tree. So your cited documentation is correct that it is "evaluated in the current context", but you somehow misread this as saying that it only looks at the subtree rooted at the context node. If you choose to navigate upwards from the context node, you can, and that is precisely what you have done.

You probably wanted .//b.

Body:
Given:

public class XPathTest {

    public static void main(String args[]) throws Exception {
        String xmlString
                = ""
                + ""
                + ""
                + "";

        ByteArrayInputStream bis = new ByteArrayInputStream(xmlString.getBytes());
        DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = domFactory.newDocumentBuilder();
        Document doc = builder.parse(new InputSource(bis));

        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("//b");

        NodeList nl = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
        dumpNodeList(nl);
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i);
            NodeList nl2 = (NodeList) expr.evaluate(n, XPathConstants.NODESET);
            dumpNodeList(nl2);
        }

    }

    public static void dumpNodeList(NodeList nl) {
        System.out.println("NodeList length = " + nl.getLength());
        for (int i = 0; i < nl.getLength(); i++) {
            System.out.println("Node #" + i);
            Element e = (Element) nl.item(i);
            System.out.println("Name = " + e.getTagName());
            System.out.println("Attr = " + e.getAttribute("c"));
        }
        System.out.println();
    }
}

Sample result:

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

NodeList length = 2
Node #0
Name = b
Attr = 1
Node #1
Name = b
Attr = 2

I evaluate the XPath expression //b, passing in the root document node to the evaluator. It, expectedly, returns the two b nodes.

What I'm confused about is when I evaluate the same expression, but instead of passing in the root node as he parameter I pass in one of the children nodes I located earlier. According to XPathExpression.evaluate(Object item), it says Evaluate the compiled XPath expression in the specified context and return the result as the specified type.

The expression, //b, means "give me all of the b nodes".

Intuitively, I would think that if I pass in a Node to XPathExpression.evalute(Object item), that the expression would be evaluated starting with that node as its root for the "give me all" part, rather than the entire document. So I would expect a resulting NodeList of one node, not two.

But instead, I get the same two nodes as if from the entire document.

So, the two questions are:

Why is the expression being evaluated relative to the entire document, and not to just using the pass Node as a synthetic root for the evaluation?

How can I get the expression to evaluate using the passed in Node as the synthetic root for the evaluation?


问:
Vehicle Routing Prob with non-connected graph or-tools Python
I'm using this python library or-tools: https://developers.google.com/optimization/routing/tsp/vehicle_routing
(the code can be found here).

The problem is that when you run the solution it gives you a path to take that covers all of the nodes once. But my project needs constraints on the paths between nodes. For example, if you are on node {3} you may not travel to node {18}. Or in another way, if you are at node {5} you can only travel to nodes {1, 12, 14}. I'm unsure how to add this constraint into the current code example.

Allow me to explain further...

If we were to look at this graph:

You may see a representation of this graph here:
https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial

Clearly in this problem you can not travel to certain nodes from other nodes. I am using the data from this graph in the google or-tools example to obtain a vehicle routing problem solution.

Here is my code:

```<code>import math
from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import routing_enums_pb2
import pandas as pd
from sklearn import preprocessing

def distance(x1, y1, x2, y2):
    dist = ((x1 - x2)**2 + (y1 - y2)**2)**(1/2)

    return dist
class CreateDistanceCallback(object):
  """Create callback to calculate distances between points."""

  def __init__(self, locations):
    """Initialize distance array."""
    size = len(locations)
    self.matrix = {}

    for from_node in range(size):
      self.matrix[from_node] = {}
      for to_node in range(size):
        x1 = locations[from_node][0]
        y1 = locations[from_node][1]
        x2 = locations[to_node][0]
        y2 = locations[to_node][1]
        self.matrix[from_node][to_node] = distance(x1, y1, x2, y2)

  def Distance(self, from_node, to_node):
    return int(self.matrix[from_node][to_node])

# Demand callback
class CreateDemandCallback(object):
  """Create callback to get demands at each location."""

  def __init__(self, demands):
    self.matrix = demands

  def Demand(self, from_node, to_node):
    return self.matrix[from_node]

def main():
  # Create the data.
  data = create_data_array()
  locations = data[0]
  demands = data[1]
  num_locations = len(locations)
  depot = 0    # The depot is the start and end point of each route.
  num_vehicles = 1

  # Create routing model.
  if num_locations > 0:
    routing = pywrapcp.RoutingModel(num_locations, num_vehicles, depot)
    search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters()

    # Callback to the distance function.
    dist_between_locations = CreateDistanceCallback(locations)
    dist_callback = dist_between_locations.Distance
    routing.SetArcCostEvaluatorOfAllVehicles(dist_callback)

    # Put a callback to the demands.
    demands_at_locations = CreateDemandCallback(demands)
    demands_callback = demands_at_locations.Demand

    # Add a dimension for demand.
    slack_max = 0
    vehicle_capacity = 1500
    fix_start_cumul_to_zero = True
    demand = "Demand"
    routing.AddDimension(demands_callback, slack_max, vehicle_capacity,
                         fix_start_cumul_to_zero, demand)

    # Solve, displays a solution if any.
    assignment = routing.SolveWithParameters(search_parameters)
    if assignment:
      # Display solution.
      # Solution cost.
      print("Total distance of all routes: " + str(assignment.ObjectiveValue()) + "\n")

      for vehicle_nbr in range(num_vehicles):
        index = routing.Start(vehicle_nbr)
        index_next = assignment.Value(routing.NextVar(index))
        route = ''
        route_dist = 0
        route_demand = 0

        while not routing.IsEnd(index_next):
          node_index = routing.IndexToNode(index)
          node_index_next = routing.IndexToNode(index_next)
          route += str(node_index) + " -> "
          # Add the distance to the next node.
          route_dist += dist_callback(node_index, node_index_next)
          # Add demand.
          route_demand += demands[node_index_next]
          index = index_next
          index_next = assignment.Value(routing.NextVar(index))

        node_index = routing.IndexToNode(index)
        node_index_next = routing.IndexToNode(index_next)
        route += str(node_index) + " -> " + str(node_index_next)
        route_dist += dist_callback(node_index, node_index_next)
        print("Route for vehicle " + str(vehicle_nbr) + ":\n\n" + route + "\n")
        print("Distance of route " + str(vehicle_nbr) + ": " + str(route_dist))
        print("Demand met by vehicle " + str(vehicle_nbr) + ": " + str(route_demand) + "\n")
    else:
      print('No solution found.')
  else:
    print('Specify an instance greater than 0.')

def create_data_array():

  nodelist = pd.read_csv('https://gist.githubusercontent.com/brooksandrew/f989e10af17fb4c85b11409fea47895b/raw/a3a8da0fa5b094f1ca9d82e1642b384889ae16e8/nodelist_sleeping_giant.csv')

  locations = [[e.X, e.Y] for e in nodelist.itertuples()]
  demands = [1] + [1] + [1] * 75

  data = [locations, demands]
  return data

if __name__ == '__main__':
  main()
</code>```

This outputs a solution:

```<code>Total distance of all routes: 12900

Route for vehicle 0:

0 -> 56 -> 40 -> 53 -> 63 -> 55 -> 14 -> 15 -> 12 -> 26 -> 34 -> 69 -> 36 -> 1 -> 64 -> 27 -> 48 -> 70 -> 47 -> 13 -> 10 -> 61 -> 45 -> 42 -> 60 -> 9 -> 8 -> 21 -> 43 -> 44 -> 3 -> 18 -> 58 -> 38 -> 28 -> 49 -> 32 -> 35 -> 50 -> 74 -> 46 -> 54 -> 76 -> 71 -> 65 -> 29 -> 16 -> 17 -> 22 -> 59 -> 7 -> 24 -> 31 -> 37 -> 67 -> 73 -> 41 -> 52 -> 75 -> 72 -> 20 -> 2 -> 39 -> 57 -> 23 -> 66 -> 5 -> 6 -> 30 -> 33 -> 68 -> 19 -> 25 -> 4 -> 11 -> 62 -> 51 -> 0

Distance of route 0: 12900
Demand met by vehicle 0: 76
</code>```

So as you can see we are traveling between nodes that cannot be travelled between.

答:
(At first sight) this looks like some wrapper for some already implemented specialized solver. Maybe changing internals is not as easy.

But an easy workaround: just change the distance-callback so that it gives very high costs for your forbidden edges.

This approach needs tuning and is not perfect. But it's a workaround.

If this makes sense, depends on your task, which looks pretty informally described.

Body:
I'm using this python library or-tools: https://developers.google.com/optimization/routing/tsp/vehicle_routing
(the code can be found here).

The problem is that when you run the solution it gives you a path to take that covers all of the nodes once. But my project needs constraints on the paths between nodes. For example, if you are on node {3} you may not travel to node {18}. Or in another way, if you are at node {5} you can only travel to nodes {1, 12, 14}. I'm unsure how to add this constraint into the current code example.

Allow me to explain further...

If we were to look at this graph:

You may see a representation of this graph here:
https://www.datacamp.com/community/tutorials/networkx-python-graph-tutorial

Clearly in this problem you can not travel to certain nodes from other nodes. I am using the data from this graph in the google or-tools example to obtain a vehicle routing problem solution.

Here is my code:

import math
from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import routing_enums_pb2
import pandas as pd
from sklearn import preprocessing

def distance(x1, y1, x2, y2):
    dist = ((x1 - x2)**2 + (y1 - y2)**2)**(1/2)

    return dist
class CreateDistanceCallback(object):
  """Create callback to calculate distances between points."""

  def __init__(self, locations):
    """Initialize distance array."""
    size = len(locations)
    self.matrix = {}

    for from_node in range(size):
      self.matrix[from_node] = {}
      for to_node in range(size):
        x1 = locations[from_node][0]
        y1 = locations[from_node][1]
        x2 = locations[to_node][0]
        y2 = locations[to_node][1]
        self.matrix[from_node][to_node] = distance(x1, y1, x2, y2)

  def Distance(self, from_node, to_node):
    return int(self.matrix[from_node][to_node])

# Demand callback
class CreateDemandCallback(object):
  """Create callback to get demands at each location."""

  def __init__(self, demands):
    self.matrix = demands

  def Demand(self, from_node, to_node):
    return self.matrix[from_node]

def main():
  # Create the data.
  data = create_data_array()
  locations = data[0]
  demands = data[1]
  num_locations = len(locations)
  depot = 0    # The depot is the start and end point of each route.
  num_vehicles = 1

  # Create routing model.
  if num_locations > 0:
    routing = pywrapcp.RoutingModel(num_locations, num_vehicles, depot)
    search_parameters = pywrapcp.RoutingModel.DefaultSearchParameters()

    # Callback to the distance function.
    dist_between_locations = CreateDistanceCallback(locations)
    dist_callback = dist_between_locations.Distance
    routing.SetArcCostEvaluatorOfAllVehicles(dist_callback)

    # Put a callback to the demands.
    demands_at_locations = CreateDemandCallback(demands)
    demands_callback = demands_at_locations.Demand

    # Add a dimension for demand.
    slack_max = 0
    vehicle_capacity = 1500
    fix_start_cumul_to_zero = True
    demand = "Demand"
    routing.AddDimension(demands_callback, slack_max, vehicle_capacity,
                         fix_start_cumul_to_zero, demand)

    # Solve, displays a solution if any.
    assignment = routing.SolveWithParameters(search_parameters)
    if assignment:
      # Display solution.
      # Solution cost.
      print("Total distance of all routes: " + str(assignment.ObjectiveValue()) + "\n")

      for vehicle_nbr in range(num_vehicles):
        index = routing.Start(vehicle_nbr)
        index_next = assignment.Value(routing.NextVar(index))
        route = ''
        route_dist = 0
        route_demand = 0

        while not routing.IsEnd(index_next):
          node_index = routing.IndexToNode(index)
          node_index_next = routing.IndexToNode(index_next)
          route += str(node_index) + " -> "
          # Add the distance to the next node.
          route_dist += dist_callback(node_index, node_index_next)
          # Add demand.
          route_demand += demands[node_index_next]
          index = index_next
          index_next = assignment.Value(routing.NextVar(index))

        node_index = routing.IndexToNode(index)
        node_index_next = routing.IndexToNode(index_next)
        route += str(node_index) + " -> " + str(node_index_next)
        route_dist += dist_callback(node_index, node_index_next)
        print("Route for vehicle " + str(vehicle_nbr) + ":\n\n" + route + "\n")
        print("Distance of route " + str(vehicle_nbr) + ": " + str(route_dist))
        print("Demand met by vehicle " + str(vehicle_nbr) + ": " + str(route_demand) + "\n")
    else:
      print('No solution found.')
  else:
    print('Specify an instance greater than 0.')

def create_data_array():

  nodelist = pd.read_csv('https://gist.githubusercontent.com/brooksandrew/f989e10af17fb4c85b11409fea47895b/raw/a3a8da0fa5b094f1ca9d82e1642b384889ae16e8/nodelist_sleeping_giant.csv')

  locations = [[e.X, e.Y] for e in nodelist.itertuples()]
  demands = [1] + [1] + [1] * 75

  data = [locations, demands]
  return data

if __name__ == '__main__':
  main()

This outputs a solution:

Total distance of all routes: 12900

Route for vehicle 0:

0 -> 56 -> 40 -> 53 -> 63 -> 55 -> 14 -> 15 -> 12 -> 26 -> 34 -> 69 -> 36 -> 1 -> 64 -> 27 -> 48 -> 70 -> 47 -> 13 -> 10 -> 61 -> 45 -> 42 -> 60 -> 9 -> 8 -> 21 -> 43 -> 44 -> 3 -> 18 -> 58 -> 38 -> 28 -> 49 -> 32 -> 35 -> 50 -> 74 -> 46 -> 54 -> 76 -> 71 -> 65 -> 29 -> 16 -> 17 -> 22 -> 59 -> 7 -> 24 -> 31 -> 37 -> 67 -> 73 -> 41 -> 52 -> 75 -> 72 -> 20 -> 2 -> 39 -> 57 -> 23 -> 66 -> 5 -> 6 -> 30 -> 33 -> 68 -> 19 -> 25 -> 4 -> 11 -> 62 -> 51 -> 0

Distance of route 0: 12900
Demand met by vehicle 0: 76

So as you can see we are traveling between nodes that cannot be travelled between.


问:
JPA Eclipselink - Multiple EntityManagerFactory instances returning same session
I have understanding an instance of EntityManagerFactory(EMF1) has its own EntityManager and session. If i create another instance of EntityManagerFactory(EMF2) using same credentials as EMF1 then it should have its own connection pool and so session. But it is not and because of this reason session customizer is also called once if everything is same

```<code>package test.jpa.factory;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestEntityManagerFactory {
    private static Logger logger = LoggerFactory.getLogger(TestEntityManagerFactory.class);
    public static final String JDBC_URL = "javax.persistence.jdbc.url";
    public static final String JDBC_USER = "javax.persistence.jdbc.user";
    public static final String JDBC_PASSWD = "javax.persistence.jdbc.password";
    public static final String WAREHOUSE_PERSISTENCE_UNIT = "etl-dw";

    public static void main(String[] args) throws Exception {
        String host = "xxxxcccc";
        String port = "1521";
        String user = "skipvpd";
        String pwd = "abcd";
        String service = "test_svc1";
        System.out.println("Same user multiple EMF");
        printSession(host, port, user, pwd, service);
        printSession(host, port, user, pwd, service);

        System.out.println("Different user multiple EMF");
        user = "1032";
        pwd = "abcd";
        printSession(host, port, user, pwd, service);
        user = "1033";
        printSession(host, port, user, pwd, service);

    }

    private static void printSession(String host, String port, String user, String pwd, String serviceName)
            throws Exception {
        EntityManagerFactory emf = getEntityManagerFactory(host, port, user, pwd, serviceName);
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        Session session = (Session) em.unwrap(org.eclipse.persistence.sessions.Session.class);
        Connection connection = (Connection) em.unwrap(java.sql.Connection.class);
        System.out.println("con_hashcode=" + connection.hashCode() + ",session_hashcode=" + session.hashCode()
                + ",em_hashcode=" + em.hashCode() + ",emf_hashcode=" + emf.hashCode());
        em.getTransaction().commit();
        em.close();

    }

    private static EntityManagerFactory getEntityManagerFactory(String host, String port, String user, String pwd,
            String serviceName) {

        Map<String, String> jpaConfig = new HashMap<String, String>();
        try {
            String jdbcURL = "jdbc:oracle:thin:@" + host + ":" + port + "/" + serviceName;

            jpaConfig.put("javax.persistence.jdbc.url", jdbcURL);
            jpaConfig.put(JDBC_USER, user);
            jpaConfig.put(JDBC_PASSWD, pwd);

            jpaConfig.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,
                    TestEntityManagerFactory.ETLSessionCustomizer.class.getName());

        } catch (Throwable t) {
            logger.error("ERROR=\"Error occured in getJPAConfiguration\" EXCEPTION={}", t);
        }
        return Persistence.createEntityManagerFactory(WAREHOUSE_PERSISTENCE_UNIT, jpaConfig);

    }

    public static class ETLSessionCustomizer implements SessionCustomizer {

        public void customize(Session session) {
            System.out.println("customize is called for session_hash_code=" + session.hashCode());
        }
    }
}
</code>```

Same user multiple EMF

customize is called for session_hash_code=1193471756

con_hashcode=675100200,session_hashcode=1193471756,em_hashcode=627727856,emf_hashcode=179294202

con_hashcode=675100200,session_hashcode=1193471756,em_hashcode=166919726,emf_hashcode=1305777754

Different user multiple EMF

customize is called for session_hash_code=1240796303
con_hashcode=738369543,session_hashcode=1240796303,em_hashcode=1017841629,emf_hashcode=1760715967

customize is called for session_hash_code=1161255903

con_hashcode=92699135,session_hashcode=1161255903,em_hashcode=1535875885,emf_hashcode=2054926467

答:
After debugging JPA code, i resolved my problem by supplying unique session name for each entity manager factory.

Problem:

If PersistenceUnitProperties.SESSION_NAME/eclipselink.session-name is not provided then EntityManagerSetupImpl.getOrBuildSessionName method try to create session name using connection properties that is same for both factories.

First time EntityManagerSetupImpl object is created and cached using session name as key inside EntityManagerFactoryProvider.
For second instance of EntityManagerFactory(with same session name), it finds the instance already in cache hence doesn't create new instance instead shared the existing one created for first EntityManagerFactory.

In my example, if you add following code, you will see different sessions and hashcode with session customizer called twice.

```<code>jpaConfig.put(PersistenceUnitProperties.SESSION_NAME, String.valueOf(System.nanoTime()));
</code>```

Here is the output after change

```<code>Same user multiple EMF
customize is called for session_hash_code=1173577197
con_hashcode=1091009906,session_hashcode=1173577197,em_hashcode=1569793443,emf_hashcode=1681793106
customize is called for session_hash_code=649715211
con_hashcode=1908828843,session_hashcode=649715211,em_hashcode=327304249,emf_hashcode=1296892976
</code>```

Body:
I have understanding an instance of EntityManagerFactory(EMF1) has its own EntityManager and session. If i create another instance of EntityManagerFactory(EMF2) using same credentials as EMF1 then it should have its own connection pool and so session. But it is not and because of this reason session customizer is also called once if everything is same

package test.jpa.factory;

import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.sessions.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class TestEntityManagerFactory {
    private static Logger logger = LoggerFactory.getLogger(TestEntityManagerFactory.class);
    public static final String JDBC_URL = "javax.persistence.jdbc.url";
    public static final String JDBC_USER = "javax.persistence.jdbc.user";
    public static final String JDBC_PASSWD = "javax.persistence.jdbc.password";
    public static final String WAREHOUSE_PERSISTENCE_UNIT = "etl-dw";

    public static void main(String[] args) throws Exception {
        String host = "xxxxcccc";
        String port = "1521";
        String user = "skipvpd";
        String pwd = "abcd";
        String service = "test_svc1";
        System.out.println("Same user multiple EMF");
        printSession(host, port, user, pwd, service);
        printSession(host, port, user, pwd, service);

        System.out.println("Different user multiple EMF");
        user = "1032";
        pwd = "abcd";
        printSession(host, port, user, pwd, service);
        user = "1033";
        printSession(host, port, user, pwd, service);

    }

    private static void printSession(String host, String port, String user, String pwd, String serviceName)
            throws Exception {
        EntityManagerFactory emf = getEntityManagerFactory(host, port, user, pwd, serviceName);
        EntityManager em = emf.createEntityManager();
        em.getTransaction().begin();
        Session session = (Session) em.unwrap(org.eclipse.persistence.sessions.Session.class);
        Connection connection = (Connection) em.unwrap(java.sql.Connection.class);
        System.out.println("con_hashcode=" + connection.hashCode() + ",session_hashcode=" + session.hashCode()
                + ",em_hashcode=" + em.hashCode() + ",emf_hashcode=" + emf.hashCode());
        em.getTransaction().commit();
        em.close();

    }

    private static EntityManagerFactory getEntityManagerFactory(String host, String port, String user, String pwd,
            String serviceName) {

        Map<String, String> jpaConfig = new HashMap<String, String>();
        try {
            String jdbcURL = "jdbc:oracle:thin:@" + host + ":" + port + "/" + serviceName;

            jpaConfig.put("javax.persistence.jdbc.url", jdbcURL);
            jpaConfig.put(JDBC_USER, user);
            jpaConfig.put(JDBC_PASSWD, pwd);

            jpaConfig.put(PersistenceUnitProperties.SESSION_CUSTOMIZER,
                    TestEntityManagerFactory.ETLSessionCustomizer.class.getName());

        } catch (Throwable t) {
            logger.error("ERROR=\"Error occured in getJPAConfiguration\" EXCEPTION={}", t);
        }
        return Persistence.createEntityManagerFactory(WAREHOUSE_PERSISTENCE_UNIT, jpaConfig);

    }

    public static class ETLSessionCustomizer implements SessionCustomizer {

        public void customize(Session session) {
            System.out.println("customize is called for session_hash_code=" + session.hashCode());
        }
    }
}

Same user multiple EMF

customize is called for session_hash_code=1193471756

con_hashcode=675100200,session_hashcode=1193471756,em_hashcode=627727856,emf_hashcode=179294202

con_hashcode=675100200,session_hashcode=1193471756,em_hashcode=166919726,emf_hashcode=1305777754

Different user multiple EMF

customize is called for session_hash_code=1240796303
con_hashcode=738369543,session_hashcode=1240796303,em_hashcode=1017841629,emf_hashcode=1760715967

customize is called for session_hash_code=1161255903

con_hashcode=92699135,session_hashcode=1161255903,em_hashcode=1535875885,emf_hashcode=2054926467

Body:
After debugging JPA code, i resolved my problem by supplying unique session name for each entity manager factory.

Problem:

If PersistenceUnitProperties.SESSION_NAME/eclipselink.session-name is not provided then EntityManagerSetupImpl.getOrBuildSessionName method try to create session name using connection properties that is same for both factories.

First time EntityManagerSetupImpl object is created and cached using session name as key inside EntityManagerFactoryProvider.
For second instance of EntityManagerFactory(with same session name), it finds the instance already in cache hence doesn't create new instance instead shared the existing one created for first EntityManagerFactory.

In my example, if you add following code, you will see different sessions and hashcode with session customizer called twice.

jpaConfig.put(PersistenceUnitProperties.SESSION_NAME, String.valueOf(System.nanoTime()));

Here is the output after change

Same user multiple EMF
customize is called for session_hash_code=1173577197
con_hashcode=1091009906,session_hashcode=1173577197,em_hashcode=1569793443,emf_hashcode=1681793106
customize is called for session_hash_code=649715211
con_hashcode=1908828843,session_hashcode=649715211,em_hashcode=327304249,emf_hashcode=1296892976