问:
Better way to join multiple tables using SQL
I am messing around with the toy databases on W3School for learning SQL and I was trying to make a table that allowed me to find out the following information on a given OrderID:

Name of the products in the order.

Total cost of each product in the order (so if they ordered 10 of 1 item, what is the cost).

Name of the suppliers of those products.

Name of the shipper for the order.

I ended up achieving it through this code:

```<code>SELECT
    Price * Quantity AS TotalCost,
    ProductName, SupplierName, ShipperName
FROM
    (SELECT *
     FROM
         (SELECT *
          FROM
              (SELECT *
               FROM Products
               LEFT JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID) AS Products
          LEFT JOIN
              OrderDetails ON Products.ProductID = OrderDetails.ProductID) AS OrderDetails
     LEFT JOIN
         Orders ON OrderDetails.OrderID = Orders.OrderID) AS Orders
LEFT JOIN
    Shippers ON Orders.ShipperID = Shippers.ShipperID
WHERE
    Orders.OrderDetails.OrderID = 10248;
</code>```

However this seems like a total mess and I assume there must be a better way of achieving the same result. I did look around at other threads to see if I could find other ways, and the threads seemed to suggest that these subqueries are not necessary and that I could just chain the JOINs together without using subqueries, but when I tried this I got errors from the W3School compiler. Not sure if this is a problem with the website itself or if the error was on my end. For example, if I try this I get an error:

```<code>SELECT
    Price * Quantity AS TotalCost,
    ProductName, SupplierName, ShipperName
FROM
    Products
LEFT JOIN
    Suppliers ON Products.SupplierID = Suppliers.SupplierID
LEFT JOIN
    OrderDetails ON Products.ProductID = OrderDetails.ProductID
LEFT JOIN
    Orders ON OrderDetails.OrderID = Orders.OrderID
LEFT JOIN
    Shippers ON Orders.ShipperID = Shippers.ShipperID
WHERE
    Orders.OrderDetails.OrderID = 10248;
</code>```

Error:

Syntax error (missing operator) in query expression 'Products.SupplierID=Suppliers.SupplierID LEFT JOIN OrderDetails ON Products.ProductID=OrderDetails.ProductID LEFT JOIN Orders ON OrderDetails.OrderID=Orders.OrderID LEFT JOIN Shippers ON Orders.ShipperID=Shippers.ShipperID'.

答: You need to specify from which table those columns come from. You can't just say SELECT Price when you have multiple tables joined. For example, Price*Quantity would need to be something like Products.Price*Orders.Quantity

Body:
I am messing around with the toy databases on W3School for learning SQL and I was trying to make a table that allowed me to find out the following information on a given OrderID:

Name of the products in the order.

Total cost of each product in the order (so if they ordered 10 of 1 item, what is the cost).

Name of the suppliers of those products.

Name of the shipper for the order.

I ended up achieving it through this code:

SELECT
    Price * Quantity AS TotalCost,
    ProductName, SupplierName, ShipperName
FROM
    (SELECT *
     FROM
         (SELECT *
          FROM
              (SELECT *
               FROM Products
               LEFT JOIN Suppliers ON Products.SupplierID = Suppliers.SupplierID) AS Products
          LEFT JOIN
              OrderDetails ON Products.ProductID = OrderDetails.ProductID) AS OrderDetails
     LEFT JOIN
         Orders ON OrderDetails.OrderID = Orders.OrderID) AS Orders
LEFT JOIN
    Shippers ON Orders.ShipperID = Shippers.ShipperID
WHERE
    Orders.OrderDetails.OrderID = 10248;

However this seems like a total mess and I assume there must be a better way of achieving the same result. I did look around at other threads to see if I could find other ways, and the threads seemed to suggest that these subqueries are not necessary and that I could just chain the JOINs together without using subqueries, but when I tried this I got errors from the W3School compiler. Not sure if this is a problem with the website itself or if the error was on my end. For example, if I try this I get an error:

SELECT
    Price * Quantity AS TotalCost,
    ProductName, SupplierName, ShipperName
FROM
    Products
LEFT JOIN
    Suppliers ON Products.SupplierID = Suppliers.SupplierID
LEFT JOIN
    OrderDetails ON Products.ProductID = OrderDetails.ProductID
LEFT JOIN
    Orders ON OrderDetails.OrderID = Orders.OrderID
LEFT JOIN
    Shippers ON Orders.ShipperID = Shippers.ShipperID
WHERE
    Orders.OrderDetails.OrderID = 10248;

Error:

Syntax error (missing operator) in query expression 'Products.SupplierID=Suppliers.SupplierID LEFT JOIN OrderDetails ON Products.ProductID=OrderDetails.ProductID LEFT JOIN Orders ON OrderDetails.OrderID=Orders.OrderID LEFT JOIN Shippers ON Orders.ShipperID=Shippers.ShipperID'.


来源: stackexchange

问:
recyclerView layout grid items not aligning properly
i don't know much about java, just started, so i will have difficulties understanding the answers. emli5.

screenshot:

expected output:

in the recyclerview (right), these items are not aligning up like i want them to.

I want that each cell has a fixed size, and maximum number of columns possible in the grid.
spacing b/w each cell (both vertical and horizontal) is equal to (left space) divided by (number of columns minus one).   [with no extra space left at start, top, bottom or end]

here is the code:

package com.MyStickersWA.DogeStickers;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

@SuppressWarnings("ALL")
public class StickerPackDetailsActivity extends AddStickerPackActivity {

    /**
     * Do not change below values of below 3 lines as this is also used by WhatsApp
     */
    public static final String EXTRA_STICKER_PACK_ID = "sticker_pack_id";
    public static final String EXTRA_STICKER_PACK_AUTHORITY = "sticker_pack_authority";
    public static final String EXTRA_STICKER_PACK_NAME = "sticker_pack_name";

    public static final String EXTRA_STICKER_PACK_WEBSITE = "sticker_pack_website";
    public static final String EXTRA_STICKER_PACK_EMAIL = "sticker_pack_email";
    public static final String EXTRA_STICKER_PACK_PRIVACY_POLICY = "sticker_pack_privacy_policy";
    public static final String EXTRA_STICKER_PACK_LICENSE_AGREEMENT = "sticker_pack_license_agreement";
    public static final String EXTRA_STICKER_PACK_TRAY_ICON = "sticker_pack_tray_icon";
    public static final String EXTRA_SHOW_UP_BUTTON = "show_up_button";
    public static final String EXTRA_STICKER_PACK_DATA = "sticker_pack";

    private RecyclerView recyclerView;
    private GridLayoutManager layoutManager;
    private StickerPreviewAdapter stickerPreviewAdapter;
    private int numColumns;
    private View addButton;
    private View infoButton;
    private View backButton;
    private View alreadyAdded;
    private StickerPack stickerPack;
    private WhiteListCheckAsyncTask whiteListCheckAsyncTask;

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

        AdView mAdView = findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        MobileAds.initialize(this, initializationStatus -> { });

        mAdView.loadAd(adRequest);

        boolean showUpButton = getIntent().getBooleanExtra(EXTRA_SHOW_UP_BUTTON, false);
        stickerPack = getIntent().getParcelableExtra(EXTRA_STICKER_PACK_DATA);
        TextView packNameTextView = findViewById(R.id.pack_name);
        TextView packPublisherTextView = findViewById(R.id.author);
        ImageView packTrayIcon = findViewById(R.id.tray_image);
        TextView packSizeTextView = findViewById(R.id.pack_size);
        TextView stickersQtyTextView = findViewById(R.id.stickers_qty);
        TextView stickersAnimatedView = findViewById(R.id.stickers_animated);
        ImageView stickersAnimatedImage = findViewById(R.id.sticker_pack_animation_indicator);
        SimpleDraweeView expandedStickerView = findViewById(R.id.sticker_details_expanded_sticker);

        addButton = findViewById(R.id.add_to_whatsapp_button);
        infoButton = findViewById(R.id.action_info);
        backButton = findViewById(R.id.action_back);
        alreadyAdded = findViewById(R.id.already_added_button);
        layoutManager = new GridLayoutManager(this, 1);
        recyclerView = findViewById(R.id.sticker_list);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(pageLayoutListener);

        if (stickerPreviewAdapter == null) {
            stickerPreviewAdapter = new StickerPreviewAdapter(getLayoutInflater(), R.drawable.sticker_error, getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size), getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_padding), stickerPack, expandedStickerView);
            recyclerView.setAdapter(stickerPreviewAdapter);
        }
        packNameTextView.setText(stickerPack.name);
        packPublisherTextView.setText(stickerPack.publisher);
        packTrayIcon.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile));
        packSizeTextView.setText(Formatter.formatShortFileSize(this, stickerPack.getTotalSize()));
        stickersQtyTextView.setText(stickerPack.getTotalQty() + "");
        addButton.setOnClickListener(v -> addStickerPackToWhatsApp(stickerPack.identifier, stickerPack.name));
        infoButton.setOnClickListener(v -> onOptionsItemSelected());
        backButton.setOnClickListener(v -> finish());

        if (stickerPack.animatedStickerPack) {
            Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.animated_indicator_vector);
            stickersAnimatedImage.setImageURI(animatedIcon);
            stickersAnimatedView.setText("Animated");
        } else {
            Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.static_indicator_vector);
            stickersAnimatedImage.setImageURI(animatedIcon);
            stickersAnimatedView.setText("Static");
        }
    }

    private void launchInfoActivity(String publisherWebsite, String publisherEmail, String privacyPolicyWebsite, String licenseAgreementWebsite, String trayIconUriString) {
        Intent intent = new Intent(StickerPackDetailsActivity.this, StickerPackInfoActivity.class);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_ID, stickerPack.identifier);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_WEBSITE, publisherWebsite);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_EMAIL, publisherEmail);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_PRIVACY_POLICY, privacyPolicyWebsite);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_LICENSE_AGREEMENT, licenseAgreementWebsite);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_TRAY_ICON, trayIconUriString);
        startActivity(intent);
    }

    public boolean onOptionsItemSelected() {
        if (stickerPack != null) {
            Uri trayIconUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile);
            launchInfoActivity(stickerPack.publisherWebsite, stickerPack.publisherEmail, stickerPack.privacyPolicyWebsite, stickerPack.licenseAgreementWebsite, trayIconUri.toString());
            return true;
        }
        return false;
    }

    private final ViewTreeObserver.OnGlobalLayoutListener pageLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            int imgSize = recyclerView.getContext().getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size);
            int recyclerViewWidth = recyclerView.getWidth();

            int numColumns = recyclerViewWidth / imgSize;
            int colSpacing = (recyclerViewWidth - (numColumns * imgSize)) / (numColumns - 1);
