#StackBounty: #helm #helm-sources Selecting a file via helm using multiple sources

Bounty: 50

I have a customized find-file that uses helm sources to help load a file into my buffer. Now, however, I would like to be able to select a file using the same algorithm and store that filename into a variable.

I can use helm-read-file-nameto select a file, but it doesn’t use any of the fancy sources or indeed anything very different from standard emacs read-file-name.

How can I get helm-read-file-name to use sources, or alternatively, use the helm function with a different action that will store the match (or matches) into a variable so I can access them?

I’ve included some code showing what I would like to conceptually have happen (providing a list of sources that helm-read-file-name might use to generate a filename to select).

(setq mhfile
    (helm-read-file-name "Attachment: " :sources '(helm-source-recentf
         helm-source-locate
         helm-source-findutils
         helm-source-buffers-list)))

Obviously I’m going down the wrong path, but I can’t figure out a way to override the default action that helm uses either.


Get this bounty!!!

#StackBounty: #regression #experiment-design Get estimates about 'variable importance' across a large number of variables and t…

Bounty: 50

My client would like to know which, of many different kinds of product dimensions, are most important for perceived quality. Some of the dimensions are as follows: price, material, country of origin, whether or not your colleagues/friends have the product, and so on. Most of these dimensions include many levels (price, for example, can be from $1 – $1000; material can include steel, plastic, and so on; country of origin includes 10 possible countries).

We want to be able to answer general questions like: which of these factors are most important in predicting customer appraisals of quality? My client has created a survey in which a random sample of, say, three of these variables are shown to a customer (e.g. a 100 dollar, plastic, widget from China; a 500 dollar metal drum from Cambodia, etc.), and the customer rates how high they perceive the quality to be.

Coming from an econometric background, it’s not clear how to answer this kind of question using my normal tools. There seems to be an enormous number of combinations of variables, and the potential for countless interaction effects seems overwhelming to interpret.

I’ve come across literature on conjoint analysis and taguchi methods, which seem relevant, but it’s not clear how to actually design and implement a study on this topic using those methods. And it’s not clear how to use regression in this context.

Random forests with variable importance seems promising, but it’s not clear how to recover regression-esque effect sizes from forests, nor is it clear how to get a sense of which interactions are most relevant.

Perhaps some kind of Lasso regression? Would I fully specify all the interactions, and run a Lasso procedure? I’m worried it may select non-sensical interactions.

Apologies if the question is non-specified. I’d like to be able to say, “If your product is coming from China, characteristics X, Y, Z are most important. If you are selling a plastic tool, characteristics A, B, C, are most important.”


Get this bounty!!!

#StackBounty: #functional-programming #event-handling #react.js #typescript Emulation of SE's text input control for tags

Bounty: 500

Introduction

I used React to write a component, which is meant to be a faithful emulation of the input for “Tags” which you see at the top of every question/topic on SE.

Why this project?

If you’re wondering why I did that, it was because (apart from a chance it might eventually become useful as a live product), it’s an example of a data-driven or user-defined content — not just static HTML pages — for which e.g. React might be a useful and relatively modern development tool.

I wanted to learn React, and to verify that I had learned it. This seemed a suitable project:

  • Big enough to be interesting
  • Small enough to be feasible
  • The UI design is well-specified (i.e. evident or documented, can be inspected in every detail), so I could concentrate on implementing the UI and not on designing it.

So far as I know there have been at least a couple of dozen SE clones written over the years — none of which I’ve looked at, and for all I know none using React.

Why this component?

I chose this component for review, as opposed to other source files in the project, for two reasons:

  • I found this the most difficult to implement — it surprised me how much code it needed — and I don’t see an obvious way to refactor it to improve its readability or maintainability
  • I know I took some liberties in the other components — e.g. writing some perhaps-overly-clever hooks, and several functions that aren’t “function components” — if I were reviewing those I suppose I’d find them easy to comment on. But this component is as orthodox as I could make it.

What?

“It’s an emulation of the tag editor” defines the the functional spec — or see also the “Appearance and behaviour” section at the top of the component’s README included below.

The UI output looks e.g. like this when styled:

enter image description here

If you’d like to try/exercise it, it’s running here : https://react-forum2.herokuapp.com/discussions/new

EditorTags.tsx

Here is the source code for review.

I find it hard to read here, with scrollbars — you may prefer to read it on GitHub.

import React from 'react';
import './EditorTags.css';
// this is to display a little 'x' SVG -- a Close icon which is displayed on each tag -- clicking it will delete the tag
// also to display a little '(!)' SVG -- an Error icon which is displayed in the element, if there's a validation error
import * as Icon from "../icons";
// this simply displays red text if non-empty text is passed to its errorMessage property
import { ErrorMessage } from './ErrorMessage';

// these are the properties of an existing tag, used or displayed by the TagDictionary
interface TagCount {
  key: string,
  summary?: string,
  count: number
}

// these are properties to configurare the validation of tags
interface Validation {
  // whether a minimum number of tags must be defined, e.g. 1
  minimum: boolean,
  // whether a maximum number of tags must be defined, e.g. 5
  maximum: boolean,
  // whether the user can create new tags, or whether tags must match what's already in the dictionary
  canNewTag: boolean,
  // whether the show validation error messages -- they're hidden until the user first presses the form's submit button
  showValidationError: boolean,
  // the href used for the link to "popular tags" in the validation error message -- i.e. "/tags"
  hrefAllTags: string
}

// the results are pushed back to the parent via this callback
export interface OutputTags { tags: string[], isValid: boolean };
type ParentCallback = (outputTags: OutputTags) => void;

// this defines the properties which you pass to the EditorTags functional component
interface EditorTagsProps extends Validation {
  // the input/original tags to be edited (or an empty array if there are none)
  inputTags: string[],
  // the results are pushed back to the parent via this callback
  result: ParentCallback,
  // a function to fetch all existing tags from the server (for tag dictionary lookup)
  getAllTags: () => Promise<TagCount[]>
};

/*
  This source file is long and has the following sections -- see also [EditorTags](./EDITORTAGS.md)

  # Defined outside the React function component:

  - All the type definitions
    - Assert
    - ParentCallback
    - Context
    - State
    - RenderedElement
    - RenderedState
    - InputElement
    - InputState
    - MutableState
    - TagDictionary

  - The reducer
    - action types
    - reducer

  - Various helper functions
    - stringSplice
    - log and logRenderedState
    - getInputIndex
    - getElementStart and getWordStart
    - assertElements and assertWords
    - getTextWidth
    - handleFocus

  - Functions which construct the RenderedState
    - renderState
    - initialState

  # Defined inside the React function component:

  - React hooks
    - errorMessage
    - assert (a function which uses errorMessage and is required by initialState)
    - state 

  - inputRef (data which is used by some of the event handlers)

  - Event handlers (which dispatch to the reducer)
    - getContext
    - handleEditorClick
    - handleDeleteTag
    - handleTagClick
    - handleChange
    - handleKeyDown
    - handleHintResult

  - Tag is a FunctionComponent to render each tag

  - The return statement which yields the JSX.Element from this function component

  # Other function components to display the drop-down hints

  - ShowHints
  - ShowHint
*/

// you could temporarily change this to enable logging, for debugging
const isLogging = false;

/*
  All the type definitions
*/

type Assert = (assertion: boolean, message: string, extra?: () => object) => void;

// this is extra data which event handlers pass (as part of the action) from the function component to the reducer
interface Context {
  inputElement: InputElement;
  assert: Assert;
  result: ParentCallback;
  tagDictionary?: TagDictionary;
  validation: Validation;
};

// this is like the input data from which the RenderedState is calculated
// these and other state elements are readonly so that event handlers must mutate MutableState instead
interface State {
  // the selection range within the buffer
  // this may even span multiple words, in which case all the selected words are in the <input> element
  readonly selection: { readonly start: number, readonly end: number },
  // the words (i.e. the tags when this is split on whitespace)
  readonly buffer: string
};

// this interface identifies the array of <input> and <Tag> elements to be rendered, and the word associated with each
interface RenderedElement {
  // the string value of this word
  readonly word: string;
  // whether this word is rendered by a Tag element or by the one input element
  readonly type: "tag" | "input";
  // whether this word matches an existing tag in the dictionary
  readonly isValid: boolean;
};

