AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

    • Início
    • system&network
    • Ubuntu
    • Unix
    • DBA
    • Computer
    • Coding
    • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / user-169992

Lance's questions

Martin Hope
Lance Pollard
Asked: 2025-04-25 15:32:42 +0800 CST

Como criar um layout que tenha apenas todos os tamanhos de linhas pares ou ímpares e mude em apenas 2?

  • 8

Tenho iterado com o Claude 3.7 Sonnet e o ChatGPT 4o por dias e dias, tentando fazer com que fique exatamente como eu quero, mas ele continua cometendo erros no algoritmo e, de vez em quando, cometendo os mesmos erros, basicamente em um círculo vicioso.

Como faço para criar um "layout" (matriz de inteiros), que representa uma grade, que tem as seguintes restrições:

  1. A função é generateGridLayout(n, minColumns, maxColumns), onde na prática ela é normalmente chamada de gen(n, 3, 7), mas em teoria poderia ser qualquer coisa que formaria uma grade legal, gen(n, 2, 256)como o intervalo máximo.
  2. Ele deve manipular um número arbitrário de elementos (digamos, até Number.MAX_SAFE_INTEGER, que é 9007199254740991, mas, na prática, meus "layouts de grade" terão apenas até 1000 itens).
  3. Se o número de itens nfor ímpar, cada linha deverá ter apenas um número ímpar de valores. Se nfor par, cada linha poderá ter números pares ou ímpares (pense em 30, podem ser 10 linhas de 3, ou 3 linhas de 10).
  4. As linhas só podem diferir 2em tamanho, sempre decrescente. Elas nunca podem diferir em 3, 4, etc. Isso significa que 7 NÃO PODE ser [5, 2] ou [4, 4, 1], pois esses têm saltos > 2. Só pode ser [7] ou [3, 3, 1], se gen(7, 3, 7).
  5. (nota meta: isso é para um layout de interface de usuário, então é baseado no tamanho da janela de visualização/contêiner, então se dissermos "máximo 7", mas houver espaço apenas para 5, ele definirá o máximo como 5, mas esse fato não é realmente relevante para a solução)
  6. Se dissermos "máximo é 7", mas houver um número par de itens, e o número par não puder satisfazer "todas as linhas pares ou ímpares", então tente maxColumns - 1, e assim por diante, até minColumns.
  7. Importante: deve minimizar o número de linhas pequenas. Portanto, para 29, com 6 maxColumns, deve ser [5, 5, 5, 5, 5, 3, 1], e não [5, 5, 5, 5, 3, 3, 3]. Ou seja, maximiza o número de linhas grandes e minimiza o número de linhas pequenas. Da mesma forma, para 29, definitivamente não deve ser [5, 5, 5, 5, 3, 3, 1, 1, 1].

Aqui estão alguns exemplos para demonstrar o objetivo:

31
[5, 5, 5, 5, 5, 3, 3]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1]

30
[5, 5, 5, 5, 5, 5]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]

29
[5, 5, 5, 5, 5, 3, 1]
[3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1]

28
[6, 6, 6, 6, 4]
[4, 4, 4, 4, 4, 4, 4]

27
[5, 5, 5, 5, 3, 3, 1]
[3, 3, 3, 3, 3, 3, 3, 3, 3]

26
[6, 6, 6, 4, 2, 2]
[4, 4, 4, 4, 4, 4, 4]

23
[5, 5, 5, 5, 3]
[3, 3, 3, 3, 3, 3, 3, 1, 1]

Elas mostram, se 5 ou 6 forem o máximo de colunas, o que ele faria, e o que deveria fazer se 4 ou 3 forem o máximo de colunas.

Por exemplo, 26 em 7 colunas no máximo NÃO devem ser:

[6, 6, 6, 6, 2] # jumps more than 2
[4, 4, 4, 4, 4, 4, 2] # doesn't maximize maxColumns

O ideal seria:

[6, 6, 6, 4, 2, 2] # jumps max 2, maximizes large columns, minimizes small columns.

Aqui está minha solução atual:

log(29, 2, 7)
log(29, 2, 6)
log(29, 2, 5)
log(29, 2, 4)
log(44, 2, 3)

function distributeGridLayout(
  length,
  minColumns,
  maxColumns
) {
  function recur(
    dp,
    length,
    width,
  ) {
    if (length == 0) {
      return []
    }

    if (length < width - 2 || width <= 0) {
      return
    }

    if (dp[width].has(length)) {
      return
    }

    dp[width].add(length)

    for (let i = 0; i < 2; i++) {
      let result = recur(dp, length - width, width)
      if (result) {
        return [width, ...result]
      }
      width -= 2
    }

    return
  }

  if (length <= maxColumns) {
    return [length]
  }

  if (maxColumns >= 3 && length === 7) {
    return [3, 3, 1]
  }

  if (maxColumns >= minColumns && length % maxColumns === 0) {
    const result = []
    while (length) {
      result.push(maxColumns)
      length -= maxColumns
    }
    return result
  }

  if (maxColumns > 4) {
    if (maxColumns > minColumns && length % (maxColumns - 1) === 0) {
      const result = []
      maxColumns--
      while (length) {
        result.push(maxColumns)
        length -= maxColumns
      }
      return result
    }
  }

  const dec = 2 - (length % 2)

  maxColumns -= maxColumns % dec

  const dp = Array.from(
    { length: maxColumns + 1 },
    () => new Set(),
  )

  for (let width = maxColumns; width > 0; width -= dec) {
    const result = recur(dp, length - width, width)
    if (result) {
      if (width <= minColumns) {
        return
      }
      return [width, ...result]
    }
  }

  return
}

function log(n, min, max) {
  const grid = distributeGridLayout(n, min, max)
  console.log(`gen(${n}, ${min}, ${max})`, grid)
}

Isso funciona para a maioria, como este layout tibetano (29 caracteres):

Mas não está funcionando para este layout tailandês (44 caracteres, em 2-3 colunas), aqui está o final (na minha interface, se o algoritmo retornar indefinido, ele volta para um layout de grade básico):

O que preciso mudar exatamente para que isso sempre se ajuste às minhas regras? O layout 44 de 3 no máximo e 2 minutos deve ser basicamente um layout de 2 colunas...

