Internal change
PiperOrigin-RevId: 512111461
This commit is contained in:
		
							parent
							
								
									9054ff7283
								
							
						
					
					
						commit
						17466fb7f1
					
				| 
						 | 
					@ -257,19 +257,28 @@ class HandDetectorGraph : public core::ModelTaskGraph {
 | 
				
			||||||
    preprocessed_tensors >> inference.In("TENSORS");
 | 
					    preprocessed_tensors >> inference.In("TENSORS");
 | 
				
			||||||
    auto model_output_tensors = inference.Out("TENSORS");
 | 
					    auto model_output_tensors = inference.Out("TENSORS");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: support hand detection metadata.
 | 
				
			||||||
 | 
					    bool has_metadata = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Generates a single side packet containing a vector of SSD anchors.
 | 
					    // Generates a single side packet containing a vector of SSD anchors.
 | 
				
			||||||
    auto& ssd_anchor = graph.AddNode("SsdAnchorsCalculator");
 | 
					    auto& ssd_anchor = graph.AddNode("SsdAnchorsCalculator");
 | 
				
			||||||
    ConfigureSsdAnchorsCalculator(
 | 
					    auto& ssd_anchor_options =
 | 
				
			||||||
        &ssd_anchor.GetOptions<mediapipe::SsdAnchorsCalculatorOptions>());
 | 
					        ssd_anchor.GetOptions<mediapipe::SsdAnchorsCalculatorOptions>();
 | 
				
			||||||
 | 
					    if (!has_metadata) {
 | 
				
			||||||
 | 
					      ConfigureSsdAnchorsCalculator(&ssd_anchor_options);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    auto anchors = ssd_anchor.SideOut("");
 | 
					    auto anchors = ssd_anchor.SideOut("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Converts output tensors to Detections.
 | 
					    // Converts output tensors to Detections.
 | 
				
			||||||
    auto& tensors_to_detections =
 | 
					    auto& tensors_to_detections =
 | 
				
			||||||
        graph.AddNode("TensorsToDetectionsCalculator");
 | 
					        graph.AddNode("TensorsToDetectionsCalculator");
 | 
				
			||||||
 | 
					    if (!has_metadata) {
 | 
				
			||||||
      ConfigureTensorsToDetectionsCalculator(
 | 
					      ConfigureTensorsToDetectionsCalculator(
 | 
				
			||||||
          subgraph_options,
 | 
					          subgraph_options,
 | 
				
			||||||
          &tensors_to_detections
 | 
					          &tensors_to_detections
 | 
				
			||||||
               .GetOptions<mediapipe::TensorsToDetectionsCalculatorOptions>());
 | 
					               .GetOptions<mediapipe::TensorsToDetectionsCalculatorOptions>());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    model_output_tensors >> tensors_to_detections.In("TENSORS");
 | 
					    model_output_tensors >> tensors_to_detections.In("TENSORS");
 | 
				
			||||||
    anchors >> tensors_to_detections.SideIn("ANCHORS");
 | 
					    anchors >> tensors_to_detections.SideIn("ANCHORS");
 | 
				
			||||||
    auto detections = tensors_to_detections.Out("DETECTIONS");
 | 
					    auto detections = tensors_to_detections.Out("DETECTIONS");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,6 +148,7 @@ cc_library(
 | 
				
			||||||
        "//mediapipe/tasks/cc/vision/hand_landmarker/calculators:hand_landmarks_deduplication_calculator",
 | 
					        "//mediapipe/tasks/cc/vision/hand_landmarker/calculators:hand_landmarks_deduplication_calculator",
 | 
				
			||||||
        "//mediapipe/tasks/cc/vision/hand_landmarker/proto:hand_landmarker_graph_options_cc_proto",
 | 
					        "//mediapipe/tasks/cc/vision/hand_landmarker/proto:hand_landmarker_graph_options_cc_proto",
 | 
				
			||||||
        "//mediapipe/tasks/cc/vision/hand_landmarker/proto:hand_landmarks_detector_graph_options_cc_proto",
 | 
					        "//mediapipe/tasks/cc/vision/hand_landmarker/proto:hand_landmarks_detector_graph_options_cc_proto",
 | 
				
			||||||
 | 
					        "//mediapipe/util:graph_builder_utils",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    alwayslink = 1,
 | 
					    alwayslink = 1,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@ limitations under the License.
 | 
				
			||||||
==============================================================================*/
 | 
					==============================================================================*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <memory>
 | 
					#include <memory>
 | 
				
			||||||
 | 
					#include <optional>
 | 
				
			||||||
#include <type_traits>
 | 
					#include <type_traits>
 | 
				
			||||||
#include <utility>
 | 
					#include <utility>
 | 
				
			||||||
#include <vector>
 | 
					#include <vector>
 | 
				
			||||||
| 
						 | 
					@ -41,6 +42,7 @@ limitations under the License.
 | 
				
			||||||
#include "mediapipe/tasks/cc/vision/hand_landmarker/calculators/hand_association_calculator.pb.h"
 | 
					#include "mediapipe/tasks/cc/vision/hand_landmarker/calculators/hand_association_calculator.pb.h"
 | 
				
			||||||
#include "mediapipe/tasks/cc/vision/hand_landmarker/proto/hand_landmarker_graph_options.pb.h"
 | 
					#include "mediapipe/tasks/cc/vision/hand_landmarker/proto/hand_landmarker_graph_options.pb.h"
 | 
				
			||||||
#include "mediapipe/tasks/cc/vision/hand_landmarker/proto/hand_landmarks_detector_graph_options.pb.h"
 | 
					#include "mediapipe/tasks/cc/vision/hand_landmarker/proto/hand_landmarks_detector_graph_options.pb.h"
 | 
				
			||||||
 | 
					#include "mediapipe/util/graph_builder_utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace mediapipe {
 | 
					namespace mediapipe {
 | 
				
			||||||
namespace tasks {
 | 
					namespace tasks {
 | 
				
			||||||
| 
						 | 
					@ -53,7 +55,7 @@ using ::mediapipe::NormalizedRect;
 | 
				
			||||||
using ::mediapipe::api2::Input;
 | 
					using ::mediapipe::api2::Input;
 | 
				
			||||||
using ::mediapipe::api2::Output;
 | 
					using ::mediapipe::api2::Output;
 | 
				
			||||||
using ::mediapipe::api2::builder::Graph;
 | 
					using ::mediapipe::api2::builder::Graph;
 | 
				
			||||||
using ::mediapipe::api2::builder::Source;
 | 
					using ::mediapipe::api2::builder::Stream;
 | 
				
			||||||
using ::mediapipe::tasks::components::utils::DisallowIf;
 | 
					using ::mediapipe::tasks::components::utils::DisallowIf;
 | 
				
			||||||
using ::mediapipe::tasks::core::ModelAssetBundleResources;
 | 
					using ::mediapipe::tasks::core::ModelAssetBundleResources;
 | 
				
			||||||
using ::mediapipe::tasks::metadata::SetExternalFile;
 | 
					using ::mediapipe::tasks::metadata::SetExternalFile;
 | 
				
			||||||
| 
						 | 
					@ -78,40 +80,46 @@ constexpr char kHandLandmarksDetectorTFLiteName[] =
 | 
				
			||||||
    "hand_landmarks_detector.tflite";
 | 
					    "hand_landmarks_detector.tflite";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct HandLandmarkerOutputs {
 | 
					struct HandLandmarkerOutputs {
 | 
				
			||||||
  Source<std::vector<NormalizedLandmarkList>> landmark_lists;
 | 
					  Stream<std::vector<NormalizedLandmarkList>> landmark_lists;
 | 
				
			||||||
  Source<std::vector<LandmarkList>> world_landmark_lists;
 | 
					  Stream<std::vector<LandmarkList>> world_landmark_lists;
 | 
				
			||||||
  Source<std::vector<NormalizedRect>> hand_rects_next_frame;
 | 
					  Stream<std::vector<NormalizedRect>> hand_rects_next_frame;
 | 
				
			||||||
  Source<std::vector<ClassificationList>> handednesses;
 | 
					  Stream<std::vector<ClassificationList>> handednesses;
 | 
				
			||||||
  Source<std::vector<NormalizedRect>> palm_rects;
 | 
					  Stream<std::vector<NormalizedRect>> palm_rects;
 | 
				
			||||||
  Source<std::vector<Detection>> palm_detections;
 | 
					  Stream<std::vector<Detection>> palm_detections;
 | 
				
			||||||
  Source<Image> image;
 | 
					  Stream<Image> image;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Sets the base options in the sub tasks.
 | 
					// Sets the base options in the sub tasks.
 | 
				
			||||||
absl::Status SetSubTaskBaseOptions(const ModelAssetBundleResources& resources,
 | 
					absl::Status SetSubTaskBaseOptions(const ModelAssetBundleResources& resources,
 | 
				
			||||||
                                   HandLandmarkerGraphOptions* options,
 | 
					                                   HandLandmarkerGraphOptions* options,
 | 
				
			||||||
                                   bool is_copy) {
 | 
					                                   bool is_copy) {
 | 
				
			||||||
  ASSIGN_OR_RETURN(const auto hand_detector_file,
 | 
					 | 
				
			||||||
                   resources.GetModelFile(kHandDetectorTFLiteName));
 | 
					 | 
				
			||||||
  auto* hand_detector_graph_options =
 | 
					  auto* hand_detector_graph_options =
 | 
				
			||||||
      options->mutable_hand_detector_graph_options();
 | 
					      options->mutable_hand_detector_graph_options();
 | 
				
			||||||
 | 
					  if (!hand_detector_graph_options->base_options().has_model_asset()) {
 | 
				
			||||||
 | 
					    ASSIGN_OR_RETURN(const auto hand_detector_file,
 | 
				
			||||||
 | 
					                     resources.GetModelFile(kHandDetectorTFLiteName));
 | 
				
			||||||
    SetExternalFile(hand_detector_file,
 | 
					    SetExternalFile(hand_detector_file,
 | 
				
			||||||
                    hand_detector_graph_options->mutable_base_options()
 | 
					                    hand_detector_graph_options->mutable_base_options()
 | 
				
			||||||
                        ->mutable_model_asset(),
 | 
					                        ->mutable_model_asset(),
 | 
				
			||||||
                    is_copy);
 | 
					                    is_copy);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  hand_detector_graph_options->mutable_base_options()
 | 
					  hand_detector_graph_options->mutable_base_options()
 | 
				
			||||||
      ->mutable_acceleration()
 | 
					      ->mutable_acceleration()
 | 
				
			||||||
      ->CopyFrom(options->base_options().acceleration());
 | 
					      ->CopyFrom(options->base_options().acceleration());
 | 
				
			||||||
  hand_detector_graph_options->mutable_base_options()->set_use_stream_mode(
 | 
					  hand_detector_graph_options->mutable_base_options()->set_use_stream_mode(
 | 
				
			||||||
      options->base_options().use_stream_mode());
 | 
					      options->base_options().use_stream_mode());
 | 
				
			||||||
  ASSIGN_OR_RETURN(const auto hand_landmarks_detector_file,
 | 
					 | 
				
			||||||
                   resources.GetModelFile(kHandLandmarksDetectorTFLiteName));
 | 
					 | 
				
			||||||
  auto* hand_landmarks_detector_graph_options =
 | 
					  auto* hand_landmarks_detector_graph_options =
 | 
				
			||||||
      options->mutable_hand_landmarks_detector_graph_options();
 | 
					      options->mutable_hand_landmarks_detector_graph_options();
 | 
				
			||||||
  SetExternalFile(hand_landmarks_detector_file,
 | 
					  if (!hand_landmarks_detector_graph_options->base_options()
 | 
				
			||||||
 | 
					           .has_model_asset()) {
 | 
				
			||||||
 | 
					    ASSIGN_OR_RETURN(const auto hand_landmarks_detector_file,
 | 
				
			||||||
 | 
					                     resources.GetModelFile(kHandLandmarksDetectorTFLiteName));
 | 
				
			||||||
 | 
					    SetExternalFile(
 | 
				
			||||||
 | 
					        hand_landmarks_detector_file,
 | 
				
			||||||
        hand_landmarks_detector_graph_options->mutable_base_options()
 | 
					        hand_landmarks_detector_graph_options->mutable_base_options()
 | 
				
			||||||
            ->mutable_model_asset(),
 | 
					            ->mutable_model_asset(),
 | 
				
			||||||
        is_copy);
 | 
					        is_copy);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  hand_landmarks_detector_graph_options->mutable_base_options()
 | 
					  hand_landmarks_detector_graph_options->mutable_base_options()
 | 
				
			||||||
      ->mutable_acceleration()
 | 
					      ->mutable_acceleration()
 | 
				
			||||||
      ->CopyFrom(options->base_options().acceleration());
 | 
					      ->CopyFrom(options->base_options().acceleration());
 | 
				
			||||||
| 
						 | 
					@ -119,7 +127,6 @@ absl::Status SetSubTaskBaseOptions(const ModelAssetBundleResources& resources,
 | 
				
			||||||
      ->set_use_stream_mode(options->base_options().use_stream_mode());
 | 
					      ->set_use_stream_mode(options->base_options().use_stream_mode());
 | 
				
			||||||
  return absl::OkStatus();
 | 
					  return absl::OkStatus();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}  // namespace
 | 
					}  // namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A "mediapipe.tasks.vision.hand_landmarker.HandLandmarkerGraph" performs hand
 | 
					// A "mediapipe.tasks.vision.hand_landmarker.HandLandmarkerGraph" performs hand
 | 
				
			||||||
| 
						 | 
					@ -219,12 +226,15 @@ class HandLandmarkerGraph : public core::ModelTaskGraph {
 | 
				
			||||||
          !sc->Service(::mediapipe::tasks::core::kModelResourcesCacheService)
 | 
					          !sc->Service(::mediapipe::tasks::core::kModelResourcesCacheService)
 | 
				
			||||||
               .IsAvailable()));
 | 
					               .IsAvailable()));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    Stream<Image> image_in = graph.In(kImageTag).Cast<Image>();
 | 
				
			||||||
 | 
					    std::optional<Stream<NormalizedRect>> norm_rect_in;
 | 
				
			||||||
 | 
					    if (HasInput(sc->OriginalNode(), kNormRectTag)) {
 | 
				
			||||||
 | 
					      norm_rect_in = graph.In(kNormRectTag).Cast<NormalizedRect>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    ASSIGN_OR_RETURN(
 | 
					    ASSIGN_OR_RETURN(
 | 
				
			||||||
        auto hand_landmarker_outputs,
 | 
					        auto hand_landmarker_outputs,
 | 
				
			||||||
        BuildHandLandmarkerGraph(
 | 
					        BuildHandLandmarkerGraph(sc->Options<HandLandmarkerGraphOptions>(),
 | 
				
			||||||
            sc->Options<HandLandmarkerGraphOptions>(),
 | 
					                                 image_in, norm_rect_in, graph));
 | 
				
			||||||
            graph[Input<Image>(kImageTag)],
 | 
					 | 
				
			||||||
            graph[Input<NormalizedRect>::Optional(kNormRectTag)], graph));
 | 
					 | 
				
			||||||
    hand_landmarker_outputs.landmark_lists >>
 | 
					    hand_landmarker_outputs.landmark_lists >>
 | 
				
			||||||
        graph[Output<std::vector<NormalizedLandmarkList>>(kLandmarksTag)];
 | 
					        graph[Output<std::vector<NormalizedLandmarkList>>(kLandmarksTag)];
 | 
				
			||||||
    hand_landmarker_outputs.world_landmark_lists >>
 | 
					    hand_landmarker_outputs.world_landmark_lists >>
 | 
				
			||||||
| 
						 | 
					@ -262,8 +272,8 @@ class HandLandmarkerGraph : public core::ModelTaskGraph {
 | 
				
			||||||
  // image_in: (mediapipe::Image) stream to run hand landmark detection on.
 | 
					  // image_in: (mediapipe::Image) stream to run hand landmark detection on.
 | 
				
			||||||
  // graph: the mediapipe graph instance to be updated.
 | 
					  // graph: the mediapipe graph instance to be updated.
 | 
				
			||||||
  absl::StatusOr<HandLandmarkerOutputs> BuildHandLandmarkerGraph(
 | 
					  absl::StatusOr<HandLandmarkerOutputs> BuildHandLandmarkerGraph(
 | 
				
			||||||
      const HandLandmarkerGraphOptions& tasks_options, Source<Image> image_in,
 | 
					      const HandLandmarkerGraphOptions& tasks_options, Stream<Image> image_in,
 | 
				
			||||||
      Source<NormalizedRect> norm_rect_in, Graph& graph) {
 | 
					      std::optional<Stream<NormalizedRect>> norm_rect_in, Graph& graph) {
 | 
				
			||||||
    const int max_num_hands =
 | 
					    const int max_num_hands =
 | 
				
			||||||
        tasks_options.hand_detector_graph_options().num_hands();
 | 
					        tasks_options.hand_detector_graph_options().num_hands();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -293,10 +303,15 @@ class HandLandmarkerGraph : public core::ModelTaskGraph {
 | 
				
			||||||
      // track the hands from the last frame.
 | 
					      // track the hands from the last frame.
 | 
				
			||||||
      auto image_for_hand_detector =
 | 
					      auto image_for_hand_detector =
 | 
				
			||||||
          DisallowIf(image_in, has_enough_hands, graph);
 | 
					          DisallowIf(image_in, has_enough_hands, graph);
 | 
				
			||||||
      auto norm_rect_in_for_hand_detector =
 | 
					      std::optional<Stream<NormalizedRect>> norm_rect_in_for_hand_detector;
 | 
				
			||||||
          DisallowIf(norm_rect_in, has_enough_hands, graph);
 | 
					      if (norm_rect_in) {
 | 
				
			||||||
 | 
					        norm_rect_in_for_hand_detector =
 | 
				
			||||||
 | 
					            DisallowIf(norm_rect_in.value(), has_enough_hands, graph);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      image_for_hand_detector >> hand_detector.In("IMAGE");
 | 
					      image_for_hand_detector >> hand_detector.In("IMAGE");
 | 
				
			||||||
      norm_rect_in_for_hand_detector >> hand_detector.In("NORM_RECT");
 | 
					      if (norm_rect_in_for_hand_detector) {
 | 
				
			||||||
 | 
					        norm_rect_in_for_hand_detector.value() >> hand_detector.In("NORM_RECT");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      auto hand_rects_from_hand_detector = hand_detector.Out("HAND_RECTS");
 | 
					      auto hand_rects_from_hand_detector = hand_detector.Out("HAND_RECTS");
 | 
				
			||||||
      auto& hand_association = graph.AddNode("HandAssociationCalculator");
 | 
					      auto& hand_association = graph.AddNode("HandAssociationCalculator");
 | 
				
			||||||
      hand_association.GetOptions<HandAssociationCalculatorOptions>()
 | 
					      hand_association.GetOptions<HandAssociationCalculatorOptions>()
 | 
				
			||||||
| 
						 | 
					@ -313,7 +328,9 @@ class HandLandmarkerGraph : public core::ModelTaskGraph {
 | 
				
			||||||
      // series, and we don't want to enable the tracking and hand associations
 | 
					      // series, and we don't want to enable the tracking and hand associations
 | 
				
			||||||
      // between input images. Always use the hand detector graph.
 | 
					      // between input images. Always use the hand detector graph.
 | 
				
			||||||
      image_in >> hand_detector.In("IMAGE");
 | 
					      image_in >> hand_detector.In("IMAGE");
 | 
				
			||||||
      norm_rect_in >> hand_detector.In("NORM_RECT");
 | 
					      if (norm_rect_in) {
 | 
				
			||||||
 | 
					        norm_rect_in.value() >> hand_detector.In("NORM_RECT");
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      auto hand_rects_from_hand_detector = hand_detector.Out("HAND_RECTS");
 | 
					      auto hand_rects_from_hand_detector = hand_detector.Out("HAND_RECTS");
 | 
				
			||||||
      hand_rects_from_hand_detector >> clip_hand_rects.In("");
 | 
					      hand_rects_from_hand_detector >> clip_hand_rects.In("");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								mediapipe/tasks/testdata/vision/hand_landmarker.task
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								mediapipe/tasks/testdata/vision/hand_landmarker.task
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										8
									
								
								third_party/external_files.bzl
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								third_party/external_files.bzl
									
									
									
									
										vendored
									
									
								
							| 
						 | 
					@ -306,8 +306,8 @@ def external_files():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http_file(
 | 
					    http_file(
 | 
				
			||||||
        name = "com_google_mediapipe_gesture_recognizer_task",
 | 
					        name = "com_google_mediapipe_gesture_recognizer_task",
 | 
				
			||||||
        sha256 = "a966b1d4e774e0423c19c8aa71f070e5a72fe7a03c2663dd2f3cb0b0095ee3e1",
 | 
					        sha256 = "d48562f535fd4ecd3cfea739d9663dd818eeaf6a8afb1b5e6f8f4747661f73d9",
 | 
				
			||||||
        urls = ["https://storage.googleapis.com/mediapipe-assets/gesture_recognizer.task?generation=1668100501451433"],
 | 
					        urls = ["https://storage.googleapis.com/mediapipe-assets/gesture_recognizer.task?generation=1677051715043311"],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http_file(
 | 
					    http_file(
 | 
				
			||||||
| 
						 | 
					@ -342,8 +342,8 @@ def external_files():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http_file(
 | 
					    http_file(
 | 
				
			||||||
        name = "com_google_mediapipe_hand_landmarker_task",
 | 
					        name = "com_google_mediapipe_hand_landmarker_task",
 | 
				
			||||||
        sha256 = "2ed44f10872e87a5834b9b1130fb9ada30e107af2c6fcc4562ad788aca4e7bc4",
 | 
					        sha256 = "32d1eab97e80a9a20edb29231e15301ce65abfd0fa9d41cf1757e0ecc8078a4e",
 | 
				
			||||||
        urls = ["https://storage.googleapis.com/mediapipe-assets/hand_landmarker.task?generation=1666153732577904"],
 | 
					        urls = ["https://storage.googleapis.com/mediapipe-assets/hand_landmarker.task?generation=1677051718270846"],
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    http_file(
 | 
					    http_file(
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user