<commit_before>import _ from 'lodash';

// TODO: Sanitize string input of buckets

function querystr_to_array(querystr: string): string[] {
  return querystr
    .split(';')
    .filter(l => l)
    .map(l => l + ';');
}

interface QueryParams {
  bid_window: string;
  bid_afk: string;
  bid_browsers?: string[];
  filter_afk: boolean;
  include_audible?: boolean;
  classes: Record<string, any>;
}

// Constructs a query that returns a fully-detailed list of events from the merging of several sources (window, afk, web).
// Puts it's results in `not_afk` and `events`.
function canonicalEvents(params: QueryParams): string {
  return `
    events  = flood(query_bucket("${params.bid_window}"));
    not_afk = flood(query_bucket("${params.bid_afk}"));
    not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);
    ${params.filter_afk ? 'events  = filter_period_intersect(events, not_afk);' : ''}
  `;
}

export function windowQuery(
  windowbucket,
  afkbucket,
  appcount,
  titlecount,
  filterAFK,
  classes,
  filterCategories: string[][]
): string[] {
  windowbucket = windowbucket.replace('"', '\\"');
  afkbucket = afkbucket.replace('"', '\\"');
  const params: QueryParams = {
    bid_window: windowbucket,
    bid_afk: afkbucket,
    classes: classes,
    filter_afk: filterAFK,
  };
  const code =
    `
      ${canonicalEvents(params)}
      events = categorize(events, ${JSON.stringify(params.classes)});
    ` +
    (filterCategories
      ? `events = filter_keyvals(events, "$category", ${JSON.stringify(filterCategories)});`
      : '') +
    `
    title_events = sort_by_duration(merge_events_by_keys(events, ["app", "title"]));
    app_events   = sort_by_duration(merge_events_by_keys(title_events, ["app"]));
    cat_events   = sort_by_duration(merge_events_by_keys(events, ["$category"]));

    events = sort_by_timestamp(events);
    app_events  = limit_events(app_events, ${appcount});
    title_events  = limit_events(title_events, ${titlecount});
    duration = sum_durations(events);
    RETURN  = {"app_events": app_events, "title_events": title_events, "cat_events": cat_events, "duration": duration, "active_events": not_afk};`;
  return querystr_to_array(code);
}

export function appQuery(appbucket: string, limit = 5): string[] {
  appbucket = appbucket.replace('"', '\\"');
  const code = `
    events  = query_bucket("${appbucket}");
    events  = merge_events_by_keys(events, ["app"]);
    events  = sort_by_duration(events);
    events  = limit_events(events, ${limit});
    total_duration = sum_durations(events);
    RETURN  = {"events": events, "total_duration": total_duration};
  `;
  return querystr_to_array(code);
}

const appnames = {
  chrome: [
    'Google-chrome',
    'chrome.exe',
    'Chromium',
    'Google Chrome',
    'Chromium-browser',
    'Chromium-browser-chromium',
    'Google-chrome-beta',
    'Google-chrome-unstable',
    'Brave-browser',
  ],
  firefox: [
    'Firefox',
    'Firefox.exe',
    'firefox',
    'firefox.exe',
    'Firefox Developer Edition',
    'firefoxdeveloperedition',
    'Firefox Beta',
    'Nightly',
  ],
  opera: ['opera.exe', 'Opera'],
  brave: ['brave.exe'],
  vivaldi: ['Vivaldi-stable', 'Vivaldi-snapshot', 'vivaldi.exe'],
};

// Returns a list of (browserName, bucketId) pairs for found browser buckets
function browsersWithBuckets(browserbuckets: string[]): [string, string][] {<commit_msg>feat: added support for Edge browser<commit_after>import _ from 'lodash';

// TODO: Sanitize string input of buckets

function querystr_to_array(querystr: string): string[] {
  return querystr
    .split(';')
    .filter(l => l)
    .map(l => l + ';');
}

interface QueryParams {
  bid_window: string;
  bid_afk: string;
  bid_browsers?: string[];
  filter_afk: boolean;
  include_audible?: boolean;
  classes: Record<string, any>;
}

// Constructs a query that returns a fully-detailed list of events from the merging of several sources (window, afk, web).
// Puts it's results in `not_afk` and `events`.
function canonicalEvents(params: QueryParams): string {
  return `
    events  = flood(query_bucket("${params.bid_window}"));
    not_afk = flood(query_bucket("${params.bid_afk}"));
    not_afk = filter_keyvals(not_afk, "status", ["not-afk"]);
    ${params.filter_afk ? 'events  = filter_period_intersect(events, not_afk);' : ''}
  `;
}

export function windowQuery(
  windowbucket,
  afkbucket,
  appcount,
  titlecount,
  filterAFK,
  classes,
  filterCategories: string[][]
): string[] {
  windowbucket = windowbucket.replace('"', '\\"');
  afkbucket = afkbucket.replace('"', '\\"');
  const params: QueryParams = {
    bid_window: windowbucket,
    bid_afk: afkbucket,
    classes: classes,
    filter_afk: filterAFK,
  };
  const code =
    `
      ${canonicalEvents(params)}
      events = categorize(events, ${JSON.stringify(params.classes)});
    ` +
    (filterCategories
      ? `events = filter_keyvals(events, "$category", ${JSON.stringify(filterCategories)});`
      : '') +
    `
    title_events = sort_by_duration(merge_events_by_keys(events, ["app", "title"]));
    app_events   = sort_by_duration(merge_events_by_keys(title_events, ["app"]));
    cat_events   = sort_by_duration(merge_events_by_keys(events, ["$category"]));

    events = sort_by_timestamp(events);
    app_events  = limit_events(app_events, ${appcount});
    title_events  = limit_events(title_events, ${titlecount});
    duration = sum_durations(events);
    RETURN  = {"app_events": app_events, "title_events": title_events, "cat_events": cat_events, "duration": duration, "active_events": not_afk};`;
  return querystr_to_array(code);
}

export function appQuery(appbucket: string, limit = 5): string[] {
  appbucket = appbucket.replace('"', '\\"');
  const code = `
    events  = query_bucket("${appbucket}");
    events  = merge_events_by_keys(events, ["app"]);
    events  = sort_by_duration(events);
    events  = limit_events(events, ${limit});
    total_duration = sum_durations(events);
    RETURN  = {"events": events, "total_duration": total_duration};
  `;
  return querystr_to_array(code);
}

const appnames = {
  chrome: [
    'Google-chrome',
    'chrome.exe',
    'Chromium',
    'Google Chrome',
    'Chromium-browser',
    'Chromium-browser-chromium',
    'Google-chrome-beta',
    'Google-chrome-unstable',
    'Brave-browser',
  ],
  firefox: [
    'Firefox',
    'Firefox.exe',
    'firefox',
    'firefox.exe',
    'Firefox Developer Edition',
    'firefoxdeveloperedition',
    'Firefox Beta',
    'Nightly',
  ],
  opera: ['opera.exe', 'Opera'],
  brave: ['brave.exe'],
  edge: ['msedge.exe'],
  vivaldi: ['Vivaldi-stable', 'Vivaldi-snapshot', 'vivaldi.exe'],
};

// Returns a list of (browserName, bucketId) pairs for found browser buckets
function browsersWithBuckets(browserbuckets: string[]): [string, string][] {
{'fraction_non_alphanumeric': 0.15657528221668376, 'fraction_numerical': 0.00029321213898255387, 'mean_word_length': 4.227586206896552, 'pattern_counts': {'":': 14, '<': 5, '<?xml version=': 0, '>': 9, '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': '1147738', 'n_tokens_mistral': 2354, 'n_tokens_neox': 2302, 'n_words': 465}