javascript
  • 1 respostas
  • 85 Views
Martin Hope
Lance Pollard
Asked: 2024-10-18 19:29:33 +0800 CST

Como construir um trie para encontrar correspondências fonéticas exatas, classificadas globalmente por peso e paginadas? (Construindo a partir deste exemplo)

  • 0

Meta

Cheguei bem longe trabalhando com IA para me ajudar a construir um Trie para encontrar palavras que rimam. Basicamente, digamos que você tem 10 milhões de palavras em inglês escritas usando o sistema de pronúncia CMU , onde cada fonema é um nó no Trie ( ARPABETnesta imagem).

insira a descrição da imagem aqui

Aqui estão os principais recursos:

  1. Os nós Trie são símbolos ASCII 1+ . Como Bpara o som "b" e CHpara o som "ch", etc.
  2. Trie pode paginar e pular de uma página específica. Então, ele pega uma propriedade limit, e page.
  3. A paginação pode ser opcionalmente limitada a correspondências de um comprimento de sequência de fonemas em particular . Como fonemas de g l a dseriam 4.
  4. A entrada de pesquisa Trie (fornecida pelo usuário) é uma matriz de fonemas . Fonemas são as unidades de som em ASCII (como o ARPABETacima).
  5. A entrada para o trie é expandida para todas as rimas possíveis . Ela é expandida usando um mapa de fonema para array de fonemas (implementado apenas parcialmente na função abaixo, levará semanas para ajustar adequadamente os valores aqui, o que preciso de TODO em breve).
  6. Podemos chamar a entrada expandida de " rhymingPhonemeArray" .
  7. Cada sequência de fonemas no rhymingPhonemeArrayé ponderada . Por "ponderada", esse peso é basicamente "quão próximo o fonema mapeado está do fonema original". Isso é para que possamos dizer "essa sequência de fonemas (com um peso cumulativo menor ) é uma rima melhor do que essa outra sequência de fonemas no rhymingPhonemeArray".

Problemas

O(s) problema(s) que estou enfrentando agora (com a solução que encontramos, compartilhada abaixo em JavaScript), são:

  1. Percorrendo todo o trie para encontrar todas as correspondências possíveis , o que não é otimizado. Idealmente, ele só percorre o que precisa (a página / quantidade limite e deslocamento).
  2. O Trie classifica todo o conjunto de correspondências depois , em vez de fazer o que queremos, que é obter a quantidade de páginas/limites já classificada. Este é o problema principal, não tenho certeza se/como ele pode fazer isso de forma otimizada, ou se é mesmo possível.
  3. O rhymingPhonemeArrayé iterado por 😔 , então se estivermos paginando e o rhymingPhonemeArrayfor como [G-A-D (cum-weight: 10), G-L-A-D (cum-weight: 24 or whatever), G-R-A-D (cum-weight: 29), etc.], você vai encontrar tudo que rima com G-A-Dprimeiro, então depois disso é paginado por, paginar por G-L-A-D, etc.. Eu gostaria de evitar esse agrupamento . Em vez disso, o peso cumulativo precisa ser classificado e paginado por meio do "conjunto global" de todas as 10 milhões de palavras.

Portanto, para (3), ele deve encontrar ( algo como isto):

input: G-A-D
matches:
  G-A-D
  G-L-A-D
  A-G-A-D
  A-R-G-A-D
  G-R-A-D
  A-G-R-A-D
  A-R-G-L-A-D
  A-R-G-R-A-D
  ...

Por "algo assim", quero dizer, observe como NÃO é assim (onde primeiro, todas as G-A-Dcorrespondências são encontradas, depois todas G-L-A-Dsão encontradas etc.):

input: G-A-D
matches:
  G-A-D
  A-G-A-D
  A-R-G-A-D
  G-L-A-D
  A-R-G-L-A-D
  G-R-A-D
  A-G-R-A-D
  A-R-G-R-A-D
  ...

Em vez disso, no primeiro matches, ele é mais entrelaçado , o que deve ser baseado no peso cumulativo global de cada palavra.

Pergunta

Como você pode modificar a seguinte "Implementação Trie" para resolver os problemas de 1, 2 e 3 acima? Nota: não precisa ser 100% exato, apenas buscando o insight chave sobre como resolver esse problema de paginação corretamente (mesmo que apenas em um nível alto/pseudocódigo). Eles são todos aspectos do mesmo problema subjacente, que é o que eu já declarei, mas declararei novamente:

A implementação do Trie abaixo não pagina corretamente e de forma um tanto eficiente as palavras classificadas por peso cumulativo global , que são correspondências exatas para rhymingPhonemeArray(que é gerado a partir da phonemesentrada).

É possível resolver esse problema sem ter que iterar sobre o Trie inteiro? Dado (lembre-se), a entrada é expandida para rhymingPhonemeArray(o que pode ser um monte de possibilidades, mas vamos praticamente limitar a entrada a provavelmente 3 sílabas, além do ponto). Se não for possível, você pode explicar por que não é possível?

Se possível, como você modificaria esta tela para suportar paginação e pular para uma página específica sem precisar percorrer tudo, enquanto ao mesmo tempo os resultados paginados são classificados globalmente pelo peso cumulativo de cada palavra?

Implementação Trie

O Trie em que pousamos era este:

class TrieNode {
  constructor() {
    this.children = {}; // Store child nodes
    this.isWord = false; // Flag to check if node marks the end of a word
    this.word = null; // Store the word if this is an end node
    this.cumulativeWeight = 0; // Store the cumulative weight for sorting
    this.phonemeLength = 0; // Length of the phoneme sequence
  }
}

class PhoneticTrie {
  constructor() {
    this.root = new TrieNode(); // Root node of the trie
  }

  // Insert words and phoneme clusters into the Trie
  insert(word, phonemes, weight) {
    let node = this.root;
    for (let phoneme of phonemes) {
      if (!node.children[phoneme]) {
        node.children[phoneme] = new TrieNode();
      }
      node = node.children[phoneme];
    }
    node.isWord = true;
    node.word = word;
    node.cumulativeWeight = weight; // Store the cumulative weight at this node
    node.phonemeLength = phonemes.length; // Store the length of the phoneme sequence
  }