// this interface combines the two states, and is what's stored using useReducer
interface RenderedState {
  // the buffer which contains the tag-words, and the selection within the buffer
  readonly state: State;
  // how that's rendered i.e. the <input> element plus <Tag> elements
  readonly elements: ReadonlyArray<RenderedElement>;
  // the current ("semi-controlled") value of the <input> element
  readonly inputValue: string;
  // the hints associated with the inputValue, taken from the TagDictionary
  hints: TagCount[];
  // the validation error message (zero length if there isn't one)
  validationError: string;
}

// this wraps the current state of the <input> control
class InputElement {
  readonly selectionStart: number;
  readonly selectionEnd: number;
  readonly isDirectionBackward: boolean;
  readonly value: string;
  readonly isLeftTrimmed: boolean;
  private readonly inputElement: HTMLInputElement;

  constructor(inputElement: HTMLInputElement, assert: Assert, stateValue?: string) {

    let { selectionStart, selectionEnd, selectionDirection, value } = inputElement;
    log("getInput", { selectionStart, selectionEnd, selectionDirection, value });

    assert(!stateValue || stateValue === value, "stateValue !== value");

    // TypeScript declaration says these may be null, though I haven't seen that in practice?
    if (selectionStart === null) {
      assert(false, "unexpected null selectionStart");
      selectionStart = 0;
    }
    if (selectionEnd === null) {
      assert(false, "unexpected null selectionEnd");
      selectionEnd = 0;
    }
    if (selectionStart > selectionEnd) {
      assert(false, "unexpected selectionStart > selectionEnd");
      selectionStart = 0;
    }
    // left trim if the user entered leading spaces
    let isLeftTrimmed = false;
    while (value.length && value[0] === " ") {
      value = value.substring(1);
      --selectionStart;
      --selectionEnd;
      isLeftTrimmed = true;
    }

    this.selectionStart = selectionStart;
    this.selectionEnd = selectionEnd;
    this.isDirectionBackward = selectionDirection === "backward";
    this.value = value;
    this.isLeftTrimmed = isLeftTrimmed;
    this.inputElement = inputElement;
  }

  focus(): void {
    this.inputElement.focus();
  }

  setContent(value: string, start: number, end: number): void {
    // set the value before the selection, otherwise the selection might be invalid
    this.inputElement.value = value;
    this.inputElement.setSelectionRange(start, end);
    // dynammically readjust the width of the input element to match its content
    const width = getTextWidth(value + "0");
    this.inputElement.style.width = `${width}px`;
  }

  toJSON(): string {
    // JSON.stringify cannot handle `inputElement: HTMLInputElement` so the purpose of this is to exclude that
    const printable: string[] = [
      `start: ${this.selectionEnd}`,
      `end: ${this.selectionEnd}`,
      `backward: ${this.isDirectionBackward}`,
      `value: ${this.value}`
    ];
    return printable.join(", ");
  }
}

// this combines the state of the <input> control with the position of the <input> within the RenderedState
// it exists only to help the KeyDown event handlers determine whether keys like ArrowLeft will change the selected word
// beware that, when this runs, the <input> control's value may not yet have been written to the elements[editing].word
class InputState {
  readonly canMoveLeft: boolean;
  readonly canMoveRight: boolean;
  readonly currentStart: number;
  readonly currentEnd: number;
  get nextLeft(): number { return this.currentStart - 1; }
  get nextRight(): number { return this.currentEnd + 1; }

  constructor(state: RenderedState, inputElement: InputElement, assert: Assert) {
    const { elements } = state;
    const { inputIndex, isFirst, isLast } = getInputIndex(elements, assert);
    const elementStart = getElementStart(elements, inputIndex, assert);

    const { selectionStart, selectionEnd, isDirectionBackward, value } = inputElement;

    // if a range is selected then which end of the range is moving?
    const isLeftMoving = (selectionStart === selectionEnd) || isDirectionBackward;
    const isRightMoving = (selectionStart === selectionEnd) || !isDirectionBackward;

    // can move left if at the start of the <input> and if there are other <Tag> elements before the <input> element
    this.canMoveLeft = selectionStart === 0 && !isFirst && isLeftMoving;
    // can move right if at the end of the <input> and if there are other <Tag> elements after the <input> element
    this.canMoveRight = selectionEnd === value.length && !isLast && isRightMoving;

    this.currentStart = elementStart + selectionStart;
    this.currentEnd = elementStart + selectionEnd;
  }

  removeSelected(mutableState: MutableState): void {
    mutableState.remove(this.currentStart, this.currentEnd);
  }
}

// this is a class which event-handlers use to mutate the current state
// its methods are whatever primitive methods are required by the event handlers which use it
// it's contructed from the previous RenderedState, then mutated, and then eventually returns the new RenderedState
class MutableState {
  private selection: { start: number, end: number };
  private buffer: string;
  // store the elements as word because until the mutation stops we don't know which will be the input element
  // e.g. what's currently current input element may be deleted and/or the input may be moved to a different word
  private words: string[];
  private context: Context;

  constructor(renderedState: RenderedState, context: Context) {
    // load the data from the previous state into non-readonly elements
    const { state, elements } = renderedState;
    this.selection = state.selection;
    this.buffer = state.buffer;
    this.words = elements.map(x => x.word); // use concat with no parameters to convert from ReadonlyArray to []
    this.context = context;

    // stash the input -- i.e. update the buffered data to reflect whatever is currently in the <input> element
    const { inputIndex } = getInputIndex(elements, context.assert);
    const { value, selectionStart, selectionEnd } = context.inputElement;
    this.replaceElement(inputIndex, value, { start: selectionStart, end: selectionEnd });
    log("MutableState", { selection: this.selection, buffer: this.buffer, words: this.words });
  }

  // called when the event handler has finished mutating this MutableState
  getState(): RenderedState {
    const state: State = { buffer: this.buffer, selection: this.selection };
    const { assert, inputElement, tagDictionary, validation } = this.context;
    const renderedState: RenderedState = renderState(state, assert, validation, inputElement, tagDictionary);
    logRenderedState("MutableState.getState returning", renderedState);
    // do a callback to the parent to say what the current tags are (excluding the empty <input> word if there is one)
    const tags: string[] = renderedState.elements.map(element => element.word).filter(word => !!word.length);
    const isValid = !renderedState.validationError.length;
    this.context.result({ tags, isValid });
    return renderedState;
  }

  replaceElement(index: number, newValue: string, selection?: { start: number, end: number }): void {
    this.invariant();

    const editingWord: string = this.words[index];
    // a special case is when the input element is empty and the last word -- then it's beyond the end of the buffer
    const nWords = this.words.length - ((this.words[this.words.length - 1] === "") ? 1 : 0);

    // if the new word matches the existing word then the replace will do nothing
    if (editingWord === newValue) {
      return;
    }
    const wordStart = getWordStart(this.words, index, this.context.assert);

    // possibly insert or delete whitespace before or after the word being added or deleted

    // if we delete the whole word and this isn't the last word then also delete the space after this word
    const deleteSpaceAfter = newValue === "" && index < nWords - 1;
    if (deleteSpaceAfter) {
      this.assertSpaceAt(wordStart + editingWord.length);
    }
    // if we delete the last word then delete the space before it
    const deleteSpaceBefore = newValue === "" && index === nWords - 1 && index !== 0;
    if (deleteSpaceBefore) {
      this.assertSpaceAt(wordStart - 1);
    }
    // if we add another word beyond a previous word (i.e. beyond the end of the buffer) then insert the space before it
    const addSpaceBefore = (wordStart === this.atBufferEnd()) && index;
    if (addSpaceBefore) {
      // assert this word was previously empty and is being changed to non-empty
      this.context.assert(!editingWord.length && !!newValue.length, "unexpected at end of buffer");
    }

    log("replaceElement", { deleteSpaceAfter, deleteSpaceBefore, addSpaceBefore });
    // calculate the deleteCount, and adjust deleteCount and/or wordStart and/or newValue, to insert or delete spaces

    const deleteCount: number = editingWord.length + (deleteSpaceAfter || deleteSpaceBefore ? 1 : 0);
    const spliceStart: number = (deleteSpaceBefore || addSpaceBefore) ? wordStart - 1 : wordStart;
    const spliceValue: string = (!addSpaceBefore) ? newValue : " " + newValue;

    // mutate the buffer
    this.buffer = stringSplice(this.buffer, spliceStart, deleteCount, spliceValue);
    // mutate the word in the elements array
    if (newValue.length) {
      this.words[index] = newValue;
    } else {
      this.words.splice(index, 1);
    }

    // adjust the selected range after mutating the text
    if (selection) {
      // called from constructor where new selection is taken from the <input> element
      const wordStart = getWordStart(this.words, index, this.context.assert);
      this.selection.start = selection.start + wordStart;
      this.selection.end = selection.end + wordStart;
    } else {
      // called from onDeleteTag where existing selection must be adjusted to account for the deleted element
      if (this.selection.start > wordStart) {
        this.selection.start -= deleteCount;
      }
      if (this.selection.end > wordStart) {
        this.selection.end -= deleteCount;
      }
    }
    this.invariant();
  }