//            int colSpacing = recyclerView.getWidth() - imgSize * numColumns;

            setNumColumns(numColumns, colSpacing);
        }
    };

    @SuppressLint("NotifyDataSetChanged")
    private void setNumColumns(int numColumns, int colSpacing) {
        if (this.numColumns != numColumns) {

//            recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 2, 2));
            layoutManager.setSpanCount(numColumns);
            recyclerView.setLayoutManager(layoutManager);

            this.numColumns = numColumns;
            if (stickerPreviewAdapter != null) {
                stickerPreviewAdapter.notifyDataSetChanged();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        whiteListCheckAsyncTask = new WhiteListCheckAsyncTask(this);
        whiteListCheckAsyncTask.execute(stickerPack);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (whiteListCheckAsyncTask != null && !whiteListCheckAsyncTask.isCancelled()) {
            whiteListCheckAsyncTask.cancel(true);
        }
    }

    private void updateAddUI(Boolean isWhitelisted) {
        if (isWhitelisted) {
            addButton.setVisibility(View.GONE);
            alreadyAdded.setVisibility(View.VISIBLE);
        } else {
            addButton.setVisibility(View.VISIBLE);
            alreadyAdded.setVisibility(View.GONE);
        }
    }

    static class WhiteListCheckAsyncTask extends AsyncTask<StickerPack, Void, Boolean> {
        private final WeakReference<StickerPackDetailsActivity> stickerPackDetailsActivityWeakReference;

        WhiteListCheckAsyncTask(StickerPackDetailsActivity stickerPackListActivity) {
            this.stickerPackDetailsActivityWeakReference = new WeakReference<>(stickerPackListActivity);
        }

        @Override
        protected final Boolean doInBackground(StickerPack... stickerPacks) {
            StickerPack stickerPack = stickerPacks[0];
            final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
            if (stickerPackDetailsActivity == null) {
                return false;
            }
            return WhitelistCheck.isWhitelisted(stickerPackDetailsActivity, stickerPack.identifier);
        }

        @Override
        protected void onPostExecute(Boolean isWhitelisted) {
            final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
            if (stickerPackDetailsActivity != null) {
                stickerPackDetailsActivity.updateAddUI(isWhitelisted);
            }
        }
    }
}
```
<pre class="lang-java prettyprint-override"><code>/*
 * Copyright (c) WhatsApp Inc. and its affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.MyStickersWA.DogeStickers;

import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;

public class StickerPreviewAdapter extends RecyclerView.Adapter<StickerPreviewViewHolder> {

    private static final float COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA = 1f;
    private static final float EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA = 0.2f;

    @NonNull
    private final StickerPack stickerPack;

    private final int cellSize;
    private final int cellLimit;
    private final int cellPadding;
    private final int errorResource;
    private final SimpleDraweeView expandedStickerPreview;

    private final LayoutInflater layoutInflater;
    private RecyclerView recyclerView;
    private View clickedStickerPreview;
    float expandedViewLeftX;
    float expandedViewTopY;

    StickerPreviewAdapter(
            @NonNull final LayoutInflater layoutInflater,
            final int errorResource,
            final int cellSize,
            final int cellPadding,
            @NonNull final StickerPack stickerPack,
            final SimpleDraweeView expandedStickerView) {
        this.cellSize = cellSize;
        this.cellPadding = cellPadding;
        this.cellLimit = 0;
        this.layoutInflater = layoutInflater;
        this.errorResource = errorResource;
        this.stickerPack = stickerPack;
        this.expandedStickerPreview = expandedStickerView;
    }

    @NonNull
    @Override
    public StickerPreviewViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int i) {
        View itemView = layoutInflater.inflate(R.layout.sticker_image_item, viewGroup, false);
        StickerPreviewViewHolder vh = new StickerPreviewViewHolder(itemView);

        ViewGroup.LayoutParams layoutParams = vh.stickerPreviewView.getLayoutParams();
        layoutParams.height = cellSize;
        layoutParams.width = cellSize;
        vh.stickerPreviewView.setLayoutParams(layoutParams);
        vh.stickerPreviewView.setPadding(cellPadding, cellPadding, cellPadding, cellPadding);

        return vh;
    }

    @Override
    public void onBindViewHolder(@NonNull final StickerPreviewViewHolder stickerPreviewViewHolder, final int i) {
        stickerPreviewViewHolder.stickerPreviewView.setImageResource(errorResource);
        stickerPreviewViewHolder.stickerPreviewView.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(i).imageFileName));
        stickerPreviewViewHolder.stickerPreviewView.setOnClickListener(v -> expandPreview(i, stickerPreviewViewHolder.stickerPreviewView));
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.recyclerView = recyclerView;
        recyclerView.addOnScrollListener(hideExpandedViewScrollListener);
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        recyclerView.removeOnScrollListener(hideExpandedViewScrollListener);
        this.recyclerView = null;
    }

    private final RecyclerView.OnScrollListener hideExpandedViewScrollListener =
            new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    if (dx != 0 || dy != 0) {
                        hideExpandedStickerPreview();
                    }
                }
            };

    private void positionExpandedStickerPreview(int selectedPosition) {
        if (expandedStickerPreview != null) {
            // Calculate the view's center (x, y), then use expandedStickerPreview's height and
            // width to
            // figure out what where to position it.
            final ViewGroup.MarginLayoutParams recyclerViewLayoutParams =
                    ((ViewGroup.MarginLayoutParams) recyclerView.getLayoutParams());
            final int recyclerViewLeftMargin = recyclerViewLayoutParams.leftMargin;
            final int recyclerViewRightMargin = recyclerViewLayoutParams.rightMargin;
            final int recyclerViewWidth = recyclerView.getWidth();
            final int recyclerViewHeight = recyclerView.getHeight();

            final StickerPreviewViewHolder clickedViewHolder =
                    (StickerPreviewViewHolder)
                            recyclerView.findViewHolderForAdapterPosition(selectedPosition);
            if (clickedViewHolder == null) {
                hideExpandedStickerPreview();
                return;
            }
            clickedStickerPreview = clickedViewHolder.itemView;
            final float clickedViewCenterX =
                    clickedStickerPreview.getX()
                            + recyclerViewLeftMargin
                            + clickedStickerPreview.getWidth() / 2f;
            final float clickedViewCenterY =
                    clickedStickerPreview.getY() + clickedStickerPreview.getHeight() / 2f;

            expandedViewLeftX = clickedViewCenterX - expandedStickerPreview.getWidth() / 2f;
            expandedViewTopY = clickedViewCenterY - expandedStickerPreview.getHeight() / 2f;

            // If the new x or y positions are negative, anchor them to 0 to avoid clipping
            // the left side of the device and the top of the recycler view.
            expandedViewLeftX = Math.max(expandedViewLeftX, 0);
            expandedViewTopY = Math.max(expandedViewTopY, 0);

            // If the bottom or right sides are clipped, we need to move the top left positions
            // so that those sides are no longer clipped.
            final float adjustmentX =
                    Math.max(
                            expandedViewLeftX
                                    + expandedStickerPreview.getWidth()
                                    - recyclerViewWidth
                                    - recyclerViewRightMargin,
                            0);
            final float adjustmentY =
                    Math.max(expandedViewTopY + expandedStickerPreview.getHeight() - recyclerViewHeight, 0);

            expandedViewLeftX -= adjustmentX;
            expandedViewTopY -= adjustmentY;

            expandedStickerPreview.setX(expandedViewLeftX);
            expandedStickerPreview.setY(expandedViewTopY);
        }
    }

    private void expandPreview(int position, View clickedStickerPreview) {
        if (isStickerPreviewExpanded()) {
            hideExpandedStickerPreview();
            return;
        }

        this.clickedStickerPreview = clickedStickerPreview;
        if (expandedStickerPreview != null) {
            positionExpandedStickerPreview(position);

            final Uri stickerAssetUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(position).imageFileName);
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setUri(stickerAssetUri)
                    .setAutoPlayAnimations(true)
                    .build();
            expandedStickerPreview.setImageResource(errorResource);
            expandedStickerPreview.setController(controller);

            expandedStickerPreview.setVisibility(View.VISIBLE);
            recyclerView.setAlpha(EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA);

            expandedStickerPreview.setOnClickListener(v -> hideExpandedStickerPreview());
        }
    }

    public void hideExpandedStickerPreview() {
        if (isStickerPreviewExpanded() && expandedStickerPreview != null) {
            clickedStickerPreview.setVisibility(View.VISIBLE);
            expandedStickerPreview.setVisibility(View.INVISIBLE);
            recyclerView.setAlpha(COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA);
        }
    }

    private boolean isStickerPreviewExpanded() {
        return expandedStickerPreview != null && expandedStickerPreview.getVisibility() == View.VISIBLE;
    }

    @Override
    public int getItemCount() {
        int numberOfPreviewImagesInPack;
        numberOfPreviewImagesInPack = stickerPack.getStickers().size();
        if (cellLimit > 0) {
            return Math.min(numberOfPreviewImagesInPack, cellLimit);
        }
        return numberOfPreviewImagesInPack;
    }
}
</code>```

thanks in advance

答:
It seems like every item has right padding.

You should use addItemDecoration on your RecyclerView instead.

Or use this: https://github.com/grzegorzojdana/SpacingItemDecoration

ContentLicense: CC BY-SA 4.0

Body:
i don't know much about java, just started, so i will have difficulties understanding the answers. emli5.

screenshot:

expected output:

in the recyclerview (right), these items are not aligning up like i want them to.

I want that each cell has a fixed size, and maximum number of columns possible in the grid.
spacing b/w each cell (both vertical and horizontal) is equal to (left space) divided by (number of columns minus one).   [with no extra space left at start, top, bottom or end]

here is the code:

package com.MyStickersWA.DogeStickers;

import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.format.Formatter;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.facebook.drawee.view.SimpleDraweeView;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.AdView;
import com.google.android.gms.ads.MobileAds;

import java.lang.ref.WeakReference;
import java.util.ArrayList;

@SuppressWarnings("ALL")
public class StickerPackDetailsActivity extends AddStickerPackActivity {

    /**
     * Do not change below values of below 3 lines as this is also used by WhatsApp
     */
    public static final String EXTRA_STICKER_PACK_ID = "sticker_pack_id";
    public static final String EXTRA_STICKER_PACK_AUTHORITY = "sticker_pack_authority";
    public static final String EXTRA_STICKER_PACK_NAME = "sticker_pack_name";

    public static final String EXTRA_STICKER_PACK_WEBSITE = "sticker_pack_website";
    public static final String EXTRA_STICKER_PACK_EMAIL = "sticker_pack_email";
    public static final String EXTRA_STICKER_PACK_PRIVACY_POLICY = "sticker_pack_privacy_policy";
    public static final String EXTRA_STICKER_PACK_LICENSE_AGREEMENT = "sticker_pack_license_agreement";
    public static final String EXTRA_STICKER_PACK_TRAY_ICON = "sticker_pack_tray_icon";
    public static final String EXTRA_SHOW_UP_BUTTON = "show_up_button";
    public static final String EXTRA_STICKER_PACK_DATA = "sticker_pack";

    private RecyclerView recyclerView;
    private GridLayoutManager layoutManager;
    private StickerPreviewAdapter stickerPreviewAdapter;
    private int numColumns;
    private View addButton;
    private View infoButton;
    private View backButton;
    private View alreadyAdded;
    private StickerPack stickerPack;
    private WhiteListCheckAsyncTask whiteListCheckAsyncTask;

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

        AdView mAdView = findViewById(R.id.adView);
        AdRequest adRequest = new AdRequest.Builder().build();
        MobileAds.initialize(this, initializationStatus -> { });

        mAdView.loadAd(adRequest);

        boolean showUpButton = getIntent().getBooleanExtra(EXTRA_SHOW_UP_BUTTON, false);
        stickerPack = getIntent().getParcelableExtra(EXTRA_STICKER_PACK_DATA);
        TextView packNameTextView = findViewById(R.id.pack_name);
        TextView packPublisherTextView = findViewById(R.id.author);
        ImageView packTrayIcon = findViewById(R.id.tray_image);
        TextView packSizeTextView = findViewById(R.id.pack_size);
        TextView stickersQtyTextView = findViewById(R.id.stickers_qty);
        TextView stickersAnimatedView = findViewById(R.id.stickers_animated);
        ImageView stickersAnimatedImage = findViewById(R.id.sticker_pack_animation_indicator);
        SimpleDraweeView expandedStickerView = findViewById(R.id.sticker_details_expanded_sticker);

        addButton = findViewById(R.id.add_to_whatsapp_button);
        infoButton = findViewById(R.id.action_info);
        backButton = findViewById(R.id.action_back);
        alreadyAdded = findViewById(R.id.already_added_button);
        layoutManager = new GridLayoutManager(this, 1);
        recyclerView = findViewById(R.id.sticker_list);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(pageLayoutListener);

        if (stickerPreviewAdapter == null) {
            stickerPreviewAdapter = new StickerPreviewAdapter(getLayoutInflater(), R.drawable.sticker_error, getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size), getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_padding), stickerPack, expandedStickerView);
            recyclerView.setAdapter(stickerPreviewAdapter);
        }
        packNameTextView.setText(stickerPack.name);
        packPublisherTextView.setText(stickerPack.publisher);
        packTrayIcon.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile));
        packSizeTextView.setText(Formatter.formatShortFileSize(this, stickerPack.getTotalSize()));
        stickersQtyTextView.setText(stickerPack.getTotalQty() + "");
        addButton.setOnClickListener(v -> addStickerPackToWhatsApp(stickerPack.identifier, stickerPack.name));
        infoButton.setOnClickListener(v -> onOptionsItemSelected());
        backButton.setOnClickListener(v -> finish());

        if (stickerPack.animatedStickerPack) {
            Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.animated_indicator_vector);
            stickersAnimatedImage.setImageURI(animatedIcon);
            stickersAnimatedView.setText("Animated");
        } else {
            Uri animatedIcon = Uri.parse("android.resource://" + getPackageName() + "/"+R.drawable.static_indicator_vector);
            stickersAnimatedImage.setImageURI(animatedIcon);
            stickersAnimatedView.setText("Static");
        }
    }

    private void launchInfoActivity(String publisherWebsite, String publisherEmail, String privacyPolicyWebsite, String licenseAgreementWebsite, String trayIconUriString) {
        Intent intent = new Intent(StickerPackDetailsActivity.this, StickerPackInfoActivity.class);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_ID, stickerPack.identifier);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_WEBSITE, publisherWebsite);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_EMAIL, publisherEmail);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_PRIVACY_POLICY, privacyPolicyWebsite);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_LICENSE_AGREEMENT, licenseAgreementWebsite);
        intent.putExtra(StickerPackDetailsActivity.EXTRA_STICKER_PACK_TRAY_ICON, trayIconUriString);
        startActivity(intent);
    }

    public boolean onOptionsItemSelected() {
        if (stickerPack != null) {
            Uri trayIconUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.trayImageFile);
            launchInfoActivity(stickerPack.publisherWebsite, stickerPack.publisherEmail, stickerPack.privacyPolicyWebsite, stickerPack.licenseAgreementWebsite, trayIconUri.toString());
            return true;
        }
        return false;
    }

    private final ViewTreeObserver.OnGlobalLayoutListener pageLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {

            int imgSize = recyclerView.getContext().getResources().getDimensionPixelSize(R.dimen.sticker_pack_details_image_size);
            int recyclerViewWidth = recyclerView.getWidth();

            int numColumns = recyclerViewWidth / imgSize;
            int colSpacing = (recyclerViewWidth - (numColumns * imgSize)) / (numColumns - 1);
//            int colSpacing = recyclerView.getWidth() - imgSize * numColumns;

            setNumColumns(numColumns, colSpacing);
        }
    };

    @SuppressLint("NotifyDataSetChanged")
    private void setNumColumns(int numColumns, int colSpacing) {
        if (this.numColumns != numColumns) {

//            recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 2, 2));
            layoutManager.setSpanCount(numColumns);
            recyclerView.setLayoutManager(layoutManager);

            this.numColumns = numColumns;
            if (stickerPreviewAdapter != null) {
                stickerPreviewAdapter.notifyDataSetChanged();
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        whiteListCheckAsyncTask = new WhiteListCheckAsyncTask(this);
        whiteListCheckAsyncTask.execute(stickerPack);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (whiteListCheckAsyncTask != null && !whiteListCheckAsyncTask.isCancelled()) {
            whiteListCheckAsyncTask.cancel(true);
        }
    }

    private void updateAddUI(Boolean isWhitelisted) {
        if (isWhitelisted) {
            addButton.setVisibility(View.GONE);
            alreadyAdded.setVisibility(View.VISIBLE);
        } else {
            addButton.setVisibility(View.VISIBLE);
            alreadyAdded.setVisibility(View.GONE);
        }
    }

    static class WhiteListCheckAsyncTask extends AsyncTask<StickerPack, Void, Boolean> {
        private final WeakReference<StickerPackDetailsActivity> stickerPackDetailsActivityWeakReference;

        WhiteListCheckAsyncTask(StickerPackDetailsActivity stickerPackListActivity) {
            this.stickerPackDetailsActivityWeakReference = new WeakReference<>(stickerPackListActivity);
        }

        @Override
        protected final Boolean doInBackground(StickerPack... stickerPacks) {
            StickerPack stickerPack = stickerPacks[0];
            final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
            if (stickerPackDetailsActivity == null) {
                return false;
            }
            return WhitelistCheck.isWhitelisted(stickerPackDetailsActivity, stickerPack.identifier);
        }

        @Override
        protected void onPostExecute(Boolean isWhitelisted) {
            final StickerPackDetailsActivity stickerPackDetailsActivity = stickerPackDetailsActivityWeakReference.get();
            if (stickerPackDetailsActivity != null) {
                stickerPackDetailsActivity.updateAddUI(isWhitelisted);
            }
        }
    }
}

/*
 * Copyright (c) WhatsApp Inc. and its affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */

package com.MyStickersWA.DogeStickers;

import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.drawee.interfaces.DraweeController;
import com.facebook.drawee.view.SimpleDraweeView;

public class StickerPreviewAdapter extends RecyclerView.Adapter<StickerPreviewViewHolder> {

    private static final float COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA = 1f;
    private static final float EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA = 0.2f;

    @NonNull
    private final StickerPack stickerPack;

    private final int cellSize;
    private final int cellLimit;
    private final int cellPadding;
    private final int errorResource;
    private final SimpleDraweeView expandedStickerPreview;

    private final LayoutInflater layoutInflater;
    private RecyclerView recyclerView;
    private View clickedStickerPreview;
    float expandedViewLeftX;
    float expandedViewTopY;

    StickerPreviewAdapter(
            @NonNull final LayoutInflater layoutInflater,
            final int errorResource,
            final int cellSize,
            final int cellPadding,
            @NonNull final StickerPack stickerPack,
            final SimpleDraweeView expandedStickerView) {
        this.cellSize = cellSize;
        this.cellPadding = cellPadding;
        this.cellLimit = 0;
        this.layoutInflater = layoutInflater;
        this.errorResource = errorResource;
        this.stickerPack = stickerPack;
        this.expandedStickerPreview = expandedStickerView;
    }

    @NonNull
    @Override
    public StickerPreviewViewHolder onCreateViewHolder(@NonNull final ViewGroup viewGroup, final int i) {
        View itemView = layoutInflater.inflate(R.layout.sticker_image_item, viewGroup, false);
        StickerPreviewViewHolder vh = new StickerPreviewViewHolder(itemView);

        ViewGroup.LayoutParams layoutParams = vh.stickerPreviewView.getLayoutParams();
        layoutParams.height = cellSize;
        layoutParams.width = cellSize;
        vh.stickerPreviewView.setLayoutParams(layoutParams);
        vh.stickerPreviewView.setPadding(cellPadding, cellPadding, cellPadding, cellPadding);

        return vh;
    }

    @Override
    public void onBindViewHolder(@NonNull final StickerPreviewViewHolder stickerPreviewViewHolder, final int i) {
        stickerPreviewViewHolder.stickerPreviewView.setImageResource(errorResource);
        stickerPreviewViewHolder.stickerPreviewView.setImageURI(StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(i).imageFileName));
        stickerPreviewViewHolder.stickerPreviewView.setOnClickListener(v -> expandPreview(i, stickerPreviewViewHolder.stickerPreviewView));
    }

    @Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        this.recyclerView = recyclerView;
        recyclerView.addOnScrollListener(hideExpandedViewScrollListener);
    }

    @Override
    public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onDetachedFromRecyclerView(recyclerView);
        recyclerView.removeOnScrollListener(hideExpandedViewScrollListener);
        this.recyclerView = null;
    }

    private final RecyclerView.OnScrollListener hideExpandedViewScrollListener =
            new RecyclerView.OnScrollListener() {
                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                    if (dx != 0 || dy != 0) {
                        hideExpandedStickerPreview();
                    }
                }
            };

    private void positionExpandedStickerPreview(int selectedPosition) {
        if (expandedStickerPreview != null) {
            // Calculate the view's center (x, y), then use expandedStickerPreview's height and
            // width to
            // figure out what where to position it.
            final ViewGroup.MarginLayoutParams recyclerViewLayoutParams =
                    ((ViewGroup.MarginLayoutParams) recyclerView.getLayoutParams());
            final int recyclerViewLeftMargin = recyclerViewLayoutParams.leftMargin;
            final int recyclerViewRightMargin = recyclerViewLayoutParams.rightMargin;
            final int recyclerViewWidth = recyclerView.getWidth();
            final int recyclerViewHeight = recyclerView.getHeight();

            final StickerPreviewViewHolder clickedViewHolder =
                    (StickerPreviewViewHolder)
                            recyclerView.findViewHolderForAdapterPosition(selectedPosition);
            if (clickedViewHolder == null) {
                hideExpandedStickerPreview();
                return;
            }
            clickedStickerPreview = clickedViewHolder.itemView;
            final float clickedViewCenterX =
                    clickedStickerPreview.getX()
                            + recyclerViewLeftMargin
                            + clickedStickerPreview.getWidth() / 2f;
            final float clickedViewCenterY =
                    clickedStickerPreview.getY() + clickedStickerPreview.getHeight() / 2f;

            expandedViewLeftX = clickedViewCenterX - expandedStickerPreview.getWidth() / 2f;
            expandedViewTopY = clickedViewCenterY - expandedStickerPreview.getHeight() / 2f;

            // If the new x or y positions are negative, anchor them to 0 to avoid clipping
            // the left side of the device and the top of the recycler view.
            expandedViewLeftX = Math.max(expandedViewLeftX, 0);
            expandedViewTopY = Math.max(expandedViewTopY, 0);

            // If the bottom or right sides are clipped, we need to move the top left positions
            // so that those sides are no longer clipped.
            final float adjustmentX =
                    Math.max(
                            expandedViewLeftX
                                    + expandedStickerPreview.getWidth()
                                    - recyclerViewWidth
                                    - recyclerViewRightMargin,
                            0);
            final float adjustmentY =
                    Math.max(expandedViewTopY + expandedStickerPreview.getHeight() - recyclerViewHeight, 0);

            expandedViewLeftX -= adjustmentX;
            expandedViewTopY -= adjustmentY;

            expandedStickerPreview.setX(expandedViewLeftX);
            expandedStickerPreview.setY(expandedViewTopY);
        }
    }

    private void expandPreview(int position, View clickedStickerPreview) {
        if (isStickerPreviewExpanded()) {
            hideExpandedStickerPreview();
            return;
        }

        this.clickedStickerPreview = clickedStickerPreview;
        if (expandedStickerPreview != null) {
            positionExpandedStickerPreview(position);

            final Uri stickerAssetUri = StickerPackLoader.getStickerAssetUri(stickerPack.identifier, stickerPack.getStickers().get(position).imageFileName);
            DraweeController controller = Fresco.newDraweeControllerBuilder()
                    .setUri(stickerAssetUri)
                    .setAutoPlayAnimations(true)
                    .build();
            expandedStickerPreview.setImageResource(errorResource);
            expandedStickerPreview.setController(controller);

            expandedStickerPreview.setVisibility(View.VISIBLE);
            recyclerView.setAlpha(EXPANDED_STICKER_PREVIEW_BACKGROUND_ALPHA);

            expandedStickerPreview.setOnClickListener(v -> hideExpandedStickerPreview());
        }
    }

    public void hideExpandedStickerPreview() {
        if (isStickerPreviewExpanded() && expandedStickerPreview != null) {
            clickedStickerPreview.setVisibility(View.VISIBLE);
            expandedStickerPreview.setVisibility(View.INVISIBLE);
            recyclerView.setAlpha(COLLAPSED_STICKER_PREVIEW_BACKGROUND_ALPHA);
        }
    }

    private boolean isStickerPreviewExpanded() {
        return expandedStickerPreview != null && expandedStickerPreview.getVisibility() == View.VISIBLE;
    }

    @Override
    public int getItemCount() {
        int numberOfPreviewImagesInPack;
        numberOfPreviewImagesInPack = stickerPack.getStickers().size();
        if (cellLimit > 0) {
            return Math.min(numberOfPreviewImagesInPack, cellLimit);
        }
        return numberOfPreviewImagesInPack;
    }
}

thanks in advance


问:
Exception in NodeWeb Kit for Canvas
I am trying to convert my nodejs application into an .exe file. I am stuck with the canvas module(npm install @tensorflow/tfjs canvas). For some reason,nw.js is not able to load this module.

This is the line for which I am getting the error :

```<code>const canvas = require("canvas");
</code>```

And this is the error :

I did go through this but unfortunately it didn't help.
My node version is : 16.10.10 and nw.js version is : 0.57.1. Using Windows10.

Is there any way in which this can be solved ? Thanks.

答:
It's my understanding that anything using nw-gyp won't work with newer version of node because of the difference in supported Python versions. Somebody needs to get nw-gyp ported to work with Python 3.

One related thread: edge-js build failing with nw-gyp

Title: Exception in NodeWeb Kit for Canvas

Body:
I am trying to convert my nodejs application into an .exe file. I am stuck with the canvas module(npm install @tensorflow/tfjs canvas). For some reason,nw.js is not able to load this module.

This is the line for which I am getting the error :

const canvas = require("canvas");

And this is the error :

I did go through this but unfortunately it didn't help.
My node version is : 16.10.10 and nw.js version is : 0.57.1. Using Windows10.

Is there any way in which this can be solved ? Thanks.


问:
Matplotlib PathPatch Colors and Legends not Matching
I have a dataset that is a list of lists.

Each list is a category to be plotted as a box plot.

Each list has a list of up to 9 components to be plotted into subplots.

The functions I am using is below was based on this answer.  I pulled it out of my work and added some mock data. Should be a minimal example below.

```<code>neonDict = {
    0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8

    }
import matplotlib as mpl
import matplotlib.pyplot as plt

def coloredBoxPlot(axis, data,edgeColor,fillColor):
        bp = axis.boxplot(data,vert=False,patch_artist=True)
        for element in ['boxes', 'whiskers', 'fliers', 'means', 'medians', 'caps']:
            plt.setp(bp[element], color=edgeColor)

        for patch in bp['boxes']:
            patch.set(facecolor=fillColor)

        return bp

def plotCalStats(data, prefix='Channel', savedir=None,colors=['#00597c','#a8005c','#00aeea','#007d50','#400080','#e07800'] ):

    csize = mpl.rcParams['figure.figsize']
    cdpi = mpl.rcParams['figure.dpi']

    mpl.rcParams['figure.figsize'] = (12,8)
    mpl.rcParams['figure.dpi'] = 1080

    pkdata  = []
    labels  = []
    lstyles = []

    fg, ax = plt.subplots(3,3)
    for pk in range(len(neonDict)):
        px = pk // 3
        py = pk  % 3
        ax[px,py].set_xlabel('Max Pixel')
        ax[px,py].set_ylabel('')
        ax[px,py].set_title(str(neonDict[pk]) + ' nm')
        pkdata.append([])

    for cat in range(len(data)):
        bp = ''

        for acal in data[cat]:
            for apeak in acal.peaks:
                pkdata[apeak].append(acal.peaks[apeak][0])

        for pk in range(9):
            px = pk // 3
            py = pk  % 3
            bp = coloredBoxPlot(ax[px,py], pkdata[pk], colors[cat], '#ffffff')

        if len(data[cat]) > 0:
            #print(colors[cat])
            #print(bp['boxes'][0].get_edgecolor())
            labels.append(prefix+' '+str(cat))
            lstyles.append(bp['boxes'][0])

    fg.legend(lstyles,labels)
    fg.suptitle('Calibration Summary by '+prefix)
    fg.tight_layout()
    if savedir is not None:
        plt.savefig(savedir + 'Boxplots.png')

    plt.show()

    mpl.rcParams['figure.figsize'] = csize
    mpl.rcParams['figure.dpi']     = cdpi
    return

class acal:
    def __init__(self):
        self.peaks = {}
        for x in range(9):
            self.peaks[x] = (np.random.randint(20*x,20*(x+1)),)

mockData = [[acal() for y in range(100)] for x in range(6)]

#Some unused channels
mockData[2] = []
mockData[3] = []
mockData[4] = []

plotCalStats(mockData)
</code>```

So the issue is that the plot colors do not match the legend.  Even if I restrict the data to only add a label if data exists (ensuring thus there is no issue with calling boxplots with an empty data set and not getting an appropriate PathPatch.

The printouts verify the colors are correctly stored in the PathPatch.  (I can add my digits -> hex converter) if that is questioned.

Attached is the output.  One can see I get a purple box but no purple in the legend.  Purple is the 4th category which is empty.

Any ideas why the labels don't match the actual style?  Thanks much!

EDITS:
To address question on 'confusing'.
I have six categories of data, each category is coming from a single event.  Each event has 9 components.  I want to compare all events, for each individual component, for each category on a single plot as shown below.

Each subplot is a individual component comprised from the series of data for each categorical (Channel).

So the link I have provided, (like I said, is adapted from) shows how to create a single box plot on one axis for 2 data sets.  I've basically done the same thing for 6 data sets on 9 axis, where 3 data sets are empty (but don't have to be, I did it to illustrate the issue.  If I have all 6 data sets there, how can you tell the colors are messed up?????)

Regarding the alpha:

The alphas are always 'ff' when giving only RGB data to matplotlib.  If I call get_edgecolors, it will return a tuple (RGBA) where A = 1.0.
See commented out print statement.

EDIT2:

If I restrict it down to a single category, it makes the box plot view less confusing.

Single Example (see how box plot color is orange, figure says it's blue)

All colors off

Feel like this used to work....

答:
Uncertain how the error presented as it did, but the issue has to do with reformatting the data before creating the box plot.

By removing pkdata.append([]) during the creation of the subplots before looping the categories and adding:
pkdata = [[],[],[],[],[],[],[],[],[]] during each iteration of the category loop fixed the issue.  The former was sending in all previous channel data...

Output is now better.  Full sol attached.

Likely, since the plot uses data from pkdata, the empty channel (data[cat]) plotted previous data (from data[cat-1]) as that was still in pkdata (actually, all previous data[cat] was still in pkdata) which was then plotted.  I only check data[cat] for data on each loop to add to the legend.  The legend was set up for channels 0,1,5, for example.. but we saw data for channel: 0 as 0, 0+1 as 1, 0+1 as 2, 0+1 as 3, 0+1 as 4, 0+1+5 as 5... thus channel 4 (purple) had data to plot but wasn't added to the legend.  Giving the impression of 'misaligned' legends but rather unlegend data...

The single channel data is actually all 6 channels overlapping, the final channel 5 color being orange, overlapping all previous, namely the original channel 0 data to whom the data belongs and was properly added to the legend.

```<code>neonDict = {
    0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8

    }
import matplotlib as mpl
import matplotlib.pyplot as plt

def getHex(r,g,b,a=1.0):

    colors = [int(r * 255 ),int(g * 255 ),int(b * 255 ),int(a * 255) ]
    s = '#'

    for x in range(4):
        cs = hex(colors[x])
        if len(cs) == 3:
            cs = cs + '0'

        s += cs.replace('0x','')

    return s

def getRGB(colstr):
    try:
        a = ''
        r = int(colstr[1:3],16) / 255
        g = int(colstr[3:5],16) / 255
        b = int(colstr[5:7],16) / 255

        if len (colstr) == 7:
            a = 1.0
        else:
            a = int(colstr[7:],16) / 255

        return (r,g,b,a)
    except Exception as e:
        print(e)
        raise e

    return

def compareHexColors(col1,col2):
    try:
        ## ASSUME #RBG or #RBGA
        ## If less than 7, append the ff for the colors
        if len(col1) < 9:
            col1 += 'ff'
        if len(col2) < 9:
            col2 += 'ff'

        return col1.lower() == col2.lower()
    except Exception as e:
        raise e
    return False

def coloredBoxPlot(axis, data,edgeColor,fillColor):
        bp = axis.boxplot(data,vert=False,patch_artist=True)
        for element in ['boxes', 'whiskers', 'fliers', 'means', 'medians', 'caps']:
            plt.setp(bp[element], color=edgeColor)

        for patch in bp['boxes']:
            patch.set(facecolor=fillColor)

        return bp

def plotCalStats(data, prefix='Channel', savedir=None,colors=['#00597c','#a8005c','#00aeea','#007d50','#400080','#e07800'] ):

    csize = mpl.rcParams['figure.figsize']
    cdpi = mpl.rcParams['figure.dpi']

    mpl.rcParams['figure.figsize'] = (12,8)
    mpl.rcParams['figure.dpi'] = 1080

    pkdata  = []
    labels  = []
    lstyles = []

    fg, ax = plt.subplots(3,3)
    for pk in range(len(neonDict)):
        px = pk // 3
        py = pk  % 3
        ax[px,py].set_xlabel('Max Pixel')
        ax[px,py].set_ylabel('')
        ax[px,py].set_title(str(neonDict[pk]) + ' nm')

    for cat in range(len(data)):
        bp = ''
        pkdata = [[],[],[],[],[],[],[],[],[]]

        for acal in data[cat]:
            for apeak in acal.peaks:
                pkdata[apeak].append(acal.peaks[apeak][0])

        for pk in range(9):
            px = pk // 3
            py = pk  % 3
            bp = coloredBoxPlot(ax[px,py], pkdata[pk], colors[cat], '#ffffff')

        if len(data[cat]) > 0:
            print(compareHexColors(colors[cat],getHex(*bp['boxes'][0].get_edgecolor())))
            labels.append(prefix+' '+str(cat))
            lstyles.append(bp['boxes'][0])

    fg.legend(lstyles,labels)
    fg.suptitle('Calibration Summary by '+prefix)
    fg.tight_layout()
    if savedir is not None:
        plt.savefig(savedir + 'Boxplots.png')

    plt.show()

    mpl.rcParams['figure.figsize'] = csize
    mpl.rcParams['figure.dpi']     = cdpi
    return

class acal:
    def __init__(self,center):
        self.peaks = {}
        for x in range(9):
            self.peaks[x] = [10*x + (center) + (np.random.randint(10)-1)/2.0,0,0]

mockData = [[acal(x) for y in range(1000)] for x in range(6)]

#Some unused channels

mockData[2] = []
mockData[3] = []
mockData[4] = []

plotCalStats(mockData)
</code>```

Body:
I have a dataset that is a list of lists.

Each list is a category to be plotted as a box plot.

Each list has a list of up to 9 components to be plotted into subplots.

The functions I am using is below was based on this answer.  I pulled it out of my work and added some mock data. Should be a minimal example below.

neonDict = {
    0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8

    }
import matplotlib as mpl
import matplotlib.pyplot as plt

def coloredBoxPlot(axis, data,edgeColor,fillColor):
        bp = axis.boxplot(data,vert=False,patch_artist=True)
        for element in ['boxes', 'whiskers', 'fliers', 'means', 'medians', 'caps']:
            plt.setp(bp[element], color=edgeColor)

        for patch in bp['boxes']:
            patch.set(facecolor=fillColor)

        return bp

def plotCalStats(data, prefix='Channel', savedir=None,colors=['#00597c','#a8005c','#00aeea','#007d50','#400080','#e07800'] ):

    csize = mpl.rcParams['figure.figsize']
    cdpi = mpl.rcParams['figure.dpi']

    mpl.rcParams['figure.figsize'] = (12,8)
    mpl.rcParams['figure.dpi'] = 1080

    pkdata  = []
    labels  = []
    lstyles = []

    fg, ax = plt.subplots(3,3)
    for pk in range(len(neonDict)):
        px = pk // 3
        py = pk  % 3
        ax[px,py].set_xlabel('Max Pixel')
        ax[px,py].set_ylabel('')
        ax[px,py].set_title(str(neonDict[pk]) + ' nm')
        pkdata.append([])

    for cat in range(len(data)):
        bp = ''

        for acal in data[cat]:
            for apeak in acal.peaks:
                pkdata[apeak].append(acal.peaks[apeak][0])

        for pk in range(9):
            px = pk // 3
            py = pk  % 3
            bp = coloredBoxPlot(ax[px,py], pkdata[pk], colors[cat], '#ffffff')

        if len(data[cat]) > 0:
            #print(colors[cat])
            #print(bp['boxes'][0].get_edgecolor())
            labels.append(prefix+' '+str(cat))
            lstyles.append(bp['boxes'][0])

    fg.legend(lstyles,labels)
    fg.suptitle('Calibration Summary by '+prefix)
    fg.tight_layout()
    if savedir is not None:
        plt.savefig(savedir + 'Boxplots.png')

    plt.show()

    mpl.rcParams['figure.figsize'] = csize
    mpl.rcParams['figure.dpi']     = cdpi
    return

class acal:
    def __init__(self):
        self.peaks = {}
        for x in range(9):
            self.peaks[x] = (np.random.randint(20*x,20*(x+1)),)

mockData = [[acal() for y in range(100)] for x in range(6)]

#Some unused channels
mockData[2] = []
mockData[3] = []
mockData[4] = []

plotCalStats(mockData)

So the issue is that the plot colors do not match the legend.  Even if I restrict the data to only add a label if data exists (ensuring thus there is no issue with calling boxplots with an empty data set and not getting an appropriate PathPatch.

The printouts verify the colors are correctly stored in the PathPatch.  (I can add my digits -> hex converter) if that is questioned.

Attached is the output.  One can see I get a purple box but no purple in the legend.  Purple is the 4th category which is empty.

Any ideas why the labels don't match the actual style?  Thanks much!

EDITS:
To address question on 'confusing'.
I have six categories of data, each category is coming from a single event.  Each event has 9 components.  I want to compare all events, for each individual component, for each category on a single plot as shown below.

Each subplot is a individual component comprised from the series of data for each categorical (Channel).

So the link I have provided, (like I said, is adapted from) shows how to create a single box plot on one axis for 2 data sets.  I've basically done the same thing for 6 data sets on 9 axis, where 3 data sets are empty (but don't have to be, I did it to illustrate the issue.  If I have all 6 data sets there, how can you tell the colors are messed up?????)

Regarding the alpha:

The alphas are always 'ff' when giving only RGB data to matplotlib.  If I call get_edgecolors, it will return a tuple (RGBA) where A = 1.0.
See commented out print statement.

EDIT2:

If I restrict it down to a single category, it makes the box plot view less confusing.

Single Example (see how box plot color is orange, figure says it's blue)

All colors off

Feel like this used to work....

Body:
Uncertain how the error presented as it did, but the issue has to do with reformatting the data before creating the box plot.

By removing pkdata.append([]) during the creation of the subplots before looping the categories and adding:
pkdata = [[],[],[],[],[],[],[],[],[]] during each iteration of the category loop fixed the issue.  The former was sending in all previous channel data...

Output is now better.  Full sol attached.

Likely, since the plot uses data from pkdata, the empty channel (data[cat]) plotted previous data (from data[cat-1]) as that was still in pkdata (actually, all previous data[cat] was still in pkdata) which was then plotted.  I only check data[cat] for data on each loop to add to the legend.  The legend was set up for channels 0,1,5, for example.. but we saw data for channel: 0 as 0, 0+1 as 1, 0+1 as 2, 0+1 as 3, 0+1 as 4, 0+1+5 as 5... thus channel 4 (purple) had data to plot but wasn't added to the legend.  Giving the impression of 'misaligned' legends but rather unlegend data...

The single channel data is actually all 6 channels overlapping, the final channel 5 color being orange, overlapping all previous, namely the original channel 0 data to whom the data belongs and was properly added to the legend.

neonDict = {
    0:0, 1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8

    }
import matplotlib as mpl
import matplotlib.pyplot as plt

def getHex(r,g,b,a=1.0):

    colors = [int(r * 255 ),int(g * 255 ),int(b * 255 ),int(a * 255) ]
    s = '#'

    for x in range(4):
        cs = hex(colors[x])
        if len(cs) == 3:
            cs = cs + '0'

        s += cs.replace('0x','')

    return s

def getRGB(colstr):
    try:
        a = ''
        r = int(colstr[1:3],16) / 255
        g = int(colstr[3:5],16) / 255
        b = int(colstr[5:7],16) / 255

        if len (colstr) == 7:
            a = 1.0
        else:
            a = int(colstr[7:],16) / 255

        return (r,g,b,a)
    except Exception as e:
        print(e)
        raise e

    return

def compareHexColors(col1,col2):
    try:
        ## ASSUME #RBG or #RBGA
        ## If less than 7, append the ff for the colors
        if len(col1) < 9:
            col1 += 'ff'
        if len(col2) < 9:
            col2 += 'ff'

        return col1.lower() == col2.lower()
    except Exception as e:
        raise e
    return False

def coloredBoxPlot(axis, data,edgeColor,fillColor):
        bp = axis.boxplot(data,vert=False,patch_artist=True)
        for element in ['boxes', 'whiskers', 'fliers', 'means', 'medians', 'caps']:
            plt.setp(bp[element], color=edgeColor)

        for patch in bp['boxes']:
            patch.set(facecolor=fillColor)

        return bp

def plotCalStats(data, prefix='Channel', savedir=None,colors=['#00597c','#a8005c','#00aeea','#007d50','#400080','#e07800'] ):

    csize = mpl.rcParams['figure.figsize']
    cdpi = mpl.rcParams['figure.dpi']

    mpl.rcParams['figure.figsize'] = (12,8)
    mpl.rcParams['figure.dpi'] = 1080

    pkdata  = []
    labels  = []
    lstyles = []

    fg, ax = plt.subplots(3,3)
    for pk in range(len(neonDict)):
        px = pk // 3
        py = pk  % 3
        ax[px,py].set_xlabel('Max Pixel')
        ax[px,py].set_ylabel('')
        ax[px,py].set_title(str(neonDict[pk]) + ' nm')

    for cat in range(len(data)):
        bp = ''
        pkdata = [[],[],[],[],[],[],[],[],[]]

        for acal in data[cat]:
            for apeak in acal.peaks:
                pkdata[apeak].append(acal.peaks[apeak][0])

        for pk in range(9):
            px = pk // 3
            py = pk  % 3
            bp = coloredBoxPlot(ax[px,py], pkdata[pk], colors[cat], '#ffffff')

        if len(data[cat]) > 0:
            print(compareHexColors(colors[cat],getHex(*bp['boxes'][0].get_edgecolor())))
            labels.append(prefix+' '+str(cat))
            lstyles.append(bp['boxes'][0])

    fg.legend(lstyles,labels)
    fg.suptitle('Calibration Summary by '+prefix)
    fg.tight_layout()
    if savedir is not None:
        plt.savefig(savedir + 'Boxplots.png')

    plt.show()

    mpl.rcParams['figure.figsize'] = csize
    mpl.rcParams['figure.dpi']     = cdpi
    return

class acal:
    def __init__(self,center):
        self.peaks = {}
        for x in range(9):
            self.peaks[x] = [10*x + (center) + (np.random.randint(10)-1)/2.0,0,0]

mockData = [[acal(x) for y in range(1000)] for x in range(6)]

#Some unused channels

mockData[2] = []
mockData[3] = []
mockData[4] = []

plotCalStats(mockData)


问:
How to change the text color of an Android ToogleButton on state change?
my toggle-Button has different colored backgrounds for each state(red and white).
Now I need to change the color of the togglebutton-text(red/white) when activated.
With xml I just cannot get it working, perhaps anybody has an idea what I'm doing wrong?

My button in the Layout xml:

```<code><ToggleButton
android:paddingRight="20dip"
android:id="@+id/pseudo_tab_right"
android:layout_weight=".50"
android:layout_width="wrap_content"
android:textStyle="bold"
android:paddingLeft="10dip"
android:textSize="12sp"
android:layout_height="wrap_content"
android:textColor="@drawable/pseudo_tab_text_color"
android:textOff="@string/pseudo_tab_right_text"
android:textOn="@string/pseudo_tab_right_text"
android:background="@drawable/tab_button_right"
/>
</code>```

xml for button-states:

```<code><?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/sort_button_red_right_43" />
<item android:drawable="@drawable/sort_button_white_right_43" />
</selector>
</code>```

And xml for color:

```<code><?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- pressed -->
<item android:state_pressed="true" android:color="#4f5459" />

<!-- focused -->
<item android:state_focused="true" android:color="#4f5459" />

<!-- default -->
<item android:color="#ffffff" />

<!-- trying these out, but none works -->
<item android:state_checked="true" android:color="#ff0000" />
<item android:state_enabled="true" android:color="#ff00dd" />
<item android:state_selected="true" android:color="#ff00dd" />
<item android:state_active="true" android:color="#ff00dd" />

</selector>
</code>```

答:
Found it:
now I'm using android:state_checked="true" and android:state_checked="false".

color-xml:

```<code><?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="#ffffff" />
    <item android:state_checked="false" android:color="#000000" />
</selector>
</code>```

ContentLicense: CC BY-SA 3.0

Body:
my toggle-Button has different colored backgrounds for each state(red and white).
Now I need to change the color of the togglebutton-text(red/white) when activated.
With xml I just cannot get it working, perhaps anybody has an idea what I'm doing wrong?

My button in the Layout xml:

<ToggleButton
android:paddingRight="20dip"
android:id="@+id/pseudo_tab_right"
android:layout_weight=".50"
android:layout_width="wrap_content"
android:textStyle="bold"
android:paddingLeft="10dip"
android:textSize="12sp"
android:layout_height="wrap_content"
android:textColor="@drawable/pseudo_tab_text_color"
android:textOff="@string/pseudo_tab_right_text"
android:textOn="@string/pseudo_tab_right_text"
android:background="@drawable/tab_button_right"
/>

xml for button-states:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/sort_button_red_right_43" />
<item android:drawable="@drawable/sort_button_white_right_43" />
</selector>

And xml for color:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

<item android:state_pressed="true" android:color="#4f5459" />

<item android:state_focused="true" android:color="#4f5459" />

<item android:color="#ffffff" />

<item android:state_checked="true" android:color="#ff0000" />
<item android:state_enabled="true" android:color="#ff00dd" />
<item android:state_selected="true" android:color="#ff00dd" />
<item android:state_active="true" android:color="#ff00dd" />

</selector>

Body:
Found it:
now I'm using android:state_checked="true" and android:state_checked="false".

color-xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:color="#ffffff" />
    <item android:state_checked="false" android:color="#000000" />
</selector>


问:
How to serve django media files via nginx ?
I'm new at Nginx, I've successfully bound my django project to Nginx. However I can't serve my static files and I guess I set my media folder's location wrongly. Here is my file tree:

```<code>root_directory
     my_django_project
         ...
         manage.py
         app1
         app2
         media
           admin
           css
           js
           ...
</code>```

And my nginx.conf goes like :

```<code>        server {
                listen 192.168.1.9:80;
                server_name localhost;
                # site_media - folder in uri for static files

            location /media/  {
            root /home/nazmi/workspace/portal/media/;
                }

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov) {
  access_log   off; # po co mi logi obrazków :)
  expires      30d;
}
                location / {
                        # host and port to fastcgi server
                        fastcgi_pass 127.0.0.1:8080;
            fastcgi_param PATH_INFO $fastcgi_script_name;
                        fastcgi_param REQUEST_METHOD $request_method;
                        fastcgi_param QUERY_STRING $query_string;
                        fastcgi_param CONTENT_TYPE $content_type;
                        fastcgi_param CONTENT_LENGTH $content_length;
            fastcgi_pass_header Authorization;
                        fastcgi_intercept_errors off;
                        }
                access_log      /var/log/nginx/localhost.access_log main;
                error_log       /var/log/nginx/localhost.error_log;
        }
}
</code>```

When I open my admin page, all css pages give 404 error. Can you tell me that how can I set my media path correctly ?

答:
```<code>location /media  {
     alias /home/user/django_app/media; #(locaion of your media folder)
}
</code>```

Try this code in nginx config to serve static and media files for a django applications (without autoindex on settings)

Body:
I'm new at Nginx, I've successfully bound my django project to Nginx. However I can't serve my static files and I guess I set my media folder's location wrongly. Here is my file tree:

root_directory
     my_django_project
         ...
         manage.py
         app1
         app2
         media
           admin
           css
           js
           ...

And my nginx.conf goes like :

        server {
                listen 192.168.1.9:80;
                server_name localhost;
                # site_media - folder in uri for static files

            location /media/  {
            root /home/nazmi/workspace/portal/media/;
                }

location ~* ^.+\.(jpg|jpeg|gif|png|ico|css|zip|tgz|gz|rar|bz2|doc|xls|exe|pdf|ppt|txt|tar|mid|midi|wav|bmp|rtf|js|mov) {
  access_log   off; # po co mi logi obrazków :)
  expires      30d;
}
                location / {
                        # host and port to fastcgi server
                        fastcgi_pass 127.0.0.1:8080;
            fastcgi_param PATH_INFO $fastcgi_script_name;
                        fastcgi_param REQUEST_METHOD $request_method;
                        fastcgi_param QUERY_STRING $query_string;
                        fastcgi_param CONTENT_TYPE $content_type;
                        fastcgi_param CONTENT_LENGTH $content_length;
            fastcgi_pass_header Authorization;
                        fastcgi_intercept_errors off;
                        }
                access_log      /var/log/nginx/localhost.access_log main;
                error_log       /var/log/nginx/localhost.error_log;
        }
}

When I open my admin page, all css pages give 404 error. Can you tell me that how can I set my media path correctly ?

Body:
location /media  {
     alias /home/user/django_app/media; #(locaion of your media folder)
}

Try this code in nginx config to serve static and media files for a django applications (without autoindex on settings)


问:
React.js/React-Native how to skip Map() iteration if condition is falsy?
I have this simple component in React-Native, My goal is to skip the iteration if the given argument gradeIsMandatory is false, it should only iterate over warranty and price,
How can I achieve this result without affecting performance? I will take any advice thanks

import React, { useCallback } from 'react';
import { View, Text, SafeAreaView, SectionList, StyleSheet, Image, TouchableOpacity, Alert} from 'react-native';

export const ModalHeader: React.FC<{}> = () => {
    const gradeIsMandatory = false

    //code I tried to use
    useEffect(()=>{
        if(!gradeIsMandatory){
            let appendGrade =  { key: 'grade', title: 'Grade' }
            modalTabs.push(appendGrade)
        }
    },[])
    return (
        <View>
            <View>
                <View>
                    {modalTabs.map((tab, i) => (
                        <TouchableOpacity>
                          <Text>{tab.title}</Text>
                        </TouchableOpacity>
                    ))}
                </View>
            </View>
        </View>
    );
}

const modalTabs = [
    { key: 'warranty', title: 'Your Waranty' },
    { key: 'price', title: 'Your price' }
]```

答: You cannot skip a map iteration. You can however just return <Fragment /> if your map condition isn't met.


问:
first search algorithm
I need to use the first search algorithm

Can anyone assist me in regards how I use first search algorithm?

Thanks in advance

答:
What exactly do open and closed mean in this context of this problem?

In Prolog a closed list is a list terminated by the atom [], representing the empty list.

In bracketed list notation that would be a list like this:

```<code>[a,b,c]
</code>```

In formal ./2 notation, that list is represented by this Prolog structure:

```<code>.( a , .( b , .( c , [] ) ) )
</code>```

Whilst the same list as an open list is this:

```<code>[ a , b , c | Some_Unbound_Variable ]
</code>```

or in ./2 notation:

```<code>.( a , .( b , .( c , Some_Unbound_Variable ) ) )
</code>```

I do not believe that that is what you're looking for. Please explain.

Your graph looks to be a directed, cyclic graph, which is to say that edges may be traversed only in one direction (One can travel from A to G, but not from G to A), and that it contains cycles, meaning that starting from one node within the graph and traversing the graph, you will eventually get back to your origin (a cycle). And that leads to endless loops, unless you track the places you've been.

You may represent your graph thus:

```<code>edge( a , f ).
edge( a , g ).
edge( c , a ).
edge( c , d ).
edge( d , c ).
edge( d , f ).
edge( e , c ).
edge( e , d ).
edge( e , g ).
edge( f , e ).
</code>```

And traversing a graph is pretty trivial:

```<code>traverse( Origin, Destination, Path ) :-
  edge(Origin,_),
  traverse( Origin, Destination, [Origin] , Path )
  .

traverse( A, B , Vs , [B|Vs] ) :- % we can get from A to B
  edge(A,B)                       % - if A and B are directly connected.
  .                               % otherwise...
traverse( A, B , Vs , P      ) :- % we can get from A to B
  edge(A,X) ,                     % - if we can get from A to some X
  X \== B   ,                     % - such that X is not B
  \+memberchk(X,Vs) ,             % - and that we have not yet visited X
  traverse(X,B,[X|Vs],P)          % - and see if we can get from X to B
  .                               %
</code>```

Upon success, Path should be unified with the path taken through the graph in reverse order, so using your graph as an example, Path = [G,E,F,A] says that you traveled G <- E <- F <- A.

Title: first search algorithm

Body:
What exactly do open and closed mean in this context of this problem?

In Prolog a closed list is a list terminated by the atom [], representing the empty list.

In bracketed list notation that would be a list like this:

[a,b,c]

In formal ./2 notation, that list is represented by this Prolog structure:

.( a , .( b , .( c , [] ) ) )

Whilst the same list as an open list is this:

[ a , b , c | Some_Unbound_Variable ]

or in ./2 notation:

.( a , .( b , .( c , Some_Unbound_Variable ) ) )

I do not believe that that is what you're looking for. Please explain.

Your graph looks to be a directed, cyclic graph, which is to say that edges may be traversed only in one direction (One can travel from A to G, but not from G to A), and that it contains cycles, meaning that starting from one node within the graph and traversing the graph, you will eventually get back to your origin (a cycle). And that leads to endless loops, unless you track the places you've been.

You may represent your graph thus:

edge( a , f ).
edge( a , g ).
edge( c , a ).
edge( c , d ).
edge( d , c ).
edge( d , f ).
edge( e , c ).
edge( e , d ).
edge( e , g ).
edge( f , e ).

And traversing a graph is pretty trivial:

traverse( Origin, Destination, Path ) :-
  edge(Origin,_),
  traverse( Origin, Destination, [Origin] , Path )
  .

traverse( A, B , Vs , [B|Vs] ) :- % we can get from A to B
  edge(A,B)                       % - if A and B are directly connected.
  .                               % otherwise...
traverse( A, B , Vs , P      ) :- % we can get from A to B
  edge(A,X) ,                     % - if we can get from A to some X
  X \== B   ,                     % - such that X is not B
  \+memberchk(X,Vs) ,             % - and that we have not yet visited X
  traverse(X,B,[X|Vs],P)          % - and see if we can get from X to B
  .                               %

Upon success, Path should be unified with the path taken through the graph in reverse order, so using your graph as an example, Path = [G,E,F,A] says that you traveled G <- E <- F <- A.


问:
How to gather all client weights at server in TFF?
I am trying to implement a custom aggregation using TFF by changing the code from this tutorial . I would like to rewrite next_fn so that all the client weights are placed at the server for further computations. As federated_collect was removed from tff-nightly, I am trying to do that using federated_aggregate.

This is what I have so far:

```<code>def accumulate(x, y):
    x.append(y)
    return x

def merge(x, y):
    x.extend(y)
    return y

@tff.federated_computation(federated_server_type, federated_dataset_type)
def next_fn(server_state, federated_dataset):
    server_weights_at_client = tff.federated_broadcast(
        server_state.trainable_weights)
    client_deltas = tff.federated_map(
        client_update_fn, (federated_dataset, server_weights_at_client))

    z = []
    agg_result = tff.federated_aggregate(client_deltas, z,
                                         accumulate=tff.tf_computation(accumulate),
                                         merge=tff.tf_computation(merge),
                                         report=tff.tf_computation(lambda x: x))

    new_weights = do_smth_with_result(agg_result)
    server_state = tff.federated_map(
        server_update_fn, (server_state, new_weights))
    return server_state
</code>```

However this results in the following Exception:

```<code>  File "/home/yana/Documents/Uni/Thesis/grufedatt_try.py", line 351, in <module>
    def next_fn(server_state, federated_dataset):
  File "/home/yana/anaconda3/envs/fedenv/lib/python3.9/site-packages/tensorflow_federated/python/core/impl/wrappers/computation_wrapper.py", line 494, in __call__
    wrapped_func = self._strategy(
  File "/home/yana/anaconda3/envs/fedenv/lib/python3.9/site-packages/tensorflow_federated/python/core/impl/wrappers/computation_wrapper.py", line 222, in __call__
    result = fn_to_wrap(*args, **kwargs)
  File "/home/yana/Documents/Uni/Thesis/grufedatt_try.py", line 358, in next_fn
    agg_result = tff.federated_aggregate(client_deltas, z,
  File "/home/yana/anaconda3/envs/fedenv/lib/python3.9/site-packages/tensorflow_federated/python/core/impl/federated_context/intrinsics.py", line 140, in federated_aggregate
    raise TypeError(
TypeError: Expected parameter `accumulate` to be of type (<<<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>>,<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>> -> <<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>>), but received (<<>,<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>> -> <<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>>) instead.
</code>```

答:
Try using tff.aggregators.federated_sample with max_num_samples being equal to the number of clients you have.

That should be a simple drop-in replacement for how you would previously use tff.federated_collect.

In your accumulate, the issue is that you are changing number of tensors the accumulator would contain, so you get an error when accumulating more than a single accumuland. If you would want to go this way though, for a rank-1 accumuland with k elements, you could probably do something like the following instead:

@tff.tf_computation(tff.types.TensorType(tf.float32, [None, k]),
                    tff.types.TensorType(tf.float32, [k]))
def accumulate(accumulator, accumuland):
  return tf.concat([accumulator, tf.expand_dims(accumuland, axis=0)], axis=0)
```

Body:
I am trying to implement a custom aggregation using TFF by changing the code from this tutorial . I would like to rewrite next_fn so that all the client weights are placed at the server for further computations. As federated_collect was removed from tff-nightly, I am trying to do that using federated_aggregate.

This is what I have so far:

def accumulate(x, y):
    x.append(y)
    return x

def merge(x, y):
    x.extend(y)
    return y

@tff.federated_computation(federated_server_type, federated_dataset_type)
def next_fn(server_state, federated_dataset):
    server_weights_at_client = tff.federated_broadcast(
        server_state.trainable_weights)
    client_deltas = tff.federated_map(
        client_update_fn, (federated_dataset, server_weights_at_client))

    z = []
    agg_result = tff.federated_aggregate(client_deltas, z,
                                         accumulate=tff.tf_computation(accumulate),
                                         merge=tff.tf_computation(merge),
                                         report=tff.tf_computation(lambda x: x))

    new_weights = do_smth_with_result(agg_result)
    server_state = tff.federated_map(
        server_update_fn, (server_state, new_weights))
    return server_state

However this results in the following Exception:

  File "/home/yana/Documents/Uni/Thesis/grufedatt_try.py", line 351, in <module>
    def next_fn(server_state, federated_dataset):
  File "/home/yana/anaconda3/envs/fedenv/lib/python3.9/site-packages/tensorflow_federated/python/core/impl/wrappers/computation_wrapper.py", line 494, in __call__
    wrapped_func = self._strategy(
  File "/home/yana/anaconda3/envs/fedenv/lib/python3.9/site-packages/tensorflow_federated/python/core/impl/wrappers/computation_wrapper.py", line 222, in __call__
    result = fn_to_wrap(*args, **kwargs)
  File "/home/yana/Documents/Uni/Thesis/grufedatt_try.py", line 358, in next_fn
    agg_result = tff.federated_aggregate(client_deltas, z,
  File "/home/yana/anaconda3/envs/fedenv/lib/python3.9/site-packages/tensorflow_federated/python/core/impl/federated_context/intrinsics.py", line 140, in federated_aggregate
    raise TypeError(
TypeError: Expected parameter `accumulate` to be of type (<<<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>>,<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>> -> <<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>>), but received (<<>,<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>> -> <<float32[9999,96],float32[96,1024],float32[256,1024],float32[1024],float32[256,96],float32[96]>>) instead.


问:
Reading the contents of a zip entry from a zip that is in the form of bytes
I'm calling onto some code that returns me an HTTP response.  I can get the contents of the response which returns me a byte array.  The bytes represent a zip file that I would like to extract and get the contents of a single file (the zip only contains one file).

Currently I have some messy code (I'll need to clean it up if I keep it) that seems to work:

```<code>    byte[] bytes = response.out.toByteArray();
    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
    ZipInputStream zip = new ZipInputStream(input);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    zip.getNextEntry();
    int data;
    while ((data = zip.read()) != -1) output.write(data);
    output.close();
    zip.close();
    input.close();
    byte[] kmlBytes = output.toByteArray();
    String contents = new String(kmlBytes, "UTF-8");
</code>```

but was wondering whether there was a cleaner way to do the same thing because the above looks incredibly ugly.

答: In order to avoid "reinventing the wheel" and reduce clutter and to focus on your app's business logic rather than low-level code like this, you can use Apache Commons Compress.</p>

Body:
I'm calling onto some code that returns me an HTTP response.  I can get the contents of the response which returns me a byte array.  The bytes represent a zip file that I would like to extract and get the contents of a single file (the zip only contains one file).

Currently I have some messy code (I'll need to clean it up if I keep it) that seems to work:

    byte[] bytes = response.out.toByteArray();
    ByteArrayInputStream input = new ByteArrayInputStream(bytes);
    ZipInputStream zip = new ZipInputStream(input);
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    zip.getNextEntry();
    int data;
    while ((data = zip.read()) != -1) output.write(data);
    output.close();
    zip.close();
    input.close();
    byte[] kmlBytes = output.toByteArray();
    String contents = new String(kmlBytes, "UTF-8");

but was wondering whether there was a cleaner way to do the same thing because the above looks incredibly ugly.


问:
AttributeError scikit learn pipeline based class
I am trying to write a sklearn based feature extraction pipeline. My pipeline code idea could be splitted in few parts

A parent class where all data preprocessing (if required) could happen

```<code>from sklearn.base import BaseEstimator, TransformerMixin

class FeatureExtractor(BaseEstimator, TransformerMixin):
    """This is the parent class for all feature extractors."""
    def __init__(self, raw_data = {}):
        self.raw_data = raw_data

    def fit(self, X, y=None):
        return self
</code>```

A decorator which helps one define the execution of feature extraction, for intelligently handling the case where one feature is dependent on another feature.

```<code># A decorator to assign order of feature extraction within fearure extractor classes
def feature_order(order):
   def order_assignment(to_func):
       to_func.order = order
       return to_func
   return order_assignment
</code>```

Finally one of the child class where all feature extraction is happening:

```<code>class ChilldFeatureExtractor1(FeatureExtractor):
   """This is the one of the child feature extractor class."""

   def __init__(self, raw_data = {}):
       super().__init__(raw_data)
       self.raw_data = raw_data

   @feature_order(1)
   def foo_plus_one(self):
       return self.raw_data['foo'] + 1

   # This feature extractor depends on value populated in previous feature extractor
   @feature_order(2)
   def foo_plus_one_plus_one(self):
       return self.raw_data['foo_plus_one'] + 1

   def transform(self):
       functions = sorted(
           #get a list of extractor functions with attribute order
           [
           getattr(self, field) for field in dir(self)
           if hasattr(getattr(self, field), "order")
           ],
           #sort the feature extractor functions by their order
           key = (lambda field: field.order)
           )

       for func in functions:
           feature_name = func.__name__
           feature_value = func()
           self.raw_data[feature_name] = feature_value

       return self.raw_data
</code>```

Testing this code a small input:

```<code>if __name__ == '__main__':
    raw_data = {'foo': 1, 'bar': 2}
    fe = ChilldFeatureExtractor1(raw_data)
    print(fe.transform())
</code>```

Gives error:

```<code>Traceback (most recent call last):
  File "/Users/temporaryadmin/deleteme.py", line 55, in <module>
    print(fe.transform())
  File "/Users/temporaryadmin/deleteme.py", line 37, in transform
    [
  File "/Users/temporaryadmin/deleteme.py", line 39, in <listcomp>
    if hasattr(getattr(self, field), "order")
  File "/Users/temporaryadmin/opt/miniconda3/envs/voutopia/lib/python3.8/site-packages/sklearn/base.py", line 450, in _repr_html_
    raise AttributeError("_repr_html_ is only defined when the "
AttributeError: _repr_html_ is only defined when the 'display' configuration option is set to 'diagram'
</code>```

However when I don't inherit sklearn classes in base class ie. class FeatureExtractor(): then I get proper output:

```<code>{'foo': 1, 'bar': 2, 'foo_plus_one': 2, 'foo_plus_one_plus_one': 3}
</code>```

Any pointer on this?

答:
The error traceback indicates where this goes wrong: self has an attribute _repr_html_ listed in its __dir__, but trying to access it with getattr throws that ValueError, as shown in the source link from @maxskoryk's answer.

One fix is to give a default value in the getattr call:

   def transform(self):
       functions = sorted(
           #get a list of extractor functions with attribute order
           [
               getattr(self, field, None) for field in dir(self)
               if hasattr(getattr(self, field, None), "order")
           ],
           #sort the feature extractor functions by their order
           key = (lambda field: field.order),
       )
       ...
```

You could also just limit to attributes not starting with an underscore, or any other reasonable way to limit which attributes get checked.

Body:
I am trying to write a sklearn based feature extraction pipeline. My pipeline code idea could be splitted in few parts

A parent class where all data preprocessing (if required) could happen

from sklearn.base import BaseEstimator, TransformerMixin

class FeatureExtractor(BaseEstimator, TransformerMixin):
    """This is the parent class for all feature extractors."""
    def __init__(self, raw_data = {}):
        self.raw_data = raw_data

    def fit(self, X, y=None):
        return self

A decorator which helps one define the execution of feature extraction, for intelligently handling the case where one feature is dependent on another feature.

# A decorator to assign order of feature extraction within fearure extractor classes
def feature_order(order):
   def order_assignment(to_func):
       to_func.order = order
       return to_func
   return order_assignment

Finally one of the child class where all feature extraction is happening:

class ChilldFeatureExtractor1(FeatureExtractor):
   """This is the one of the child feature extractor class."""

   def __init__(self, raw_data = {}):
       super().__init__(raw_data)
       self.raw_data = raw_data

   @feature_order(1)
   def foo_plus_one(self):
       return self.raw_data['foo'] + 1

   # This feature extractor depends on value populated in previous feature extractor
   @feature_order(2)
   def foo_plus_one_plus_one(self):
       return self.raw_data['foo_plus_one'] + 1

   def transform(self):
       functions = sorted(
           #get a list of extractor functions with attribute order
           [
           getattr(self, field) for field in dir(self)
           if hasattr(getattr(self, field), "order")
           ],
           #sort the feature extractor functions by their order
           key = (lambda field: field.order)
           )

       for func in functions:
           feature_name = func.__name__
           feature_value = func()
           self.raw_data[feature_name] = feature_value

       return self.raw_data

Testing this code a small input:

if __name__ == '__main__':
    raw_data = {'foo': 1, 'bar': 2}
    fe = ChilldFeatureExtractor1(raw_data)
    print(fe.transform())

Gives error:

Traceback (most recent call last):
  File "/Users/temporaryadmin/deleteme.py", line 55, in <module>
    print(fe.transform())
  File "/Users/temporaryadmin/deleteme.py", line 37, in transform
    [
  File "/Users/temporaryadmin/deleteme.py", line 39, in <listcomp>
    if hasattr(getattr(self, field), "order")
  File "/Users/temporaryadmin/opt/miniconda3/envs/voutopia/lib/python3.8/site-packages/sklearn/base.py", line 450, in _repr_html_
    raise AttributeError("_repr_html_ is only defined when the "
AttributeError: _repr_html_ is only defined when the 'display' configuration option is set to 'diagram'

However when I don't inherit sklearn classes in base class ie. class FeatureExtractor(): then I get proper output:

{'foo': 1, 'bar': 2, 'foo_plus_one': 2, 'foo_plus_one_plus_one': 3}

Any pointer on this?

Body:
The error traceback indicates where this goes wrong: self has an attribute _repr_html_ listed in its __dir__, but trying to access it with getattr throws that ValueError, as shown in the source link from @maxskoryk's answer.

One fix is to give a default value in the getattr call:

   def transform(self):
       functions = sorted(
           #get a list of extractor functions with attribute order
           [
               getattr(self, field, None) for field in dir(self)
               if hasattr(getattr(self, field, None), "order")
           ],
           #sort the feature extractor functions by their order
           key = (lambda field: field.order),
       )
       ...

You could also just limit to attributes not starting with an underscore, or any other reasonable way to limit which attributes get checked.


问:
Changing WCF binding from wsHttp to netTcp
I have problems with a WCF Service WsHttpBinding that I want to change to a NetTcpBinding.
Previously, I have set up the Service in my IIS7 local machine and it works with the WsHttpBinding.

The Proxy for this Service has a CustomBehavior which adds two message headers before sending the request message

When I change the binding to a NetTcpBinding I get the following Exception in my logs..

```<code> Exception: System.ServiceModel.ServiceActivationException: Service /ConsignmentService/Consignment.svc cannot be activated due to an exception during compilation. The exception message is: Exception has been thrown by the target of an invocation ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ServiceModel.MessageHeaderException: There is not a header with the name "ClientID" og namespace 'http://AmphoraExtension/Header' in the message.
   ved System.ServiceModel.Channels.MessageHeaders.GetHeader[T](String name, String ns, XmlObjectSerializer serializer)
   ved System.ServiceModel.Channels.MessageHeaders.GetHeader[T](String name, String ns)
</code>```

This works fine with the wsHttpBinding, but when switching to NetTcpBinding it doesn't.
What am I missing here?

答:
Solved it myself.

This was my bad. A request was made to the WCF server BEFORE the actual request with parameters and Header, which forced the Service class to be instantiated. And in the constructor there was logic around the header data that was supposed to be there. I made a workaround for this

Body:
I have problems with a WCF Service WsHttpBinding that I want to change to a NetTcpBinding.
Previously, I have set up the Service in my IIS7 local machine and it works with the WsHttpBinding.

The Proxy for this Service has a CustomBehavior which adds two message headers before sending the request message

When I change the binding to a NetTcpBinding I get the following Exception in my logs..

 Exception: System.ServiceModel.ServiceActivationException: Service /ConsignmentService/Consignment.svc cannot be activated due to an exception during compilation. The exception message is: Exception has been thrown by the target of an invocation ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ServiceModel.MessageHeaderException: There is not a header with the name "ClientID" og namespace 'http://AmphoraExtension/Header' in the message.
   ved System.ServiceModel.Channels.MessageHeaders.GetHeader[T](String name, String ns, XmlObjectSerializer serializer)
   ved System.ServiceModel.Channels.MessageHeaders.GetHeader[T](String name, String ns)

This works fine with the wsHttpBinding, but when switching to NetTcpBinding it doesn't.
What am I missing here?


问:
how to loop to expect a list of item in jest
I have added the below jest unit test to render a component and I am expecting some of its elements using "getAllByText" as there are multiple similar elements. I got a review comment to loop over the list of element if there are more than 1 and expect each of them to be visible. Can someone please help me in modifying the test to loop over all the elements.

```<code>it('should render seat total wrapper on small breakpoint', () => {
    render(
      <MockViewportProvider viewSize={ViewSizes.SMALL}>
        <SeatMapContext.Provider value={{ state: contextObj, dispatch: noop }}>
          <SeatMapCabinAndSeatWrapper
            flightSeatMapPlaneData={seatMapPlanesData}
            flightLegsDetails={FlightLegsDetails}
            onChangeLegIndex={jest.fn}
            selectedLegIndex={0}
            handleLegendButtonClick={jest.fn()}
            handleApplySeatSelection={handleApplySeatSelection}
          />
        </SeatMapContext.Provider>
      </MockViewportProvider>
    );
    expect(screen.getByRole('button', { name: 'Next Flight' })).toBeVisible();
    expect(screen.getAllByText('$276.24')[0]).toBeVisible();
  });
</code>```

Review comments -> "if there are expected to be more than 1 item then please loop over the list and expect each element to be visible
if there should only be 1 item then please determine how to use getByText".

答:
Just use a for loop.

```<code>for (const element of screen.getAllByText('$276.24')) {
    expect(element).toBeVisible();
}
</code>```

For an implementation with no for..of loop:

```<code>const list = screen.getAllByText('$276.24');
for (let i = 0; i < list.length; i++) {
    expect(list[i]).toBeVisible();
}
</code>```

Or:

```<code>screen.getAllByText('$276.24').forEach((element) => {
    expect(element).toBeVisible();
});
</code>```

Body:
I have added the below jest unit test to render a component and I am expecting some of its elements using "getAllByText" as there are multiple similar elements. I got a review comment to loop over the list of element if there are more than 1 and expect each of them to be visible. Can someone please help me in modifying the test to loop over all the elements.

it('should render seat total wrapper on small breakpoint', () => {
    render(
      <MockViewportProvider viewSize={ViewSizes.SMALL}>
        <SeatMapContext.Provider value={{ state: contextObj, dispatch: noop }}>
          <SeatMapCabinAndSeatWrapper
            flightSeatMapPlaneData={seatMapPlanesData}
            flightLegsDetails={FlightLegsDetails}
            onChangeLegIndex={jest.fn}
            selectedLegIndex={0}
            handleLegendButtonClick={jest.fn()}
            handleApplySeatSelection={handleApplySeatSelection}
          />
        </SeatMapContext.Provider>
      </MockViewportProvider>
    );
    expect(screen.getByRole('button', { name: 'Next Flight' })).toBeVisible();
    expect(screen.getAllByText('$276.24')[0]).toBeVisible();
  });

Review comments -> "if there are expected to be more than 1 item then please loop over the list and expect each element to be visible
if there should only be 1 item then please determine how to use getByText".

Body:
Just use a for loop.

for (const element of screen.getAllByText('$276.24')) {
    expect(element).toBeVisible();
}

For an implementation with no for..of loop:

const list = screen.getAllByText('$276.24');
for (let i = 0; i < list.length; i++) {
    expect(list[i]).toBeVisible();
}

Or:

screen.getAllByText('$276.24').forEach((element) => {
    expect(element).toBeVisible();
});