  // Global sorting of rhyming phoneme matches using a min-heap
  searchWithPagination({ phonemes, limit, page, length }) {
    const minHeap = new MinHeap(); // Min-Heap to store sorted results

    // Generate rhyming phoneme variations
    const rhymingPhonemesArray = expandToRhymingPhonemes(phonemes);

    // Search the Trie for all rhyming phoneme sequences and insert results into the global heap
    for (let rhyme of rhymingPhonemesArray) {
      this.searchAndInsertToHeap(rhyme.phonemes, this.root, rhyme.weight, minHeap, length);
    }

    // Paginate results directly from the globally sorted heap
    const paginatedResults = [];
    const startIndex = (page - 1) * limit;
    let index = 0;

    while (minHeap.size() > 0 && paginatedResults.length < limit) {
      const wordData = minHeap.extractMin();
      if (index >= startIndex) {
        paginatedResults.push(wordData.word);
      }
      index++;
    }

    return paginatedResults;
  }

  // Search a specific phoneme sequence in the Trie and insert matches into the heap
  searchAndInsertToHeap(phonemes, node, rhymeWeight, heap, targetLength, depth = 0, phonemeSeq = []) {
    if (depth === phonemes.length) {
      if (node.isWord && node.word) {
        // If length filtering is specified, ensure the word matches the phoneme length
        if (!targetLength || node.phonemeLength === targetLength) {
          heap.insert({
            word: node.word,
            cumulativeWeight: node.cumulativeWeight + rhymeWeight, // Add the rhyme weight here
            phonemeLength: node.phonemeLength, // Include phoneme length for sorting
          });
        }
      }
      return;
    }

    const phoneme = phonemes[depth];
    if (!node.children[phoneme]) return; // No match
    this.searchAndInsertToHeap(phonemes, node.children[phoneme], rhymeWeight, heap, targetLength, depth + 1, [...phonemeSeq, phoneme]);
  }
}


class MinHeap {
  constructor() {
    this.heap = []; // Store the heap elements
  }

  // Insert an item into the heap based on its weight and phoneme length
  insert({ word, cumulativeWeight, phonemeLength }) {
    this.heap.push({ word, cumulativeWeight, phonemeLength });
    this.bubbleUp(this.heap.length - 1);
  }

  bubbleUp(index) {
    let currentIndex = index;
    while (currentIndex > 0) {
      const parentIndex = Math.floor((currentIndex - 1) / 2);
      // Sort primarily by cumulative weight, secondarily by phoneme length
      if (
        this.heap[currentIndex].cumulativeWeight > this.heap[parentIndex].cumulativeWeight ||
        (this.heap[currentIndex].cumulativeWeight === this.heap[parentIndex].cumulativeWeight &&
          this.heap[currentIndex].phonemeLength > this.heap[parentIndex].phonemeLength)
      ) {
        break;
      }
      [this.heap[currentIndex], this.heap[parentIndex]] = [this.heap[parentIndex], this.heap[currentIndex]];
      currentIndex = parentIndex;
    }
  }

  // Extract the item with the lowest weight
  extractMin() {
    if (this.heap.length === 0) return null;
    if (this.heap.length === 1) return this.heap.pop();
    const min = this.heap[0];
    this.heap[0] = this.heap.pop();
    this.bubbleDown(0);
    return min;
  }

  bubbleDown(index) {
    const lastIndex = this.heap.length - 1;
    while (true) {
      let leftChildIdx = 2 * index + 1;
      let rightChildIdx = 2 * index + 2;
      let smallestIdx = index;

      if (
        leftChildIdx <= lastIndex &&
        (this.heap[leftChildIdx].cumulativeWeight < this.heap[smallestIdx].cumulativeWeight ||
          (this.heap[leftChildIdx].cumulativeWeight === this.heap[smallestIdx].cumulativeWeight &&
            this.heap[leftChildIdx].phonemeLength < this.heap[smallestIdx].phonemeLength))
      ) {
        smallestIdx = leftChildIdx;
      }
      if (
        rightChildIdx <= lastIndex &&
        (this.heap[rightChildIdx].cumulativeWeight < this.heap[smallestIdx].cumulativeWeight ||
          (this.heap[rightChildIdx].cumulativeWeight === this.heap[smallestIdx].cumulativeWeight &&
            this.heap[rightChildIdx].phonemeLength < this.heap[smallestIdx].phonemeLength))
      ) {
        smallestIdx = rightChildIdx;
      }
      if (smallestIdx === index) break;

      [this.heap[index], this.heap[smallestIdx]] = [this.heap[smallestIdx], this.heap[index]];
      index = smallestIdx;
    }
  }

  size() {
    return this.heap.length;
  }
}

function expandToRhymingPhonemes(phonemes) {
  // todo: this function would have a huge map of phoneme substitutions...
  const phonemeSubstitutions = {
    "k": ["g", "p"], // Example of substitutions for the phoneme "k"
    "æ": ["a", "e"], // Example for "æ"
    "t": ["d", "s"], // Example for "t"
  };

  const rhymingPhonemesArray = [];

  function generateRhymes(sequence, depth = 0, currentWeight = 0) {
    if (depth === sequence.length) {
      rhymingPhonemesArray.push({ phonemes: sequence.slice(), weight: currentWeight });
      return;
    }

    const phoneme = sequence[depth];
    const substitutions = phonemeSubstitutions[phoneme] || [phoneme];

    for (const sub of substitutions) {
      generateRhymes(
        [...sequence.slice(0, depth), sub, ...sequence.slice(depth + 1)],
        depth + 1,
        currentWeight + (sub === phoneme ? 0 : 1)  // Substitution adds to weight
      );
    }
  }

  generateRhymes(phonemes);
  return rhymingPhonemesArray;
}

const trie = new PhoneticTrie();
trie.insert("glad", ["g", "l", "a", "d"], 3);
trie.insert("grad", ["g", "r", "a", "d"], 2);
trie.insert("blad", ["b", "l", "a", "d"], 4);
trie.insert("grin", ["g", "r", "i", "n"], 5);