  private invariant() {
    // we mutate the state but because we make several mutations this asserts that the state remains sane or predictable
    assertWords(this.words, this.buffer, this.context.assert);
  }
  private assertSpaceAt(index: number) {
    this.context.assert(this.buffer.substring(index, index + 1) === " ", "expected a space at this location");
  }

  remove(start: number, deleteCount: number): void {
    this.buffer = stringSplice(this.buffer, start, deleteCount, "");
  }

  // the start and end of the selection range are usually the same
  setSelectionBoth(where: number): void {
    this.selection.start = where;
    this.selection.end = where;
  }
  setSelectionStart(where: number): void {
    this.selection.start = where;
  }
  setSelectionEnd(where: number): void {
    this.selection.end = where;
  }
  // the location of the selection index beyond the end of the buffer (starting the empty, to-be-defined next tag)
  atBufferEnd(): number {
    return (this.buffer.length) ? this.buffer.length + 1 : 0;
  }

  selectEndOf(index: number) {
    const wordStart = getWordStart(this.words, index, this.context.assert);
    this.setSelectionBoth(wordStart + this.words[index].length);
  }
  focus() {
    this.context.inputElement.focus();
  }
};

// we want to display a maximum of 6 hints
const maxHints = 6;

// this is a class to lookup hints for existing tags which match the current input value
class TagDictionary {
  // the current implementation repeatedly iterates the whole dictionary
  // if that's slow (because the dictionary is large) in future we could partition the dictionary by letter
  private readonly tags: TagCount[];
  constructor(tags: TagCount[]) {
    this.tags = tags;
  }
  getHints(inputValue: string, elements: RenderedElement[]): TagCount[] {
    if (!inputValue.length) {
      return [];
    }
    // don't want what we already have i.e. what matches other tags
    const unwanted: string[] = elements.filter(x => x.type === "tag").map(x => x.word);
    // we'll select tags in the following priority:
    // 1. Tags where the inputValue matches the beginning of the tag
    // 2. If #1 returns too many tags, then prefer tags with a higher count because they're the more popular/more likely
    // 3. If #1 doesn't return enough tags, then find tags where the inputValue matches within the tag
    // 4. If #3 returns too many tags, then prefer tags with a higher count
    const findTags = (start: boolean, max: number): TagCount[] => {
      const found = (this.tags.filter(tag => start
        ? tag.key.startsWith(inputValue)
        : tag.key.substring(1).includes(inputValue))).filter(x => !unwanted.includes(x.key));
      // higher counts first, else alphabetic
      found.sort((x, y) => (x.count === y.count) ? x.key.localeCompare(y.key) : y.count - x.count);
      return found.slice(0, max);
    }
    const found = findTags(true, maxHints);
    return (found.length === maxHints) ? found : found.concat(findTags(false, maxHints - found.length));
  }
  exists(inputValue: string): boolean {
    return this.tags.some(tag => tag.key === inputValue);
  }
  toJSON(): string {
    // not worth logging all the elements
    return `${this.tags.length} elements`;
  }
}

/*
  The reducer
*/

interface ActionEditorClick { type: "EditorClick", context: Context };
interface ActionHintResult { type: "HintResult", context: Context, hint: string, inputIndex: number };
interface ActionDeleteTag { type: "DeleteTag", context: Context, index: number };
interface ActionTagClick { type: "TagClick", context: Context, index: number };
interface ActionKeyDown { type: "KeyDown", context: Context, key: string, shiftKey: boolean };
interface ActionChange { type: "Change", context: Context };

type Action = ActionEditorClick | ActionHintResult | ActionDeleteTag | ActionTagClick | ActionKeyDown | ActionChange;

function isEditorClick(action: Action): action is ActionEditorClick { return action.type === "EditorClick"; }
function isHintResult(action: Action): action is ActionHintResult { return action.type === "HintResult"; }
function isDeleteTag(action: Action): action is ActionDeleteTag { return action.type === "DeleteTag"; }
function isTagClick(action: Action): action is ActionTagClick { return action.type === "TagClick"; }
function isKeyDown(action: Action): action is ActionKeyDown { return action.type === "KeyDown"; }
function isChange(action: Action): action is ActionChange { return action.type === "Change"; }

function reducer(state: RenderedState, action: Action): RenderedState {

  log("reducer", action);
  const inputElement = action.context.inputElement;

  // this function returns a MutableState instance, which is based on the previous state plus the passed-in context
  // the passed-in context includes the new content of the <input> element
  function getMutableState(): MutableState {
    logRenderedState("getMutableState", state);
    return new MutableState(state, action.context);
  }
  // this function returns a InputState instance
  function getInputState(): InputState {
    return new InputState(state, inputElement, action.context.assert);
  }

  if (isChange(action)) {
    const mutableState: MutableState = getMutableState();
    return mutableState.getState();
  }

  if (isEditorClick(action)) {
    // click on the 
=> set focus on the within the
inputElement.focus(); const mutableState: MutableState = getMutableState(); mutableState.setSelectionBoth(mutableState.atBufferEnd()); return mutableState.getState(); } if (isHintResult(action)) { // click on a hint => set focus on the inputElement.focus(); const mutableState: MutableState = getMutableState(); mutableState.replaceElement(action.inputIndex, action.hint); mutableState.setSelectionBoth(mutableState.atBufferEnd()); return mutableState.getState(); } if (isDeleteTag(action)) { const mutableState: MutableState = getMutableState(); mutableState.replaceElement(action.index, ""); return mutableState.getState(); } if (isTagClick(action)) { const mutableState: MutableState = getMutableState(); // want to position the cursor at the end of the selected word mutableState.selectEndOf(action.index); // clicking on the tag made the input lose the focus mutableState.focus(); return mutableState.getState(); } if (isKeyDown(action)) { const { key, shiftKey } = action; switch (key) { case "Home": case "ArrowUp": { // move selection to start of first tag const mutableState: MutableState = getMutableState(); mutableState.setSelectionBoth(0); return mutableState.getState(); } case "End": case "ArrowDown": { // move selection to end of last tag const mutableState: MutableState = getMutableState(); mutableState.setSelectionBoth(mutableState.atBufferEnd()); return mutableState.getState(); } case "ArrowLeft": { const inputState: InputState = getInputState(); // we're at the left of the input so traverse into the previous tag const mutableState: MutableState = getMutableState(); const wanted = inputState.nextLeft; if (shiftKey) { mutableState.setSelectionStart(wanted); } else { mutableState.setSelectionBoth(wanted); } return mutableState.getState(); } case "ArrowRight": { const inputState: InputState = getInputState(); // we're at the right of the input so traverse into the next tag const mutableState: MutableState = getMutableState(); const wanted = inputState.nextRight; if (shiftKey) { mutableState.setSelectionEnd(wanted); } else { mutableState.setSelectionBoth(wanted); } return mutableState.getState(); } case "Backspace": { // same as ArrowLeft except also delete the space between the two tags const inputState: InputState = getInputState(); const mutableState: MutableState = getMutableState(); if (shiftKey) { // also delete whatever is selected inputState.removeSelected(mutableState); } const wanted = inputState.nextLeft; mutableState.remove(wanted, 1); mutableState.setSelectionBoth(wanted); return mutableState.getState(); } case "Delete": { // same as ArrowRight except also delete the space between the two tags const inputState: InputState = getInputState(); const mutableState: MutableState = getMutableState(); if (shiftKey) { // also delete whatever is selected inputState.removeSelected(mutableState); } const wanted = inputState.currentStart; mutableState.remove(wanted, 1); mutableState.setSelectionBoth(wanted); return mutableState.getState(); } default: break; } // switch } // if isKeyDown logRenderedState("reducer returning old state", state); return state; } // reducer /* Various helper functions */ // Helper function analogous to Array.splice -- string has built-in slice but no splice // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice function stringSplice(text: string, start: number, deleteCount: number, insert: string): string { // up to but not including start const textStart = text.substring(0, start); const textEnd = text.substring(start + deleteCount); const after = textStart + insert + textEnd; log("stringSplice", { text, start, deleteCount, insert, after }); return after; } function log(title: string, o: object, force?: boolean): void { if (!isLogging && !force) { return; } const json = JSON.stringify(o, null, 2); console.log(`${title} -- ${json}`); } function logRenderedState(title: string, renderedState: RenderedState): void { log(title, renderedState); } // this identifies the index of the one-and-only element within the array of RenderedElement function getInputIndex(elements: ReadonlyArray, assert: Assert) : { inputIndex: number, isFirst: boolean, isLast: boolean } { let inputIndex: number = 0; let counted = 0; for (let i = 0; i or ReadonlyArray // that's because the MutableState class works with ReadonlyArray instead of ReadonlyArray // because it doesn't yet know the type associated with each word // Helper function to determine the offset into the buffer associated with a given RenderedElement function getElementStart(elements: ReadonlyArray, index: number, assert: Assert): number { return getWordStart(elements.map(x => x.word), index, assert); } function getWordStart(words: ReadonlyArray, index: number, assert: Assert): number { let wordStart = 0; for (let i = 0; i element is beyond the end of the buffer // that wouldn't trigger this assertion because we're only testing for all i , buffer: string, assert: Assert): void { assertWords(elements.map(x => x.word), buffer, assert); getInputIndex(elements, assert); elements.forEach((element, index) => assert(!!element.word.length || (element.type === "input" && index === elements.length - 1), "unexpected zero-length word")); } function assertWords(words: ReadonlyArray, buffer: string, assert: Assert): void { for (let i = 0; i { return { word, fragment, wordStart, length: word.length, buffer, words } }); } } function getTextWidth(text: string) { // https://stackoverflow.com/a/21015393/49942 const getContext = (): CanvasRenderingContext2D | undefined => { if (!(getTextWidth as any).canvas) { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); if (!context) { return undefined; } // matches the font famly and size defined in App.css context.font = '14px Arial, "Helvetica Neue", Helvetica, sans-serif'; (getTextWidth as any).canvas = canvas; (getTextWidth as any).context = context; } return ((getTextWidth as any).context) as CanvasRenderingContext2D; } const context = getContext(); if (!context) { return 20; } return context.measureText(text).width; } // see [Simulating `:focus-within`](./EDITORTAGS.md#simulating-focus-within) function handleFocus(e: React.FocusEvent, hasFocus: boolean) { function isElement(related: EventTarget | HTMLElement): related is HTMLElement { return (related as HTMLElement).tagName !== undefined; } // read it const target = e.target; const relatedTarget = e.relatedTarget; // relatedTarget is of type EventTarget -- upcast from that to HTMLElement const related: HTMLElement | undefined = (relatedTarget && isElement(relatedTarget)) ? relatedTarget : undefined; // get the tagName and className of the element const relatedName = (!relatedTarget) ? "!target" : (!related) ? "!element" : related.tagName; const relatedClass = (!related) ? "" : related.className; // log it const activeElement = document.activeElement; const targetName = target.tagName; const activeElementName = (activeElement) ? activeElement.tagName : "!activeElement"; log("handleFocus", { hasFocus, targetName, activeElementName, relatedName, relatedClass }); // calculate it hasFocus = hasFocus || (relatedClass === "hint"); // write the result const div = document.getElementById("tag-both")!; if (hasFocus) { div.className = "focussed"; } else { div.className = ""; } } /* Functions which construct the RenderedState */ // this function calculates a new RenderedState and sets the InputElement content and selection, for a given State value // it's called from initialState and from MutableState function renderState(state: State, assert: Assert, validation: Validation, inputElement?: InputElement, tagDictionary?: TagDictionary) : RenderedState { const elements: RenderedElement[] = []; let editing: number | undefined = undefined; let inputValue: string = ""; function setInput(text: string, start: number, end: number, inputElement: InputElement): void { log("setInput", { text, start, end }); inputElement.setContent(text, start, end); inputValue = text; assert(start >= 0 && end word.length); const selection = state.selection; // this is where each word starts, an index into the buffer let wordStart = 0; // this accumulates previous words within the selection, when selection is a range which spans more than one word let accumulated: { wordStart: number, start: number, text: string } | undefined = undefined; for (let wordIndex = 0; wordIndex wordEnd) || (selection.end = wordStart) { // selection starts in this word if (selection.end element yet, so push it now editing = elements.length; // if (initializing) then the `input` and `inputRef` values haven't yet been created because the state is created // before they are, via the call to initialState -- but when it is created it's initially empty so that's alright if (inputElement) { // the element is already part of the DOM; reset it now setInput("", 0, 0, inputElement); } addElement("input", ""); } assertElements(elements, state.buffer, assert); const hints: TagCount[] = !tagDictionary ? [] : tagDictionary.getHints(inputValue, elements); // if logging only log the keyword of each hint, otherwise logging the tags' summaries makes it long and hard to read (hints as any).toJSON = () => "[" + hints.map(hint => hint.key).join(",") + "]"; function getValidationError(): string { const nWords: number = elements.filter(element => !!element.word.length).length; const invalid: string[] = elements.filter(element => !element.isValid).map(element => element.word); if (nWords 5 && validation.maximum) { return "Please enter a maximum of five tags."; } if (!!invalid.length) { return (invalid.length === 1) ? `Tag '${invalid[0]}' does not match an existing topic.` : `Tags ${invalid.map(word => "'" + word + "'").join(" and ")} do not match existing topics.` } return ""; } const validationError = getValidationError(); const renderedState: RenderedState = { state, elements, inputValue, hints, validationError }; return renderedState; } // this function calculates the initial state, calculated from props and used to initialize useState function initialState(assert: Assert, inputTags: string[], validation: Validation): RenderedState { assert(!inputTags.some(found => found !== found.trim()), "input tags not trimmed", () => { return { inputTags }; }); const buffer = inputTags.join(" "); const start = buffer.length + 1; const state: State = { buffer, selection: { start, end: start } }; log("initialState starting", { inputTags }) const renderedState: RenderedState = renderState(state, assert, validation); logRenderedState("initialState returning", renderedState) return renderedState; } /* EditorTags -- the functional component */ export const EditorTags: React.FunctionComponent = (props) => { const { inputTags, result, getAllTags } = props; const validation: Validation = props; /* React hooks */ // this is an optional error message const [errorMessage, setErrorMessage] = React.useState(undefined); function assert(assertion: boolean, message: string, extra?: () => object): void { if (!assertion) { if (extra) { const o: object = extra(); const json = JSON.stringify(o, null, 2); message = `${message} -- ${json}`; } // write to errorMessage state means it's displayed by the `` element setTimeout(() => { // do it after a timeout because otherwise if we do this during a render then React will complain with: // "Too many re-renders. React limits the number of renders to prevent an infinite loop." setErrorMessage(message); }, 0); console.error(message); } } // see ./EDITOR.md and the definition of the RenderedState interface for a description of this state // also https://fettblog.eu/typescript-react/hooks/#usereducer says that type is infered from signature of reducer const [state, dispatch] = React.useReducer(reducer, inputTags, (inputTags) => initialState(assert, inputTags, validation)); // this is a dictionary of existing tags const [tagDictionary, setTagDictionary] = React.useState(undefined); logRenderedState("--RENDERING--", state); // useEffect to fetch all the tags from the server exactly once // React's elint rules demand that getAllTags be specified in the deps array, but the value of getAllTags // (which we're being passed as a parameter) is utimately a function at module scope, so it won't vary React.useEffect(() => { // get tags from server getAllTags() .then((tags) => { // use them to contruct a dictionary const tagDictionary: TagDictionary = new TagDictionary(tags); // save the dictionary in state setTagDictionary(tagDictionary); }) .catch((reason) => { // alarm the user setErrorMessage(`getAllTags() failed -- ${reason}`); }); }, [getAllTags]); /* inputRef (data which is used by some of the event handlers) */ const inputRef = React.createRef(); /* Event handlers (which dispatch to the reducer) */ function getContext(inputElement: HTMLInputElement): Context { return { inputElement: new InputElement(inputElement, assert), assert, result, tagDictionary, validation }; } function handleEditorClick(e: React.MouseEvent) { const isDiv = (e.target as HTMLElement).tagName === "DIV"; if (!isDiv) { // this wasn't a click on the
itself, presumably instead a click on something inside the div return; } dispatch({ type: "EditorClick", context: getContext(inputRef.current!) }); } function handleDeleteTag(index: number, e: React.MouseEvent) { dispatch({ type: "DeleteTag", context: getContext(inputRef.current!), index }); e.preventDefault(); } function handleTagClick(index: number, e: React.MouseEvent) { dispatch({ type: "TagClick", context: getContext(inputRef.current!), index }); e.preventDefault(); } function handleChange(e: React.ChangeEvent) { dispatch({ type: "Change", context: getContext(e.target) }); } function handleKeyDown(e: React.KeyboardEvent) { if (e.key === "Enter") { // do nothing and prevent form submission e.preventDefault(); return; } // apparently dispatch calls the reducer asynchonously, i.e. after this event handler returns, which will be too // late to call e.preventDefault(), and so we need two-stage processing, i.e. some here and some inside the reducer: // - here we need to test whether the action will or should be handled within the reducer // - later in the reducer we need to actually perform the action function newinputState() { const inputElement: InputElement = new InputElement(e.target as HTMLInputElement, assert); return new InputState(state, inputElement, assert); } function isHandled(): boolean { switch (e.key) { case "Home": case "ArrowUp": // move selection to start of first tag return !getInputIndex(state.elements, assert).isFirst; case "End": case "ArrowDown": // move selection to end of last tag return !getInputIndex(state.elements, assert).isLast; case "ArrowLeft": case "Backspace": { const inputState: InputState = newinputState(); return inputState.canMoveLeft; } case "ArrowRight": case "Delete": { const inputState: InputState = newinputState(); return inputState.canMoveRight; } default: break; } // switch return false; } if (isHandled()) { e.preventDefault(); const context: Context = getContext(e.target as HTMLInputElement); dispatch({ type: "KeyDown", context, key: e.key, shiftKey: e.shiftKey }); } } function handleHintResult(outputTag: string) { const { inputIndex } = getInputIndex(state.elements, assert); dispatch({ type: "HintResult", context: getContext(inputRef.current!), hint: outputTag, inputIndex }); } /* Tag is a FunctionComponent to render each tag */ interface TagProps { text: string, index: number, isValid: boolean }; const Tag: React.FunctionComponent = (props) => { const { text, index, isValid } = props; // https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers // eslint-disable-next-line const close = handleDeleteTag(index, e)} title="Remove tag">; const className = isValid ? "tag" : "tag invalid"; return handleTagClick(index, e)}> {text} {close} } /* The return statement which yields the JSX.Element from this function component */ function showValidationResult() { const showError = props.showValidationError && !!state.validationError.length; if (!showError) { return { className: "tag-editor", icon: undefined, validationError: undefined }; } const className = "tag-editor invalid validated"; const icon = ; const validationErrorMessage = state.validationError; // use instead of -- https://github.com/ReactTraining/react-router/issues/6344 const suffix = (validationErrorMessage[validationErrorMessage.length - 1] !== ";") ? undefined : ( {"see a list of "} popular tags{"."} ); const validationError = {validationErrorMessage} {suffix}

; return { validationError, icon, className }; } const { validationError, icon, className } = showValidationResult(); function getElement(element: RenderedElement, index: number): React.ReactElement { const isValid = !props.showValidationError || element.isValid; return (element.type === "tag") ? : handleFocus(e, true)} onBlur={e => handleFocus(e, false)} /> } return (
{state.elements.map(getElement)} {icon}
<ShowHints hints={state.hints} inputValue={state.inputValue} result={handleHintResult} /> <ErrorMessage errorMessage={errorMessage} /> {validationError} </div> ); } /* ShowHints */ interface ShowHintsProps { // hints (from dictionary) hints: TagCount[], // the current value of the tag in the editor inputValue: string, // callback of tag selected from list of hints if user clicks on it result: (outputTag: string) => void } const ShowHints: React.FunctionComponent<ShowHintsProps> = (props) => { const { hints, inputValue, result } = props; if (!inputValue.length) { return
; } return (
{!hints.length ? "No results found." : hints.map(hint => )}
); } interface ShowHintProps { // hints (from dictionary) hint: TagCount, // the current value of the tag in the editor inputValue: string, // callback of tag selected from list of hints if user clicks on it result: (outputTag: string) => void } const ShowHint: React.FunctionComponent<ShowHintProps> = (props) => { const { hint, inputValue, result } = props; function getTag(key: string) { const index = key.indexOf(inputValue); return ( <span className="tag"> {(index === -1) ? key : <React.Fragment> {key.substring(0, index)} <span className="match">{inputValue}</span> {key.substring(index + inputValue.length)} </React.Fragment>} </span> ); } // the key with the matched letters highlighted const tag = getTag(hint.key); // count the number of times this tag is used elsewhere, if any const count = (hint.count) ? <span className="multiplier">×&nbsp;{hint.count}</span> : undefined; // the summary, if any const summary = (hint.summary) ? <p>{hint.summary}</p> : undefined; // a link to more info i.e. the page which defines this tag function getMore(key: string) { const icon = <Icon.Info width="16" height="16" />; // we use <a> here instead of <Link> because this link will open a whole new tab, i.e. another instance of this SPA // in future I think it would be better to reimplement this as a split screen (two-column) view const anchor = <a href={`/tags/${key}/info`} target="_blank" rel="noopener noreferrer">{icon}</a>; return <p className="more-info">{anchor}</p>; } const more = getMore(hint.key); return (
result(hint.key)} onKeyDown={e => { if (e.key === "Enter") result(hint.key); e.preventDefault() }} onFocus={e => handleFocus(e, true)} onBlur={e => handleFocus(e, false)} > {tag} {count} {summary} {more}
); }

EDITORTAGS.md

This is a README for the source file above.

You don’t have to read this. I wrote it because there a couple of tricky things in the implementation — design decisions, e.g. to do with “focus-within” — which I didn’t want to document as comments in the source code.

EditorTags

The EditorTags component lets you edit and select the tags associated with a topic.

  • Appearance and behaviour
  • Implementation state data
  • Sequence of definitions
    • Problem constraints
    • Solution as implemented
  • Controlling the <input> element
  • Simulating :focus-within

Appearance and behaviour

It looks like a simple <input type="text"> control, which contains multiple words — one word per tag —
however all words except the currently-selected word have some visible style applied to them.

It’s implemented as a

like this:

  function getElement(element: RenderedElement, index: number): React.ReactElement {
    const isValid = !props.showValidationError || element.isValid;
    return (element.type === "tag")
      ? 
      :  handleFocus(e, true)} onBlur={e => handleFocus(e, false)} />
  }

  return (
    
{state.elements.map(getElement)} {icon}
<ShowHints hints={state.hints} inputValue={state.inputValue} result={handleHintResult} /> <ErrorMessage errorMessage={errorMessage} /> {validationError} </div> );

The <div> — and the state.elements array shown above — contains:

  • Exactly one <input> element, in which you edit the currently-selected word
  • One or more React components of my type <Tag>, which style the other words which you’re not currently editing

The <input> element may be:

  • Alone in the <div>
  • The first or the last element in the <div>, either before or after all <Tag> elements
  • In the middle of the <div>, with <Tag> elements to its left and right

When you use the cursor keys (including ArrowLeft and ArrowRight) to scroll beyond the edge of
the <input> control, then this component detects that and changes its selection of which tag is currently editable.

Implementation state data

There’s quite a bit of state (i.e. member data) associated with this component:

  • A state.buffer string whose value equals the current string or array of words (i.e. tags) being edited
  • A state.selection index or range, that identifies which word is currently being edited —
    this is a start and end range, because you can select a range of text,
    e.g. by pressing the Shift key when you use the cursor keys
  • The elements array, which is calculated from the buffer and the selection range, and which identifies which word is
    associated with the <input> element and which other words are associated with the <Tag> elements.
  • The inputValue which identifies the current value of the <input> element
  • A hints array which lists the possible tags which might be a match for the input value
  • A validationError message if the current tags are invalid and deserve an error message
// this is like the input data from which the RenderedState is calculated
// these and other state elements are readonly so that event handlers must mutate MutableState instead
interface State {
  // the selection range within the buffer
  // this may even span multiple words, in which case all the selected words are in the <input> element
  readonly selection: { readonly start: number, readonly end: number },
  // the words (i.e. the tags when this is split on whitespace)
  readonly buffer: string
};

// this interface identifies the array of <input> and <Tag> elements to be rendered, and the word associated with each
interface RenderedElement {
  // the string value of this word
  readonly word: string;
  // whether this word is rendered by a Tag element or by the one input element
  readonly type: "tag" | "input";
  // whether this word matches an existing tag in the dictionary
  readonly isValid: boolean;
};

// this interface combines the two states, and is what's stored using useReducer
interface RenderedState {
  // the buffer which contains the tag-words, and the selection within the buffer
  readonly state: State;
  // how that's rendered i.e. the <input> element plus <Tag> elements
  readonly elements: ReadonlyArray<RenderedElement>;
  // the current ("semi-controlled") value of the <input> element
  readonly inputValue: string;
  // the hints associated with the inputValue, taken from the TagDictionary
  hints: TagCount[];
  // the validation error message (zero length if there isn't one)
  validationError: string;
}

Because there’s a lot of data, and the data elements are inter-related,
I implement it with useReducer instead of useState.

Sequence of definitions

The sequence in which things are defined in the source file is significant —
and it’s fragile, i.e. if you don’t do it right then there’s a compiler error about using something before it’s defined,
or a run-time error about using something with an undefined value.

I use the following strategy:

  • Because the initialState and therefore the renderState functions are called when the state is initialized and
    before inputRef.current exists, this function and anything called from this function cannot reference the state data.
  • To ensure they don’t reference the state data, they’re defined in the EditorTabs.tsx module (for convenience),
    but defined outside the EditorTags function component inside which the state data are defined, so that the compiler
    would error if they were referenced from those functions.

So the following are defined outside the function component:

  • The initialState and renderState functions
  • Any TypeScript class definitions which these functions use
  • Any other TypeScript type definitions which these functions or classes use — so, for simplicity, every TypeScript
    type definition.
  • Any small helper/utility functions which these functions use — and so, for simplicity, all helper/utility functions
  • Because a reducer should be stateless or pure, it too is defined outside the function component
  • And therefore also the TypeScript type definitions of the action types, and the corresponding user-defined type guards

So the following remain inside the function component:

  • All state data
  • All event handlers (which delegate to the reducer, and which may reference inputRef.current)
  • The assert function depends on the setErrorMessage function, which is state — so the assert function too is
    defined inside the function component, and is passed as a parameter to any function which needs it.

Data that’s stored inside the function component, and which isn’t stored as state,
is passed to the reducer in the “action”.

interface ActionEditorClick { type: "EditorClick", context: Context };
interface ActionHintResult { type: "HintResult", context: Context, hint: string, inputIndex: number };
interface ActionDeleteTag { type: "DeleteTag", context: Context, index: number };
interface ActionTagClick { type: "TagClick", context: Context, index: number };
interface ActionKeyDown { type: "KeyDown", context: Context, key: string, shiftKey: boolean };
interface ActionChange { type: "Change", context: Context };

All the Action types include an InputElement (which is created by the event handler which generates the action),
because the MutableState class (called from the reducer) requires an InputElement, in order to update the State
(including the buffer and the selection) to match the contents of the <input> element.

In fact there’s other data too, which the reducer needs and is passed in the action:

// this is extra data which event handlers pass (as part of the action) from the function component to the reducer
interface Context {
  inputElement: InputElement;
  assert: Assert;
  result: ParentCallback;
  tagDictionary?: TagDictionary;
  validation: Validation;
};

Controlling the <input> element

The <input> element is a semi-controlled component (see e.g.
What are Controlled Components in React?“).

There’s an inputRef as well to access to the underlying HTML element, which is used to set the focus, and
to get and set the selection range within the element, but not to get the value of the element —
the value of the element is got via its onChange handler (and the value property of the event’s target).

Note that React’s onChange event handler has redefined (non-standard) semantics — i.e. it’s fired after every change,
and not only when it loses focus.

I say that it’s “semi” controlled, because although its onChange handler writes its value to state …

<input type="text" ref={inputRef} onChange={handleChange} ...

… it does not have a corresponding value property which might read its value from state …

<input type="text" ref={inputRef} onChange={handleChange} value={state.inputValue} ...

The reason why not is because if the value property is used to write a string into a previously-empty
input element, then the selection range within the control is automatically pushed to the end of the new string.

This interferes with the desired behaviour of the ArrowRight key, where we want to copy
the next (to the right) tag into the input control, and set the selection range to the beginning of the control.

So, instead, the setInput function writes into the value property of the underlying HTMLInputElement.

  • I worried that doing this might trigger another onChange event, but it doesn’t seem to.
  • An alternative might be to use useEffect to alter the selection of the input (to match the selection specified in
    the state), after it’s rendered.
    That seems like even more of a kluge, though — making it “semi-controlled” instead, i.e. writing to the DOM element,
    seems neater.

The inputValue element also still exists as an alement of the RenderedState data,
but it’s write-only — i.e. it’s up-to-date (and a opy of what was written into the DOM element).

Simulating :focus-within

There are a couple of effects in EditorTags.css for example …

.tag-hints {
  visibility: hidden;
}

.tag-both:focus-within .tag-hints {
  visibility: visible;
}

… where is would be convenient to use :focus-within. However that’s not supported by some browsers (e.g. Edge).
Although the “Create React App” setup include postcss modules, they’re not configurable —
You cannot customize postcss rules
— and the default configuration doesn’t enable support for postcss-focus-within.

To avoid the complexity or fragility of trying to bypass the CRA default configuration,
instead I use onfocus and onBlur handlers to simulate :focus-within
(by adding or removing focussed to the class value).

There’s also complexity in deciding whether something has lost focus.

  • The problem is that, using React’s synthetic events, onBlur fires before onFocus
    so focus seems lost when focus moves from .tag-editor input to one of the .hint elements.
  • The right the right way to support this functionality would be to use the focusin event as described in
    Focus Event Order,
    however React’s synthetic events don’t support focusinhttps://github.com/facebook/react/issues/6410

Solutions like …

… solve this using a timer in some way —
which is probably good, only I’m not certain of the sequence in which events are emitted.

So instead I use a solution (see the handleFocus function) which depends on the relatedTarget of the event:

  • That works on my machine (Windows 10), at least, using Chrome, Firefox, and Edge.
  • https://github.com/facebook/react/issues/3751 warns that apparently this won’t work with IE 9 through IE 11,
    though comments there say that document.activeElement might help make it work on IE

Otherwise, if support for IE (not just Edge) is needed, one of the other solutions listed earlier above might be better.


Get this bounty!!!

#StackBounty: #audio #bluetooth #pygame Why won't pygame play sound over Bluetooth when everything else works?

Bounty: 50

I having trouble getting a program I’ve written using the pygame sound mixer to play sound to work over Bluetooth. The program is able to work correctly over HDMI audio. The Raspberry Pi has no trouble connecting to the Bluetooth headphones, and aplay works just fine to play sound. After I attempt to play sound with pygame, aplay is broken and will not play sound until I do a reboot. Any ideas?

Here is my basic python test program:

simplePyGame.py

import pygame.mixer

pygame.mixer.init(48000, -16, 1, 1024)

sndA = pygame.mixer.Sound("A.wav")

soundChannel1A = pygame.mixer.Channel(1)

soundChannel1A.play(sndA)

Running the program outputs the following:

$ python simplePyGame.py
Traceback (most recent call last):
  File "simplePyGame.py", line 3, in <module>
    pygame.mixer.init(48000, -16, 1, 1024)
pygame.error: Couldn't set hardware audio parameters: Success

Now, using aplay to play a WAV file outputs this error. It doesn’t go away until the Raspberry Pi is restarted.

$ aplay ../20second_sine.wav
Playing WAVE '../20second_sine.wav' : Signed 16 bit Little Endian, Rate 8000 Hz, Mono
aplay: set_params:1363: Unable to install hw params:
ACCESS:  RW_INTERLEAVED
FORMAT:  S16_LE
SUBFORMAT:  STD
SAMPLE_BITS: 16
FRAME_BITS: 16
CHANNELS: 1
RATE: 8000
PERIOD_TIME: (85333 85334)
PERIOD_SIZE: (682 683)
PERIOD_BYTES: (1364 1366)
PERIODS: (5 7)
BUFFER_TIME: 511875
BUFFER_SIZE: NONE
BUFFER_BYTES: 8190
TICK_TIME: 0

Versions:
– Raspbian Stretch (Linux 9)
– Python 2.7.13
– aplay 1.1.3
– pygame 1.9.3
– bluealsa 1.2.0

Full information: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=214901


Get this bounty!!!

#StackBounty: #np-hardness #partition-problem A partition problem with order constraints

Bounty: 50

In the OrderedPartition problem, the input is two sequences of $n$ positive integers, $(a_i){iin [n]}$ and $(b_i){iin [n]}$.
The output is a partition of the indices $[n]$ into two disjoint subsets, $I$ and $J$, such that:

  1. $sum_{iin I} a_i = sum_{jin J} a_i$
  2. For all $iin I$ and for all $jin J$: $b_ileq b_j$.

In other words, we have to first order the indices on a line such that the $b_i$ are weakly increasing, and then cut the line such that the sum of the $a_i$ in both sides is the same.

If all $b_i$ are the same, then condition 2 is irrelevant and we have an instance of the NP-hard Partition problem.
On the other hand, if all $b_i$ are different, then condition 2 imposes a single ordering on the indices, so there are only $n-1$ options to check, and the problem becomes polynomial. What happens in between these cases?

To formalize the question, define by OrderedPartition[n,d], for $1leq dleq n$,
the problem restricted to instances of size $n$, in which the largest subset of identical $b_i$-s is of size $d$. So the easy case, when all $b_i$-s are different, is OrderedPartition[n,1], and the hard case, when all $b_i$-s are identical, is OrderedPartition[n,n].

More generally, For any $n$ and $d$, in any OrderedPartition[n,d] instance, the number of possible partitions respecting condition 2 is $O(n 2^d)$. Hence, if $din O(log{n})$, then OrderedPartition[n,d] is still polynomial in $n$.

On the other hand, for any $n$ and $d$, we can reduce from a Partition problem with $d$ integers to OrderedPartition[n,d]. Let $p_1,ldots,p_d$ be an instance of Partition. Define the instance OrderedPartition[n,d] by:

  • For each $iin {1,ldots,d}$, let $a_i := 2ncdot p_i$ and $b_i := 1$.
  • For each $iin {d+1,ldots,n}$, let $a_i := 1$ and $b_i := i$
    [if $n-d$ is odd, make $a_n:=2$ such that the sum will be even].

Hence, if $dinOmega(n^{1/k})$, for any integer $kgeq 1$, then OrderedPartition[n,d] is NP-hard.

QUESTION: What happens in the intermediate cases, in which $d$ is super-logarithmic but sub-polynomial in $n$?


Get this bounty!!!

#StackBounty: #well-being #happiness What can one do to permanently increase one's baseline happiness (subjective well-being)?

Bounty: 50

According to the hedonic treadmill theory of subjective well-being each human has a hedonic set point. Positive or negative life events cause relatively short-term deviations to one’s happiness before it returns to the baseline happiness level determined by the set point. The set point appears to be stable over the course of one’s life. One’s happiness, measured over time, looks something like this:

enter image description here

Question: What, if anything, has been demonstrated by research to cause long-term, significant upward shifts of the baseline happiness? And, if so, which of those interventions are accessible to an average person (in wealthy countries)?

enter image description here


Get this bounty!!!

#StackBounty: #table-of-contents #titlesec #tocloft #titletoc Make decrease the space between title of list of figures and list of tabl…

Bounty: 100

I try to reduce the space between the title name of list of figure (“Liste des Figures” on the image below) and the list of figures.

I would like to do the same for the title name of list of tables (“Liste des Tables”).

The particularity of my case is that I want to have the list of figures and the list of tables on the same page.

As you can see, decreasing the space betwwen the title ans lists would allow me to have all just on a single page.

lists too long : that takes 2 pages

The issue is also that I am using a special style for chapter, table of contents, list of figure … etc (the black rectangle with the horizontal line above titles).

I show you below the source that I use :

documentclass[11pt,french,oneside]{report}
usepackage[latin1]{inputenc}
usepackage[T1]{fontenc}
usepackage[francais]{babel}
usepackage{indentfirst}
usepackage{lastpage}
usepackage{amsmath,amssymb}
usepackage{fancyhdr}
usepackage{url}
usepackage{epsfig}
usepackage{graphics}
usepackage{multirow}
usepackage{vmargin}
usepackage{float}
usepackage{psboxit,pstcol}
usepackage{tabularx}

usepackage[style=ext-authoryear, backend=biber]{biblatex}
usepackage[hyperfootnotes=false,colorlinks,allcolors=blue]{hyperref}
usepackage[nameinlink,noabbrev]{cleveref}
Crefname{appendix}{l'Appendice}{les Appendices}
usepackage{setspace}
usepackage{needspace}
usepackage{caption}

usepackage[table,svgnames,dvipsnames]{xcolor}
usepackage{calc}
usepackage{geometry}

setcounter{tocdepth}{3}
setcounter{secnumdepth}{3}

DeclareCaptionFont{xbf}{bfseriesboldmath}
captionsetup{font=xbf}

definecolor{jonquil}{rgb}{0.98, 0.85, 0.37}
definecolor{lavender(web)}{rgb}{0.9, 0.9, 0.98}

DeclareFixedFont{ttb}{T1}{txtt}{bx}{n}{9} % for bold
DeclareFixedFont{ttm}{T1}{txtt}{m}{n}{9}  % for normal

usepackage{color}
definecolor{deepblue}{rgb}{0,0,0.5}
definecolor{deepred}{rgb}{0.6,0,0}
definecolor{deepgreen}{rgb}{0,0.5,0}

usepackage{listings}

newcommandpythonstyle{lstset{
language=Python,
basicstyle=ttm,
otherkeywords={self},             % Add keywords here
keywordstyle=ttbcolor{deepblue},
emph={MyClass,__init__},          % Custom highlighting
emphstyle=ttbcolor{deepred},    % Custom highlighting style
stringstyle=color{deepgreen},
frame=tb,                         % Any extra options here
showstringspaces=false,

commentstyle=ttbselectfontitshape,columns=fullflexible], 
numbers=left,
stepnumber=1,
}}

newcolumntype{C}{>{centeringarraybackslash}X}

usepackage{colortbl} % for rowcolor macro
usepackage{array}
setlengthextrarowheight{1.5pt} % for a more open "look"
usepackage[skip=0.5baselineskip]{caption}

renewcommand*{nameyeardelim}{addcommaspace}

newcommand*{x}{mathsf{x}mskip1mu}

DeclareCiteCommand{cite}[mkbibparens]
  {usebibmacro{prenote}}
  {usebibmacro{citeindex}%
   printtext[bibhyperref]{usebibmacro{cite}}}
  {multicitedelim}
  {usebibmacro{postnote}}

DeclareCiteCommand*{cite}[mkbibparens]
  {usebibmacro{prenote}}
  {usebibmacro{citeindex}%
   printtext[bibhyperref]{usebibmacro{citeyear}}}
  {multicitedelim}
  {usebibmacro{postnote}}

newcommand{emptysection}[1]{%
    begingrouprenewcommandaddcontentsline[3]{}%
    section{#1}endgroup%
}

makeatletter
newlength{chapter@number@width}
def@makechapterhead#1{%
  {normalfont
  setlength{parindent}{0pt}%
  vspace*{10pt}%
  settowidth{chapter@number@width}{%
    hbox{color{white}LARGEbfseries
          hspace{dimexpr 1mm+3pt}%
          thechapter
          hspace{dimexpr 1mm+3pt}%
    }}
  hbox{%
    vtop{%
      hsize=dimexprchapter@number@width+tabcolsep+2fboxrule+tabcolsep
      begin{tabular}[t]{@{}c}
        scshapestrutmakebox[0pt]{hspace{0pt plus 1 fill minus 1 fill}@chapapphspace{0pt plus 1 fill minus 1 fill}} \
        fboxsep=0pt
        colorbox{black}{vbox{%
           hbox{vbox to dimexpr 1mm+3pt{}}
           hbox{color{white}LARGEbfseries
                 hspace{dimexpr 1mm+3pt}%
                 thechapter
                 hspace{dimexpr 1mm+3pt}%
                }
           hrule height 0.4pt depth 0pt width 0pt
           hbox{vbox to 6pt{}}
           hbox{parbox{0pt}{Hugebfseriesvphantom{E}}}
           }}%
      end{tabular}%
      }%
    vtop{%
      advancehsize by -dimexprchapter@number@width+2fboxrule+tabcolsep
      hspace*{-0.5cm}begin{tabular}[t]{c}
        scshapestrutvphantom{@chapapp} \
        fboxsep=0pt
        colorbox{white}{vbox{%
           hbox{vbox to dimexpr 1mm+3pt{}}
           hbox{LARGEbfseries
                 hspace{dimexpr 1mm+3pt}%
                 phantom{thechapter}
                 hspace{dimexpr 1mm+3pt}%
                }
           hrule height 0.4pt depth 0pt width hsize
           hbox{vbox to 6pt{}}
           hbox{hspace*{20pt}parbox{dimexprtextwidth-2mm-6pt-chapter@number@width-tabcolsep-2fboxrule-20pt}{Hugebfseries #1}}
           }}%
      end{tabular}%
      }%
    }%
  vspace{50pt}%
  }
}
def@makeschapterhead#1{%
  {normalfont
  setlength{parindent}{0pt}%
  vspace*{10pt}%
  settowidth{chapter@number@width}{%
    hbox{color{white}LARGEbfseries
          hspace{dimexpr 1mm+3pt}%
          thechapter
          hspace{dimexpr 1mm+3pt}%
    }}
  hbox{%
    vtop{%
      hsize=dimexprchapter@number@width+tabcolsep+2fboxrule+tabcolsep
      begin{tabular}[t]{@{}c}
        scshapestrutmakebox[0pt]{hspace{0pt plus 1 fill minus 1 fill}phantom{@chapapp}hspace{0pt plus 1 fill minus 1 fill}} \
        fboxsep=0pt
        colorbox{black}{vbox{%
           hbox{vbox to dimexpr 1mm+3pt{}}
           hbox{color{white}LARGEbfseries
                 hspace{dimexpr 1mm+3pt}%
                 phantom{thechapter}%
                 hspace{dimexpr 1mm+3pt}%
                }
           hrule height 0.4pt depth 0pt width 0pt
           hbox{vbox to 6pt{}}
           hbox{parbox{0pt}{Hugebfseriesvphantom{E}}}
           }}%
      end{tabular}%
      }%
    vtop{%
      advancehsize by -dimexprchapter@number@width+2fboxrule+tabcolsep
      hspace*{-0.5cm}begin{tabular}[t]{c}
        scshapestrutvphantom{@chapapp} \
        fboxsep=0pt
        colorbox{white}{vbox{%
           hbox{vbox to dimexpr 1mm+3pt{}}
           hbox{LARGEbfseries
                 hspace{dimexpr 1mm+3pt}%
                 phantom{thechapter}
                 hspace{dimexpr 1mm+3pt}%
                }
           hrule height 0.4pt depth 0pt width hsize
           hbox{vbox to 6pt{}}
           hbox{hspace*{20pt}parbox{dimexprtextwidth-2mm-6pt-chapter@number@width-tabcolsep-2fboxrule-20pt}{Hugebfseries #1}}
           }}%
      end{tabular}%
      }%
    }%
  vspace{50pt}%
  }
}

setlengthparindent{0pt}


newenvironment{changemargin}[2]{begin{list}{}{%
setlength{topsep}{0pt}%
setlength{leftmargin}{0pt}%
setlength{rightmargin}{0pt}%
setlength{listparindent}{parindent}%
setlength{itemindent}{parindent}%
setlength{parsep}{0pt plus 1pt}%
addtolength{leftmargin}{#1}%
addtolength{rightmargin}{#2}%
}item }{end{list}}



setmarginsrb{2.3cm}{0.0cm}{2.1cm}{1cm}{1.3cm}{0.5cm}{0.4cm}{1cm}
pagestyle{fancy}
renewcommand{footrulewidth}{0.4pt}
renewcommand{headrulewidth}{0.4pt}
chead{hspace{-0.3cm}textit{Rapport de stage M2 Astrophysique, Sciences de lrq Espace, Plan'etologie hspace{-0.3cm}}}
lhead{epsfig{file=logo_small.jpg,height=0.8cm,width=2cm}}
rhead{epsfig{file=logo_ut3_small.png,height=0.8cm,width=2cm}}
lfoot{textit{lisssold riufi}}
cfoot{hspace{1.6cm} textit{ - Performances}} 
rfoot{thepage/pageref{LastPage}}

makeatletter
g@addto@macroappendix{%
  cleardoublepage
  hypertarget{appendixstart}{}%
  addtocontents{toc}{
    protectcontentsline{chapter}{protecthyperlink{appendixstart}{Appendice}}{}{}%
  }%
}
makeatother

usepackage[nameinlink,noabbrev]{cleveref}
renewcommand{arraystretch}{1.25} 

begin{document}

renewcommand*listfigurename{Liste des Figures}
renewcommand*listtablename{Liste des Tables}

tableofcontents

%%%%%% CRITICAL PART TO GET list of figures and list of tables %%%%
%%%%%% ON THE SAME PAGE %%%%%
%%%%%% This is HERE where I would like to reduce space between title
%%%%%% list while keeping the special style of titles (like chapters)

thispagestyle{plain}
listoffigures
begingroup
letclearpagerelax
listoftables
endgroup
thispagestyle{plain}

chapter*{Introduction}
addcontentsline{toc}{chapter}{Introduction}

If I use only :

setlength{cftbeforeloftitleskip}{5pt} % LOF: Listing of Figures
setlength{cftbeforelottitleskip}{5pt} % LOT: Listing of Tables

this causes the removing of the special format of chapters and table of figures, table of tables and also this makes push up all to the table of contents, i.e the mess up …

If someone could help me to produce one single page while keeeping the special style for both titles, this would be nice to tell me how to do it.

Regards


Get this bounty!!!

#StackBounty: #well-being #happiness What can one do to permanently increase one's baseline happiness (subjective well-being)?

Bounty: 50

According to the hedonic treadmill theory of subjective well-being each human has a hedonic set point. Positive or negative life events cause relatively short-term deviations to one’s happiness before it returns to the baseline happiness level determined by the set point. The set point appears to be stable over the course of one’s life. One’s happiness, measured over time, looks something like this:

enter image description here

Question: What, if anything, has been demonstrated by research to cause long-term, significant upward shifts of the baseline happiness? And, if so, which of those interventions are accessible to an average person (in wealthy countries)?

enter image description here


Get this bounty!!!