<commit_before>/**
 * Copyright 2018-present Facebook.
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 * @format
 */

import type {
  ImageId,
  ImageData,
  ImagesList,
  ImagesListResponse,
  ImageEvent,
  FrescoDebugOverlayEvent,
  AndroidCloseableReferenceLeakEvent,
  CacheInfo,
} from './api.js';
import type {ImagesMap} from './ImagePool.js';
import type {MetricType, MiddlewareAPI} from 'flipper';
import React from 'react';
import ImagesCacheOverview from './ImagesCacheOverview.js';
import {
  FlipperPlugin,
  FlexRow,
  Text,
  DetailSidebar,
  colors,
  styled,
  isProduction,
} from 'flipper';
import ImagesSidebar from './ImagesSidebar.js';
import ImagePool from './ImagePool.js';

export type ImageEventWithId = ImageEvent & {eventId: number};

type PersistedState = {
  surfaceList: Set<string>,
  images: ImagesList,
  events: Array<ImageEventWithId>,
  imagesMap: ImagesMap,
};

type PluginState = {
  selectedSurface: string,
  selectedImage: ?ImageId,
  isDebugOverlayEnabled: boolean,
  isAutoRefreshEnabled: boolean,
  images: ImagesList,
  coldStartFilter: boolean,
};

const EmptySidebar = styled(FlexRow)({
  alignItems: 'center',
  justifyContent: 'center',
  color: colors.light30,
  padding: 15,
  fontSize: 16,
});

const surfaceDefaultText = 'SELECT ALL SURFACES';

const debugLog = (...args) => {
  if (!isProduction()) {
    // eslint-disable-next-line no-console
    console.log(...args);
  }
};

type ImagesMetaData = {|
  levels: ImagesListResponse,
  events: Array<ImageEventWithId>,
  imageDataList: Array<ImageData>,
|};

export default class extends FlipperPlugin<PluginState, *, PersistedState> {
  static defaultPersistedState: PersistedState = {
    images: [],
    events: [],
    imagesMap: {},
    surfaceList: new Set(),
  };

  static exportPersistedState = (
    callClient: (string, ?Object) => Promise<Object>,
    persistedState: ?PersistedState,
    store: ?MiddlewareAPI,
  ): Promise<?PersistedState> => {
    if (persistedState) {
      return Promise.resolve(persistedState);
    }
    const defaultPromise = Promise.resolve(persistedState);
    if (!store) {
      return defaultPromise;
    }
    return callClient('getAllImageData').then((data: ImagesMetaData) => {
      if (!data) {
        return;
      }
      const {levels, events, imageDataList} = data;
      let pluginData: PersistedState = {
        images: [...levels.levels],
        surfaceList: new Set(),
        events: [],
        imagesMap: {},
      };

      events.forEach((event: ImageEventWithId, index) => {
        const {attribution} = event;
        if (attribution instanceof Array && attribution.length > 0) {
          const surface = attribution[0].trim();
          if (surface.length > 0) {
            pluginData.surfaceList.add(surface);
          }
        }
        pluginData = {
          ...pluginData,
          events: [{eventId: index, ...event}, ...pluginData.events],
        };
      });

      imageDataList.forEach((imageData: ImageData) => {
        const {imageId} = imageData;
        pluginData.imagesMap[imageId] = imageData;
      });
      return pluginData;
    });
  };

  static metricsReducer = (
    persistedState: PersistedState,
  ): Promise<MetricType> => {
    const {events, imagesMap} = persistedState;
    let wastedBytes = 0;
    events.forEach(event => {
      const {viewport, imageIds} = event;
      if (!viewport) {
        return;
      }
      imageIds.forEach(imageID => {
        const imageData: ImageData = imagesMap[imageID];
        if (!imageData) {
          return;
        }
        const imageWidth: number = imageData.width;
        const imageHeight: number = imageData.height;
        const viewPortWidth: number = viewport.width;
        const viewPortHeight: number = viewport.height;
        const viewPortArea = viewPortWidth * viewPortHeight;
        const imageArea = imageWidth * imageHeight;
        wastedBytes += Math.max(0, imageArea - viewPortArea);
      });
    });
    return Promise.resolve({WASTED_BYTES: wastedBytes});
  };

  state: PluginState;
  imagePool: ImagePool;
  nextEventId: number = 1;

  state = {
    selectedSurface: surfaceDefaultText,
    selectedImage: null,
    isDebugOverlayEnabled: false,
    isAutoRefreshEnabled: false,
    images: [],
    coldStartFilter: false,
  };

  filterImages = (
    images: ImagesList,
    events: Array<ImageEventWithId>,
    surface: string,
    coldStart: boolean,
  ): ImagesList => {
    if (!surface || (surface === surfaceDefaultText && !coldStart)) {
      return images;
    }
    const imageList = images.map((image: CacheInfo) => {
      const imageIdList = image.imageIds.filter(imageID => {
        const filteredEvents = events.filter((event: ImageEventWithId) => {<commit_msg>Reduce in metrics reducer<commit_after>/**
 * Copyright 2018-present Facebook.
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 * @format
 */

import type {
  ImageId,
  ImageData,
  ImagesList,
  ImagesListResponse,
  ImageEvent,
  FrescoDebugOverlayEvent,
  AndroidCloseableReferenceLeakEvent,
  CacheInfo,
} from './api.js';
import type {ImagesMap} from './ImagePool.js';
import type {MetricType, MiddlewareAPI} from 'flipper';
import React from 'react';
import ImagesCacheOverview from './ImagesCacheOverview.js';
import {
  FlipperPlugin,
  FlexRow,
  Text,
  DetailSidebar,
  colors,
  styled,
  isProduction,
} from 'flipper';
import ImagesSidebar from './ImagesSidebar.js';
import ImagePool from './ImagePool.js';

export type ImageEventWithId = ImageEvent & {eventId: number};

type PersistedState = {
  surfaceList: Set<string>,
  images: ImagesList,
  events: Array<ImageEventWithId>,
  imagesMap: ImagesMap,
};

type PluginState = {
  selectedSurface: string,
  selectedImage: ?ImageId,
  isDebugOverlayEnabled: boolean,
  isAutoRefreshEnabled: boolean,
  images: ImagesList,
  coldStartFilter: boolean,
};

const EmptySidebar = styled(FlexRow)({
  alignItems: 'center',
  justifyContent: 'center',
  color: colors.light30,
  padding: 15,
  fontSize: 16,
});

const surfaceDefaultText = 'SELECT ALL SURFACES';

const debugLog = (...args) => {
  if (!isProduction()) {
    // eslint-disable-next-line no-console
    console.log(...args);
  }
};

type ImagesMetaData = {|
  levels: ImagesListResponse,
  events: Array<ImageEventWithId>,
  imageDataList: Array<ImageData>,
|};

export default class extends FlipperPlugin<PluginState, *, PersistedState> {
  static defaultPersistedState: PersistedState = {
    images: [],
    events: [],
    imagesMap: {},
    surfaceList: new Set(),
  };

  static exportPersistedState = (
    callClient: (string, ?Object) => Promise<Object>,
    persistedState: ?PersistedState,
    store: ?MiddlewareAPI,
  ): Promise<?PersistedState> => {
    if (persistedState) {
      return Promise.resolve(persistedState);
    }
    const defaultPromise = Promise.resolve(persistedState);
    if (!store) {
      return defaultPromise;
    }
    return callClient('getAllImageData').then((data: ImagesMetaData) => {
      if (!data) {
        return;
      }
      const {levels, events, imageDataList} = data;
      let pluginData: PersistedState = {
        images: [...levels.levels],
        surfaceList: new Set(),
        events: [],
        imagesMap: {},
      };

      events.forEach((event: ImageEventWithId, index) => {
        const {attribution} = event;
        if (attribution instanceof Array && attribution.length > 0) {
          const surface = attribution[0].trim();
          if (surface.length > 0) {
            pluginData.surfaceList.add(surface);
          }
        }
        pluginData = {
          ...pluginData,
          events: [{eventId: index, ...event}, ...pluginData.events],
        };
      });

      imageDataList.forEach((imageData: ImageData) => {
        const {imageId} = imageData;
        pluginData.imagesMap[imageId] = imageData;
      });
      return pluginData;
    });
  };

  static metricsReducer = (
    persistedState: PersistedState,
  ): Promise<MetricType> => {
    const {events, imagesMap} = persistedState;
    let wastedBytes = events.reduce((acc, event) => {
      const {viewport, imageIds} = event;
      if (!viewport) {
        return acc;
      }
      return (
        acc +
        imageIds.reduce((innerAcc, imageID) => {
          const imageData: ImageData = imagesMap[imageID];
          if (!imageData) {
            return innerAcc;
          }
          const imageWidth: number = imageData.width;
          const imageHeight: number = imageData.height;
          const viewPortWidth: number = viewport.width;
          const viewPortHeight: number = viewport.height;
          const viewPortArea = viewPortWidth * viewPortHeight;
          const imageArea = imageWidth * imageHeight;
          return innerAcc + Math.max(0, imageArea - viewPortArea);
        }, acc)
      );
    }, 0);
    return Promise.resolve({WASTED_BYTES: wastedBytes});
  };

  state: PluginState;
  imagePool: ImagePool;
  nextEventId: number = 1;

  state = {
    selectedSurface: surfaceDefaultText,
    selectedImage: null,
    isDebugOverlayEnabled: false,
    isAutoRefreshEnabled: false,
    images: [],
    coldStartFilter: false,
  };

  filterImages = (
    images: ImagesList,
    events: Array<ImageEventWithId>,
    surface: string,
    coldStart: boolean,
  ): ImagesList => {
    if (!surface || (surface === surfaceDefaultText && !coldStart)) {
      return images;
    }
    const imageList = images.map((image: CacheInfo) => {
      const imageIdList = image.imageIds.filter(imageID => {
        const filteredEvents = events.filter((event: ImageEventWithId) => {
{'fraction_non_alphanumeric': 0.1200326897538053, 'fraction_numerical': 0.0032689753805291654, 'mean_word_length': 3.0371134020618555, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '93653', 'n_tokens_mistral': 2910, 'n_tokens_neox': 2858, 'n_words': 689}