// Search for similar words to "g-l-a-d" and paginate the results, with optional length filtering
const resultsPage1 = trie.searchWithPagination({
  phonemes: ["g", "l", "a", "d"],
  limit: 2,
  page: 1,
  length: 4, // Only consider words with exactly 4 phonemes
});

const resultsPage2 = trie.searchWithPagination({
  phonemes: ["g", "l", "a", "d"],
  limit: 2,
  page: 2,
  length: 4,
});

console.log(resultsPage1); // Output: ["grad", "glad"] (sorted by weight and length)
console.log(resultsPage2); // Output: ["blad", "grin"]

Atualizações

  1. Aqui está um resumo com mais expansões/tentativas do Trie para resolver esse problema fundamental.
javascript
  • 1 respostas
  • 46 Views
Martin Hope
HareSurf
Asked: 2024-09-17 22:26:23 +0800 CST

Como calcular o número de colunas de modo que cada linha tenha todos os números pares ou ímpares de itens, da forma mais compacta possível?

  • 4

Gostaria de dispor glifos unicode semelhantes a este :

Pode haver de 13 a 100 itens na coleção exibida (alfabetos, abjads, abugidas, silabários, etc.), então pode haver um conjunto com 99 itens, ou um com 16 itens, etc.

Como você pode dispor os elementos de forma mais bonita (e automática) (para que também fique bonito quando responsivo)? Aqui está o que eu tenho por padrão com o flexbox:

insira a descrição da imagem aqui

Cada item tem uma altura fixa e a largura é responsiva (mas a mesma para cada elemento).

O objetivo é que cada linha tenha um número par ou ímpar de itens. Dessa forma, todas as colunas verticais ficarão alinhadas (e não fará o que meu gif animado está fazendo, onde linhas pares/ímpares são intercaladas).

  1. É possível fazer alguma fórmula matemática para calcular algo como "você precisa de 5 itens por linha, exceto que a última linha terá 3 (ou 1)"? Dada alguma contagem total como 99?

Como você faria isso?

Eu tenho um componente React que faz o layout do Flexbox como <Grid minWidth={96} gap={8} maxColumns={5} breakpoints={[5, 3, 1]} />, onde breakpointsestão o número de itens permitidos por linha, e maxColumnssão as colunas máximas (breakpoints/maxColumn é meio redundante, você pode definir qualquer um ou, talvez eu limpe isso mais tarde) . Todas essas informações podem ser irrelevantes, mas apenas apontando para o caso, é meu componente de grade responsivo.

Como posso dividir meu total por x para descobrir se deve haver linhas pares ou ímpares e, então, definir o maxColumnsou breakpointspara o que for "mais compacto"? Então, por exemplo:

  • Se forem 26 elementos , ficaria melhor com 6 linhas de 4, seguidas de 1 linha de 2. - Se forem 27 elementos ,

A "beleza" disso pode ser subjetiva, e não há uma regra clara para o que é mais bonito. Apenas procurando por qualquer coisa que não deixe facilmente um nó único órfão no final e então tenha 7 itens em todas as outras linhas. Idealmente, temos:

  • Entre 3 e 7 colunas.
  • A última linha deve ter o mesmo número de itens em todas as linhas anteriores, ou não menos que isso maxRowCount - 2(portanto, se todas as linhas tiverem 7, a última linha poderá ter 5 ou apenas 7, ou se todas as linhas tiverem 5, a última linha poderá ter apenas 3 ou 5, etc.).
  • O item de linha tem um minWidth: 96px, e cresce para preencher o espaço. Posso descobrir como tornar as coisas responsivas quando tivermos o básico disso funcionando, mas suponha que a containerWidthexista.

Então, na minha cabeça, digamos que temos containerWidth === 700px. Então, 700/96 == 7+, então talvez 7 por linha. Se tivermos 99 itens (por exemplo), então 99 % 7 == 1, então 7não vai funcionar porque teremos 1 na última linha. 6não vai funcionar porque 99é par, então tente 5? 99 % 5 == 4, isso não vai funcionar porque 4é par. Então tente 3, 99 % 3 == 0, então isso funcionaria como está, use isso!

Como você implementaria algo assim?

javascript
  • 2 respostas
  • 31 Views
Martin Hope
Lance
Asked: 2024-06-25 10:50:33 +0800 CST

Keyman “O arquivo do teclado é uma versão antiga” e outros erros/avisos com Keyman CLI?

  • 5

Usei IA para me ajudar a aprender Keyman e resultou nisso:

c My Fantasy Script Keyboard
store(&VERSION) '1.0'
store(&NAME) 'My Fantasy Script'
store(&BITMAP) 'fntsy.ico'
store(&LAYOUTFILE) 'fntsy.kmn'
store(&TARGETS) 'windows macosx linux web'

begin Unicode > use(main)

group(main) using keys
+ '0' > U+00A1 c Mapping for the '0' key
+ '1' > U+00A6 c Mapping for the '1' key
+ '2' > U+00A2 c Mapping for the '2' key
+ '3' > U+00A3 c Mapping for the '3' key
+ '4' > U+00A5 c Mapping for the '4' key
+ '5' > U+00A4 c Mapping for the '5' key
+ '6' > U+00A9 c Mapping for the '6' key
+ '7' > U+00A7 c Mapping for the '7' key
+ '8' > U+00AB c Mapping for the '8' key
+ '9' > U+00AE c Mapping for the '9' key

O que estou fazendo de errado?

Por que obtenho esta saída ao executar este comando (instalando @keymanapp/kmc )?

$ kmc build --color --debug fntsy.kmn
fntsy.kmn - info KM05002: Building fntsy.kmn
fntsy.kmn:2 - warn KM02081: The keyboard file is an old version
fntsy.kmn:2 - error KM0200D: Invalid 'version' command
fntsy.kmn - info KM05007: fntsy.kmn failed to build.

Como faço para corrigir isso? Essa documentação é muito difícil de seguir e encontrar soluções, então provavelmente estou usando a versão errada do formato de arquivo (embora não tenha conseguido encontrar a correta ou o que há de errado com a minha), e a versão inválida está me confundindo também.

Atualizar:

Alterar a versão para fazer referência à versão de Keymans (não à versão do meu idioma) parece superar isso:

store(&VERSION) '17.0'

Mas agora recebo uma série destes avisos:

fntsy.kmn:11 - warn KM02084: There are too many characters in the keystroke part of the rule.
fntsy.kmn:12 - warn KM02084: There are too many characters in the keystroke part of the rule.

Eu tenho regras como essa, o que há de errado?

group(main) using keys
+ 'I$&--@_^' [K_TAB] > 'I%9440005' c Mapping for the 'I$&--@_^' key, the vowel i with stress, lengthening, tense, stress, nasalization and extra low tone
+ 'I$&-@_^' [K_TAB] > 'I%940005' c Mapping for the 'I$&-@_^' key, the vowel i with stress, lengthening, tense, stress, nasalization and low tone
+ 'I$&++@_^' [K_TAB] > 'I%9330005' c Mapping for the 'I$&++@_^' key, the vowel i with stress, lengthening, tense, stress, nasalization and extra high tone
+ 'I$&+@_^' [K_TAB] > 'I%930005' c Mapping for the 'I$&+@_^' key, the vowel i with stress, lengthening, tense, stress, nasalization and high tone
keyman
  • 1 respostas
  • 16 Views
Martin Hope
Lance
Asked: 2024-05-27 11:02:24 +0800 CST

Quais são as diferenças e os propósitos dos campos shasum, integridade e assinaturas do NPM?

  • 4

Um exemplo de JSON de metadados do pacote NPM se parece com este ( distmovido para o topo):

{
  "name": "lodash",
  "version": "4.17.21",
  "description": "Lodash modular utilities.",
  "dist": {
    "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
    "shasum": "679591c564c3bffaae8454cf0b3df370c3d6911c",
    "tarball": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
    "fileCount": 1054,
    "unpackedSize": 1412415,
    "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgMS3ZCRA9TVsSAnZWagAA8+4P/jx+SJ6Ue5oAJjz0L7gw\nLDD5YvP8aoliFq4GYkwUXfVQvOwomIPfa+U5Kao/hDfuwFQ/Bq5D5nSsl2bj\nrjJgvlKXna0SId8AgDgY2fB7zSfninuJvalY4iTWMN8DFSpG0XE2QFfoKpd3\njDmuzcNtgr79QV6DgjOVkHiP1IGNDlLTc1QEKiwo/5CdGQi1q/iCj6dViQMJ\nByuuuV2Qzi3f/FI25cG797WZar1MHhhlcnB50HiVBGp54IZOyuqdqWPduZQo\nvhONtonxPGBm3/J+uAkeUSSyL3Ud+FzLvdg8WEI9gDL0yvU4k0FcsnOONEYn\nngLaKEsw2xAnPBYW3Lf73Jnpwx6FAT3k49kgzxiNYSxEo7x4wiuNtBoDMyNw\nEKj6SZ0bUNmaJgiMfDnnDjCKjI3JrO1hho8z6CkwuvxuWLlW9wSsVayggzAI\nEhfeTeISugVHh332oDY2MI/Ysu8MnVN8fGmqeYQBBFj3aWatuA2NvVjACnX/\n54G7FtCU8TxZpm9shFRSopBx8PeI3r+icx1CT8YVFypY416PLnidHyqtME1G\neuRd1nWEz18hvVUAEHmuvHo+EPP3tITmTTUPQcZGMdBcZC+4UBmPMWX466HE\nbHw4aOnUWMa0sWfsERC5xzRZAb4lgMPEoTOnZyN4usMy7x9TzGZKZvU24HUE\nmpae\r\n=NOmG\r\n-----END PGP SIGNATURE-----\r\n",
    "signatures": [
      {
        "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA",
        "sig": "MEUCIF3Yithbtmy1aEBNlfNWbLswAfPIyQUuNUGARD3Ex2t4AiEA6TlN2ZKJCUpS/Sf2Z6MduF1BNSvayHIpu5wAcICcKXw="
      }
    ]
  },
  "keywords": [
    "modules",
    "stdlib",
    "util"
  ],
  "homepage": "https://lodash.com/",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/lodash/lodash.git"
  },
  "icon": "https://lodash.com/icon.svg",
  "license": "MIT",
  "main": "lodash.js",
  "author": {
    "name": "John-David Dalton",
    "email": "[email protected]"
  },
  "contributors": [
    {
      "name": "John-David Dalton",
      "email": "[email protected]"
    },
    {
      "name": "Mathias Bynens",
      "email": "[email protected]"
    }
  ],
  "scripts": {
    "test": "echo \"See https://travis-ci.org/lodash-archive/lodash-cli for testing details.\""
  },
  "gitHead": "c6e281b878b315c7a10d90f9c2af4cdb112d9625",
  "bugs": {
    "url": "https://github.com/lodash/lodash/issues"
  },
  "_id": "[email protected]",
  "_nodeVersion": "14.15.5",
  "_npmVersion": "6.14.11",
  "_npmUser": {
    "name": "bnjmnt4n",
    "email": "[email protected]"
  },
  "directories": {

  },
  "maintainers": [
    {
      "name": "mathias",
      "email": "[email protected]"
    },
    {
      "name": "jdalton",
      "email": "[email protected]"
    },
    {
      "name": "bnjmnt4n",
      "email": "[email protected]"
    }
  ],
  "_npmOperationalInternal": {
    "host": "s3://npm-registry-packages",
    "tmp": "tmp/lodash_4.17.21_1613835736675_0.01913912595366596"
  },
  "_hasShrinkwrap": false
}

Aqui estão minhas perguntas relacionadas aos 3 campos:

  • dist.shasum: Diz-se que este é shasum <tarball>o tarball (comando CLI), usando SHA-1.
  • dist.integrity: ChatGPT diz (eu acho...) que isso serve ao mesmo propósito que o shasum, mas é "mais seguro" (porque às vezes usa codificação SHA-256 ou SHA-512. Mas qual é a real diferença ou razão para ter ambos dist.shasume dist.integrity?Eles diferem de alguma outra forma?
  • dist.signatures[*].sig: O que essa assinatura faz? como você usa isso? ChatGPT parece dizer que isso é testado usando chaves públicas, mas quem tem quais lados das chaves e quando isso é usado? Quando/por que você teria mais de um?

Já que estamos aqui também, como isso dist.npm-signaturese relaciona com as três coisas acima?

security
  • 1 respostas
  • 20 Views
Martin Hope
Lance
Asked: 2024-04-07 05:25:48 +0800 CST

Como parar de caminhar bits (direção = bit menos significativo para o mais significativo) depois de chegar à cadeia de 0's?

  • 3

Eu tenho essas duas funções para percorrer os 32 bits de um número inteiro no TypeScript:

export function* walkBitsFromLSB(n: number) {
  for (let i = 0; i < 32; i++) {
    // Check the least significant bit (LSB)
    const bit = (n >> i) & 1
    yield bit
  }
}

export function* walkBitsFromMSB(n: number) {
  // Start with a mask that isolates the MSB of a 32-bit integer
  let mask = 1 << 31
  for (let i = 0; i < 32; i++) {
    // Apply the mask to n and check if the result is non-zero
    const bit = n & mask ? 1 : 0
    yield bit
    // Shift the mask right for the next bit
    mask >>>= 1
  }
}

Posso modificar o MSB para percorrer apenas os bits "relevantes", assim:

export function* walkRelevantBitsFromMSB(n: number) {
  let mask = 1 << 31;
  let start = false; // Flag to indicate when we've found the first non-zero bit
  for (let i = 0; i < 32; i++) {
    const bit = n & mask ? 1 : 0;
    if (bit === 1) start = true;
    if (start) yield bit; // Only start yielding bits after the first 1 is encountered
    mask >>>= 1;
  }
}

Como você pode fazer o mesmo para a função LSB de uma maneira ideal?

Ou seja, se os bits fossem 0b00000000000000000001111011101101, você leria:

1
0
1
1
0
1
1
1
0
1
1
1
1
DONE

Como você poderia fazer isso sem criar um armazenamento de cache/hashmap { [binaryNumber]: length }ou qualquer tipo de hashtable como esse. Como você pode simplesmente derivá-lo da entrada npara a função, o comprimento em que você para de verificar os valores?

javascript
  • 1 respostas
  • 23 Views
Martin Hope
Lance
Asked: 2024-02-11 14:12:34 +0800 CST

Como fazer com que o tipo de resultado de retorno da função dependa do parâmetro de entrada no TypeScript?

  • 5

Eu tenho este playground TypeScript até agora:

export type Encoding = 'buffer' | 'blob' | 'base64'

export default async function md2docx<E extends Encoding>(
  text: string,
  encoding: E,
): Promise<
  E extends 'blob' ? Blob : E extends 'buffer' ? number : string
> {
  switch (encoding) {
    case 'buffer': return 10 //Buffer.from(text)
    case 'blob': return new Blob([text])
    case 'base64': atob(text)
  }
}

md2docx('foo', 'blob').then(output => {
  output.arrayBuffer
})

Basicamente, quero poder passar o tipo de codificação para a função md2docxe fazer com que ela retorne o tipo correto e seja digitado corretamente na outputvariável. No momento meu código não está funcionando. Se eu fizer o seguinte, terei que verificar output instanceof Blobmanualmente o tipo de coisa que gostaria de evitar:

export type Encoding = 'buffer' | 'blob' | 'base64'

export default async function md2docx<E extends Encoding>(
  text: string,
  encoding: E,
) {
  switch (encoding) {
    case 'buffer': return 10 //Buffer.from(text)
    case 'blob': return new Blob([text])
    case 'base64': atob(text)
  }
}

md2docx('foo', 'blob').then(output => {
  if (output instanceof Blob) {
    output.arrayBuffer; // .arrayBuffer property exists.
  }
})
typescript
  • 1 respostas
  • 30 Views
Martin Hope
Lance
Asked: 2024-01-17 14:16:16 +0800 CST

Como corrigir `argumento inseguro do tipo `any` atribuído a um parâmetro do tipo `string`.` no Zod?

  • 5

Na verdade, por algum motivo estranho, estou recebendo um erro localmente (com zod v3.22.4) e outro erro no stackblitz, usando v3.22.4, então não tenho certeza, talvez ambos os erros precisem ser corrigidos.

O exemplo do stackblitz , que é o mesmo código que tenho localmente, é este:

import { z } from 'zod';

type BuildCommandToDecompressWithUnarchiver = {
  overwrite?: boolean;
  password?: string;
  output: {
    directory: {
      path: string;
    };
  };
  input: {
    file: {
      path: string;
    };
  };
};

const BuildCommandToDecompressWithUnarchiverModel: z.ZodType<BuildCommandToDecompressWithUnarchiver> =
  z.object({
    overwrite: z.optional(z.boolean()).default(false),
    password: z.optional(z.string()),
    output: z.object({
      directory: z.object({
        path: z.string(),
      }),
    }),
    input: z.object({
      file: z.object({
        path: z.string(),
      }),
    }),
  });

export function buildCommandToDecompressWithUnarchiver(source) {
  const input = BuildCommandToDecompressWithUnarchiverModel.parse(source);
  const cmd = [
    `unar`,
    `${input.input.file.path}`,
    `-o`,
    `${input.output.directory.path}`,
  ];

  cmd.push('--quiet');

  if (input.overwrite) {
    cmd.push(`-f`);
  }

  if (input.password) {
    cmd.push(`-p`, input.password);
  }

  return cmd;
}

console.log(
  BuildCommandToDecompressWithUnarchiverModel.parse({
    output: {
      directory: {
        path: 'foo',
      },
    },
    input: {
      file: {
        path: 'x.zip',
      },
    },
  })
);

Em primeiro lugar, nota lateral. Eu preciso z.ZodType<BuildCommandToDecompressWithUnarchiver>porque em muitas das minhas definições eu uso esquemas aninhados e você precisa usar esse padrão com frequência para compilá-lo. Então isso precisa ficar.

Mas o que estou obtendo no stackblitz é:

Type 'ZodObject<{ overwrite: ZodDefault<ZodOptional<ZodBoolean>>; password: ZodOptional<ZodString>; output: ZodObject<{ directory: ZodObject<{ path: ZodString; }, "strip", ZodTypeAny, { ...; }, { ...; }>; }, "strip", ZodTypeAny, { ...; }, { ...; }>; input: ZodObject<...>; }, "strip", ZodTypeAny, { ...; }, { ...; }>' is not assignable to type 'ZodType<BuildCommandToDecompressWithUnarchiver, ZodTypeDef, BuildCommandToDecompressWithUnarchiver>'.
  The types of '_type.output.directory' are incompatible between these types.
    Type '{ path?: string; }' is not assignable to type '{ path: string; }'.
      Property 'path' is optional in type '{ path?: string; }' but required in type '{ path: string; }'.(2322)

Não vejo nenhum lugar que esteja definindo pathcomo opcional, então de onde isso vem?

Mas localmente, vejo um erro diferente:

Unsafe argument of type `any` assigned to a parameter of type `string`.eslint@typescript-eslint/no-unsafe-argument
(property) password?: string

insira a descrição da imagem aqui

Eu tenho aquele erro "Argumento inseguro do tipo anyatribuído a um parâmetro do tipo string" em mais de uma dúzia de lugares na minha base de código, todos usando o mesmo padrão para definir esquemas zod. Alguma ideia de como consertar o último (e possivelmente por que o stackblitz não está reproduzindo e, em vez disso, mostra um erro diferente, que às vezes também recebo localmente)?

Minha maneira de contornar o último erro é apenas do input.password as string, mas isso não está certo... Já é garantido que uma string foi digitada neste ponto.

typescript
  • 1 respostas
  • 16 Views
Martin Hope
Lance
Asked: 2024-01-07 16:14:29 +0800 CST

Como obter uma lista dos formatos de entrada e saída na API ImageMagick?

  • 6

Estou mexendo no navegador / wasm ImageMagick API e ele tem um MagickFormatmódulo aqui que se parece essencialmente com isto:

export declare enum MagickFormat {
    Unknown = "UNKNOWN",
    ThreeFr = "3FR",
    ThreeG2 = "3G2",
    ThreeGp = "3GP",
    A = "A",
    Aai = "AAI",
    Ai = "AI",
    Apng = "APNG",
    Art = "ART",
    Arw = "ARW",
    Ashlar = "ASHLAR",
    Avi = "AVI",
    Avif = "AVIF",
    Avs = "AVS",
    B = "B",
    Bayer = "BAYER",
    Bayera = "BAYERA",
    Bgr = "BGR",
    Bgra = "BGRA",
    Bgro = "BGRO",
    Bmp = "BMP",
    Bmp2 = "BMP2",
    Bmp3 = "BMP3",
    Brf = "BRF",
    C = "C",
    Cal = "CAL",
    Cals = "CALS",
    Canvas = "CANVAS",
    Caption = "CAPTION",
    Cin = "CIN",
    Cip = "CIP",
    Clip = "CLIP",
    Cmyk = "CMYK",
    Cmyka = "CMYKA",
    Cr2 = "CR2",
    Cr3 = "CR3",
    ...

Essencialmente, ele lista cerca de 260 formatos, mas não diz quais são permitidos como entrada e quais são permitidos como saída . Tentei converter um PNG para CR2, mas a API wasm falhou com:

Error: NoEncodeDelegateForThisImageFormat `CR2' @ error/constitute.c/WriteImage/1409

Eu sabia que isso iria falhar porque li em algum site aleatório que não me lembro, que CR2 é o formato camera raw da Canon, e eles só podem tomá-lo como entrada e usá-lo para gerar saídas mais simples, como JPG/PNG/etc .. Mas minha pergunta é: quais são exatamente os formatos de entrada e saída permitidos para o ImageMagick? Como posso descobrir isso? Existe uma maneira de listá-los de alguma forma com a API (que eu posso então descobrir para traduzir para a API wasm)? Idealmente, não é um exemplo de CLI, mas um exemplo de API de código-fonte, eu acho.

Todos aqueles incluídos MagickFormatsão permitidos como formatos de entrada? E apenas um subconjunto de formatos de saída? Ou onde posso encontrar quais são permitidos para quais? Ah, e relacionado, depende da entrada qual saída é permitida? (Tipo, é uma matriz do tipo "JPG pode ser convertido em X e Y, mas não em Z, mas PNG pode ser convertido em X e Z, mas não em Y", ou é mais simples do que isso?) Estou parcialmente curioso neste processo, se você tiver que criar uma lista de mapeamentos um-para-muitos para cada tipo de entrada para as saídas possíveis para essa entrada, ou se for mais genérico que isso.

Objetivo principal: descobrir quais operações posso fazer.

Também vi a supportedFormatspropriedade , mas não tenho certeza se isso resolve totalmente o meu problema.

encoding
  • 1 respostas
  • 24 Views
Martin Hope
Lance
Asked: 2023-12-02 19:20:12 +0800 CST

Exemplo de uma consulta GraphQL em que existem vários tipos de filtro diferentes em um único tipo de registro, dependendo de onde ele está localizado na árvore de consulta?

  • 4

Estou pedindo ajuda ao ChatGPT para aprofundar as possibilidades de consulta do GraphQL, enquanto estou brincando em criar uma variante JSON do GraphQL para fins de aprendizagem. Uma coisa que me deixa perplexo há algum tempo é como você pode oferecer suporte a argumentos/parâmetros de entrada de consulta em um nó, mas não em outro do mesmo tipo de nó.

Construindo aquele longo tópico do ChatGPT (que você não precisa ler para esta postagem), digamos que você tenha um tipo de sistema como este:

const resolvers = {
  Query: {
    author: (parent, args) => {
      // Implement logic to fetch an author by ID
    },
    post: (parent, args) => {
      // Implement logic to fetch a post by ID
    },
  },
  Author: {
    posts: (author) => {
      // Implement logic to fetch all posts by this author
    },
  },
  Post: {
    comments: (post) => {
      // Implement logic to fetch all comments for this post
    },
  },
  Comment: {
    author: (comment) => {
      // Implement logic to fetch the author of this comment
    },
  },
};

Estou tentando imaginar uma imagem onde você tenha algo como esta consulta:

query {
  author(id: "1") {
    id
    name
    posts(limit: 10) {
      id
      title
      content
      comments(limit: 10) {
        id
        text
        author {
          id
          name
          posts(createdAtGt: someDate) {
            id
            title
            content
          }
        }
      }
    }
  }
}

Ou algo ainda mais complexo.

Basicamente, vemos aqui que existe Query.authore também Comment.author, então a primeira parte da pergunta é: por que você precisa do Comment.authorescopo, por que não apenas usar o Query.authorescopo? Não é como se estivéssemos criando um Author.posts.comments()escopo; em vez disso, temos um Post.commentsresolvedor de nível superior.

Mas e se tivéssemos uma situação em que (e ainda não consigo encontrar um exemplo simples e claro) você quisesse filtrar de uma maneira as postagens de author.posts, mas de uma maneira completamente diferente comment.author.posts, _e não quisesse permitir a filtragem de postagens em um contexto para serem usadas na consulta GraphQL no outro contexto na árvore de consulta...

Você já se deparou com essa situação?

Basicamente, estou me perguntando por que você escolheria uma direção em vez de outra:

  1. Permitir que apenas 1 tipo de filtragem funcione em todos os nós/registros de um tipo específico.
  2. Ou 2, especifique uma funcionalidade exclusiva de entrada/filtragem em nível por ramificação, de modo que um tipo de registro possa ter 10 mecanismos de filtragem diferentes com base em sua localização na árvore de consulta.

Se (2) acontecer em aplicativos de produção mais complexos, parece que você teria que reimplementar muita lógica básica em vários pontos diferentes nos resolvedores e, em seguida, personalizar onde for necessário. Basicamente me perguntando por que você não criaria um resolvedor mais parecido com este (lembrando que estou pensando em uma alternativa JSON ao GraphQL para fins de aprendizado):

{
  author: {
    resolve(parent, args) {
      // Find author by id
    },
    children: {
      posts: {
        resolve(parent) {
          // find posts by author id, and allow `limit` on the posts query, only here.
        },
        children: {
          comments: {
            resolve(parent) {
              // find comments by post id
            },
            children: {
              author: {
                resolve(parent) {
                  // find author by comment author id
                },
                children: {
                  posts: {
                    resolve(parent) {
                      // find posts by author id, but only allow searching for greater than certain date.
                    }
                  }
                }
              }
            }
          }
        }
      },
      comments: {
        resolve(parent) {
          // now find comments by author id
        },
        children: {
          author: {
            resolve(parent) {
              // maybe here we have different logic and only return authors with a first name starting with "A".
            },
            children: {
              posts: {
                resolve(parent) {
                  // and another variant here too... it can go on more and more custom cases.
                }
              }
            }
          }
        }
      }
    }
  }
}

Algo assim ocorre no mundo do GraphQL? Em caso afirmativo, qual é um exemplo semicomplexo para demonstrar? Se não, por que não?

graphql
  • 1 respostas
  • 27 Views

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Reformatar números, inserindo separadores em posições fixas

    • 6 respostas
  • Marko Smith

    Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não?

    • 2 respostas
  • Marko Smith

    Problema com extensão desinstalada automaticamente do VScode (tema Material)

    • 2 respostas
  • Marko Smith

    Vue 3: Erro na criação "Identificador esperado, mas encontrado 'import'" [duplicado]

    • 1 respostas
  • Marko Smith

    Qual é o propósito de `enum class` com um tipo subjacente especificado, mas sem enumeradores?

    • 1 respostas
  • Marko Smith

    Como faço para corrigir um erro MODULE_NOT_FOUND para um módulo que não importei manualmente?

    • 6 respostas
  • Marko Smith

    `(expression, lvalue) = rvalue` é uma atribuição válida em C ou C++? Por que alguns compiladores aceitam/rejeitam isso?

    • 3 respostas
  • Marko Smith

    Um programa vazio que não faz nada em C++ precisa de um heap de 204 KB, mas não em C

    • 1 respostas
  • Marko Smith

    PowerBI atualmente quebrado com BigQuery: problema de driver Simba com atualização do Windows

    • 2 respostas
  • Marko Smith

    AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos

    • 1 respostas
  • Martin Hope
    Fantastic Mr Fox Somente o tipo copiável não é aceito na implementação std::vector do MSVC 2025-04-23 06:40:49 +0800 CST
  • Martin Hope
    Howard Hinnant Encontre o próximo dia da semana usando o cronógrafo 2025-04-21 08:30:25 +0800 CST
  • Martin Hope
    Fedor O inicializador de membro do construtor pode incluir a inicialização de outro membro? 2025-04-15 01:01:44 +0800 CST
  • Martin Hope
    Petr Filipský Por que os conceitos do C++20 causam erros de restrição cíclica, enquanto o SFINAE antigo não? 2025-03-23 21:39:40 +0800 CST
  • Martin Hope
    Catskul O C++20 mudou para permitir a conversão de `type(&)[N]` de matriz de limites conhecidos para `type(&)[]` de matriz de limites desconhecidos? 2025-03-04 06:57:53 +0800 CST
  • Martin Hope
    Stefan Pochmann Como/por que {2,3,10} e {x,3,10} com x=2 são ordenados de forma diferente? 2025-01-13 23:24:07 +0800 CST
  • Martin Hope
    Chad Feller O ponto e vírgula agora é opcional em condicionais bash com [[ .. ]] na versão 5.2? 2024-10-21 05:50:33 +0800 CST
  • Martin Hope
    Wrench Por que um traço duplo (--) faz com que esta cláusula MariaDB seja avaliada como verdadeira? 2024-05-05 13:37:20 +0800 CST
  • Martin Hope
    Waket Zheng Por que `dict(id=1, **{'id': 2})` às vezes gera `KeyError: 'id'` em vez de um TypeError? 2024-05-04 14:19:19 +0800 CST
  • Martin Hope
    user924 AdMob: MobileAds.initialize() - "java.lang.Integer não pode ser convertido em java.lang.String" para alguns dispositivos 2024-03-20 03:12:31 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help
subwaysurfers
my femboy roommate

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve