text:
Issues when using snapshot tests with DNT: tests and builds

During type checking:
[dnt] Building project...
[dnt] Type checking...
src/deps/deno.land/std@0.168.0/testing/snapshot.ts:420:18 - error TS7017: Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.

420       globalThis.addEventListener("unload", this.#teardown);
                     ~~~~~~~~~~~~~~~~

error: Uncaught Error: Had 1 diagnostics.
        throw new Error(`Had ${diagnostics.length} diagnostics.`);
              ^
    at build (https://deno.land/x/dnt@0.33.0/mod.ts:320:15)
    at async file:///home/orta/dev/puzmo/redwood-codegen-api-types/scripts/buildNPM.ts:7:1

During testing:

FAILURES

uses a rn to promise when we see an async tag
  Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/orta/dev/puzmo/redwood-codegen-api-types/npm/esm/tests/__snapshots__/preferPromiseFnWhenKnown.test.js.snap' imported from /home/orta/dev/puzmo/redwood-codegen-api-types/npm/esm/deps/deno.land/std@0.168.0/testing/snapshot.js

I bet for testing .snap files need to be migrated with other files? For build - unsure. Right now, I just made it skip both, though I may just drop the snapshot, it's only 1 and I only like using inline snapshots anyway

I got the tests running using the following hacks:

Rename the snapshot files to end in .ts so they can be transpiled during the build
Import the files in a generated snapshots.ts file and add this file as an entry point so the snapshot files will be transpiled
Edit script/deps/deno.land/std@0.198.0/testing/snapshot.js to remove the file:// prefix and patch the path before the snapshot file is "required"

This still resulted in the snapshots failing tests due to " being replaced with ':
        [Diff] Actual / Expected

        {
          fields: Map(6) {
    -       'display' => {
    -         kind: 'option',
    +       "display" => {
    +         kind: "option",
              valueType: {
                fields: Map(8) {
    -             'firstperson_lefthand' => {
    -               kind: 'option',
    +             "firstperson_lefthand" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    +                   "rotation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    +                     kind: "array",
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    +                   "translation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    -                   }
    +                     kind: "array",
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'firstperson_righthand' => {
    -               kind: 'option',
    +             "firstperson_righthand" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    +                   "rotation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    +                     kind: "array",
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    +                   "translation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    -                   }
    +                     kind: "array",
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'fixed' => {
    -               kind: 'option',
    +             "fixed" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    -                     kind: 'option',
    +                   "rotation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    -                     kind: 'option',
    +                   "translation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    -                   }
    +                       kind: "array",
    +                     },
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'ground' => {
    -               kind: 'option',
    +             "ground" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    +                   "rotation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    +                     kind: "array",
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    -                     kind: 'option',
    +                   "translation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    -                   }
    +                       kind: "array",
    +                     },
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'gui' => {
    -               kind: 'option',
    +             "gui" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    -                     kind: 'option',
    +                   "rotation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    -                     kind: 'option',
    +                   "translation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    -                   }
    +                       kind: "array",
    +                     },
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'head' => {
    -               kind: 'option',
    +             "head" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    -                     kind: 'option',
    +                   "rotation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    +                   "translation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    -                   }
    +                     kind: "array",
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'thirdperson_lefthand' => {
    -               kind: 'option',
    +             "thirdperson_lefthand" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    +                   "rotation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    +                     kind: "array",
                        },
    -                   'scale' => {
    +                   "scale" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    +                     kind: "array",
                        },
    -                   'translation' => {
    +                   "translation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    -                   }
    +                     kind: "array",
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             'thirdperson_righthand' => {
    -               kind: 'option',
    +             "thirdperson_righthand" => {
    +               kind: "option",
                    valueType: {
                      fields: Map(3) {
    -                   'rotation' => {
    -                     kind: 'option',
    +                   "rotation" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'scale' => {
    -                     kind: 'option',
    +                   "scale" => {
    +                     kind: "option",
                          valueType: {
                            elementType: {
    -                         kind: 'primitive',
    -                         name: 'number'
    +                         kind: "primitive",
    +                         name: "number",
                            },
    -                       kind: 'array'
    -                     }
    +                       kind: "array",
    +                     },
                        },
    -                   'translation' => {
    +                   "translation" => {
                          elementType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    +                       kind: "primitive",
    +                       name: "number",
                          },
    -                     kind: 'array'
    -                   }
    +                     kind: "array",
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    -             }
    +                 kind: "struct",
    +               },
    +             },
                },
    -           kind: 'struct'
    -         }
    +           kind: "struct",
    +         },
            },
    -       'elements' => {
    -         kind: 'option',
    +       "elements" => {
    +         kind: "option",
              valueType: {
                elementType: {
                  fields: Map(3) {
    -               'faces' => {
    +               "faces" => {
                      fields: Map(6) {
    -                   'down' => {
    -                     kind: 'option',
    +                   "down" => {
    +                     kind: "option",
                          valueType: {
                            fields: Map(2) {
    -                         'texture' => {
    -                           kind: 'primitive',
    -                           name: 'string'
    +                         "texture" => {
    +                           kind: "primitive",
    +                           name: "string",
                              },
    -                         'uv' => {
    +                         "uv" => {
                                elementType: {
    -                             kind: 'primitive',
    -                             name: 'number'
    +                             kind: "primitive",
    +                             name: "number",
                                },
    -                           kind: 'array'
    -                         }
    +                           kind: "array",
    +                         },
                            },
    -                       kind: 'struct'
    -                     }
    +                       kind: "struct",
    +                     },
                        },
    -                   'east' => {
    +                   "east" => {
                          fields: Map(2) {
    -                       'texture' => {
    -                         kind: 'primitive',
    -                         name: 'string'
    +                       "texture" => {
    +                         kind: "primitive",
    +                         name: "string",
                            },
    -                       'uv' => {
    +                       "uv" => {
                              elementType: {
    -                           kind: 'primitive',
    -                           name: 'number'
    +                           kind: "primitive",
    +                           name: "number",
                              },
    -                         kind: 'array'
    -                       }
    +                         kind: "array",
    +                       },
                          },
    -                     kind: 'struct'
    +                     kind: "struct",
                        },
    -                   'north' => {
    +                   "north" => {
                          fields: Map(2) {
    -                       'texture' => {
    -                         kind: 'primitive',
    -                         name: 'string'
    +                       "texture" => {
    +                         kind: "primitive",
    +                         name: "string",
                            },
    -                       'uv' => {
    +                       "uv" => {
                              elementType: {
    -                           kind: 'primitive',
    -                           name: 'number'
    +                           kind: "primitive",
    +                           name: "number",
                              },
    -                         kind: 'array'
    -                       }
    +                         kind: "array",
    +                       },
                          },
    -                     kind: 'struct'
    +                     kind: "struct",
                        },
    -                   'south' => {
    +                   "south" => {
                          fields: Map(2) {
    -                       'texture' => {
    -                         kind: 'primitive',
    -                         name: 'string'
    +                       "texture" => {
    +                         kind: "primitive",
    +                         name: "string",
                            },
    -                       'uv' => {
    +                       "uv" => {
                              elementType: {
    -                           kind: 'primitive',
    -                           name: 'number'
    +                           kind: "primitive",
    +                           name: "number",
                              },
    -                         kind: 'array'
    -                       }
    +                         kind: "array",
    +                       },
                          },
    -                     kind: 'struct'
    +                     kind: "struct",
                        },
    -                   'up' => {
    +                   "up" => {
                          fields: Map(2) {
    -                       'texture' => {
    -                         kind: 'primitive',
    -                         name: 'string'
    +                       "texture" => {
    +                         kind: "primitive",
    +                         name: "string",
                            },
    -                       'uv' => {
    +                       "uv" => {
                              elementType: {
    -                           kind: 'primitive',
    -                           name: 'number'
    +                           kind: "primitive",
    +                           name: "number",
                              },
    -                         kind: 'array'
    -                       }
    +                         kind: "array",
    +                       },
                          },
    -                     kind: 'struct'
    +                     kind: "struct",
                        },
    -                   'west' => {
    +                   "west" => {
                          fields: Map(2) {
    -                       'texture' => {
    -                         kind: 'primitive',
    -                         name: 'string'
    +                       "texture" => {
    +                         kind: "primitive",
    +                         name: "string",
                            },
    -                       'uv' => {
    +                       "uv" => {
                              elementType: {
    -                           kind: 'primitive',
    -                           name: 'number'
    +                           kind: "primitive",
    +                           name: "number",
                              },
    -                         kind: 'array'
    -                       }
    +                         kind: "array",
    +                       },
                          },
    -                     kind: 'struct'
    -                   }
    +                     kind: "struct",
    +                   },
                      },
    -                 kind: 'struct'
    +                 kind: "struct",
                    },
    -               'from' => {
    +               "from" => {
                      elementType: {
    -                   kind: 'primitive',
    -                   name: 'number'
    +                   kind: "primitive",
    +                   name: "number",
                      },
    -                 kind: 'array'
    +                 kind: "array",
                    },
    -               'to' => {
    +               "to" => {
                      elementType: {
    -                   kind: 'primitive',
    -                   name: 'number'
    +                   kind: "primitive",
    +                   name: "number",
                      },
    -                 kind: 'array'
    -               }
    +                 kind: "array",
    +               },
                  },
    -             kind: 'struct'
    +             kind: "struct",
                },
    -           kind: 'array'
    -         }
    +           kind: "array",
    +         },
            },
    -       'gui_light' => {
    -         kind: 'option',
    +       "gui_light" => {
    +         kind: "option",
              valueType: {
    -           kind: 'primitive',
    -           name: 'string'
    -         }
    +           kind: "primitive",
    +           name: "string",
    +         },
            },
    -       'overrides' => {
    -         kind: 'option',
    +       "overrides" => {
    +         kind: "option",
              valueType: {
                elementType: {
                  fields: Map(2) {
    -               'model' => {
    -                 kind: 'primitive',
    -                 name: 'string'
    +               "model" => {
    +                 kind: "primitive",
    +                 name: "string",
                    },
    -               'predicate' => {
    +               "predicate" => {
                      fields: Map(15) {
    -                   'angle' => {
    -                     kind: 'option',
    +                   "angle" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'blocking' => {
    -                     kind: 'option',
    +                   "blocking" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'broken' => {
    -                     kind: 'option',
    +                   "broken" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'brushing' => {
    -                     kind: 'option',
    +                   "brushing" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'cast' => {
    -                     kind: 'option',
    +                   "cast" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'charged' => {
    -                     kind: 'option',
    +                   "charged" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'filled' => {
    -                     kind: 'option',
    +                   "filled" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'firework' => {
    -                     kind: 'option',
    +                   "firework" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'level' => {
    -                     kind: 'option',
    +                   "level" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'pull' => {
    -                     kind: 'option',
    +                   "pull" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'pulling' => {
    -                     kind: 'option',
    +                   "pulling" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'throwing' => {
    -                     kind: 'option',
    +                   "throwing" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'time' => {
    -                     kind: 'option',
    +                   "time" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'tooting' => {
    -                     kind: 'option',
    +                   "tooting" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
                        },
    -                   'trim_type' => {
    -                     kind: 'option',
    +                   "trim_type" => {
    +                     kind: "option",
                          valueType: {
    -                       kind: 'primitive',
    -                       name: 'number'
    -                     }
    -                   }
    +                       kind: "primitive",
    +                       name: "number",
    +                     },
    +                   },
                      },
    -                 kind: 'struct'
    -               }
    +                 kind: "struct",
    +               },
                  },
    -             kind: 'struct'
    +             kind: "struct",
                },
    -           kind: 'array'
    -         }
    +           kind: "array",
    +         },
            },
    -       'parent' => {
    -         kind: 'option',
    +       "parent" => {
    +         kind: "option",
              valueType: {
    -           kind: 'primitive',
    -           name: 'string'
    -         }
    +           kind: "primitive",
    +           name: "string",
    +         },
            },
    -       'textures' => {
    -         kind: 'option',
    +       "textures" => {
    +         kind: "option",
              valueType: {
                fields: Map(5) {
    -             'layer0' => {
    -               kind: 'option',
    +             "layer0" => {
    +               kind: "option",
                    valueType: {
    -                 kind: 'primitive',
    -                 name: 'string'
    -               }
    +                 kind: "primitive",
    +                 name: "string",
    +               },
                  },
    -             'layer1' => {
    -               kind: 'option',
    +             "layer1" => {
    +               kind: "option",
                    valueType: {
    -                 kind: 'primitive',
    -                 name: 'string'
    -               }
    +                 kind: "primitive",
    +                 name: "string",
    +               },
                  },
    -             'layer2' => {
    -               kind: 'option',
    +             "layer2" => {
    +               kind: "option",
                    valueType: {
    -                 kind: 'primitive',
    -                 name: 'string'
    -               }
    +                 kind: "primitive",
    +                 name: "string",
    +               },
                  },
    -             'particle' => {
    -               kind: 'option',
    +             "particle" => {
    +               kind: "option",
                    valueType: {
    -                 kind: 'primitive',
    -                 name: 'string'
    -               }
    +                 kind: "primitive",
    +                 name: "string",
    +               },
                  },
    -             'spyglass' => {
    -               kind: 'option',
    +             "spyglass" => {
    +               kind: "option",
                    valueType: {
    -                 kind: 'primitive',
    -                 name: 'string'
    -               }
    -             }
    +                 kind: "primitive",
    +                 name: "string",
    +               },
    +             },
                },
    -           kind: 'struct'
    -         }
    -       }
    +           kind: "struct",
    +         },
    +       },
          },
    -     kind: 'struct'
    +     kind: "struct",
        }

        at assertSnapshot (/home/ben/repos/gentype/npm/script/deps/deno.land/std@0.198.0/testing/snapshot.js:481:15)
        at async run (/home/ben/repos/gentype/npm/script/test.js:123:9)
        at async Object.<anonymous> (/home/ben/repos/gentype/npm/script/test.js:132:9)
        at async TestSuiteInternal.runTest (/home/ben/repos/gentype/npm/script/deps/deno.land/std@0.198.0/testing/_test_suite.js:307:13)
        at async TestSuiteInternal.runTest (/home/ben/repos/gentype/npm/script/deps/deno.land/std@0.198.0/testing/_test_suite.js:292:17)
        at async Object.fn (/home/ben/repos/gentype/npm/script/deps/deno.land/std@0.198.0/testing/_test_suite.js:265:25)
        at async Object.step (/home/ben/repos/gentype/npm/test_runner.js:136:21)
        at async TestSuiteInternal.run (/home/ben/repos/gentype/npm/script/deps/deno.land/std@0.198.0/testing/_test_suite.js:273:13)
        at async Object.fn (/home/ben/repos/gentype/npm/script/deps/deno.land/std@0.198.0/testing/_test_suite.js:130:29)
        at async runTestDefinitions (/home/ben/repos/gentype/npm/test_runner.js:54:13)
  fail

Is anyone currently working on this? If not, I may have capacity to look into it.

@orta For the 1st issue have a look here: https://github.com/denoland/deno_std/pull/4957#issuecomment-2147598172
For snapshots I tried copying them into the target folder via:
await copy("src/v1/tests/__snapshots__", "npm/esm/v1/tests/__snapshots__", { overwrite: true });

however the import is tried with .js.snap instead of .ts.snap and they don't seem to be picked up in the transformation phase.

authors: bcheidemann joscha orta

repo: denoland/dnt


text:
Unable to get/set schedule.

Is there an existing issue for this?

[X] I have searched the existing issues

I'm having the following issue:

When I run the "Plum ecoMAX: get_schedule" service for heating, the integration returns all values as "day". This is not correct because in the controller I have it set from 00.00 to 06.00 "night" from 6.00 to 15.00 "day" from 15.00 to 00.00 "night" "
I can't save the schedule to the controller using the Plum ecoMAX service: set_schedule" for heating.

When I run the "Plum ecoMAX: get_schedule" service for water heater, the integration returns the correct values.
But I can't save the schedule to the controller using the Plum ecoMAX service: set_schedule" for the water heater.

I have following devices connected:

[ ] ecoMAX 3xx series
[X] ecoMAX 8xx series
[ ] ecoMAX 9xx series
[ ] Expansion module B
[ ] Expansion module C
[X] ecoSTER 200/ecoSTER Touch
[ ] ecoLAMBDA
[ ] ecoNET 300

I'm connecting to my devices using:
Ethernet/WiFi to RS-485 converter
I'm seeing following log messages:
No response
My diagnostics data:
config_entry-plum_ecomax-3d173fc70d439aca63ce86c959ccc479.json.txt
Code of Conduct

[X] I agree to follow this project's Code of Conduct

From your diagnostics the issue is not related to the integration, but to the PyPlumIO library, which handles low-level protocol.
From a few cues, such as incorrect fuel level, missing model string and partially working schedules, it seems that Plum changed structure of related frames for your model. As PyPlumIO was initially writen for ecoMAX 850P in 2022, changes in firmware done by Plum in further models/firmwares can break the library's ability to decode frames.
This prompts future reverse-engineering of what changed in your device firmware. I'll get to it on the weekends, hovewer it will most likely take more than couple days. Sorry for inconvenience!

I confirm that my controller is ecoMAX 860P6-O. If I can help you with anything, write please.
Regards Jarek

Just so that I have somewhere to start, could you please elaborate if there any errors, when trying to set water heater schedule using set_schedule service or it just silently fails?

Hi
There are no errors after calling the service. There are no errors in the
HA logs.
Regards, Jarek
śr., 13 gru 2023 o 02:37 Denis Paavilainen @.***>
napisał(a):

Just so that I have somewhere to start, could you please elaborate if
there any errors, when trying to set water heater schedule using
set_schedule service or it just silently fails?
—
Reply to this email directly, view it on GitHub
https://github.com/denpamusic/PyPlumIO/issues/18#issuecomment-1853128287,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AR7UDQNAKMUBL2DV5N34TVDYJEBFJAVCNFSM6AAAAABAK37CP2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNJTGEZDQMRYG4
.
You are receiving this because you authored the thread.Message ID:
@.***>

This is not good :(
If you still want to help and know how to run arbitrary python scripts, could you please run one below and send me schedules.json file that it'll produce.
If you don't know how to run python scripts or not comfortable with doing so, don't worry, I'll still try to solve this issue, it's just gonna take more time.
If you decided to help, this simple heavily-commented script will simply send a request for schedules to your boiler and once it'll get a response, it'll save raw bytes and decoded data into JSON file. This way I can obtain raw bytes of the schedule response from your device and try to deduce why it is decoded incorrectly.
Don't forget to install PyPlumIO via pip before running this script:
$ pip install pyplumio

and set HOST and PORT variables to point to your converter.
"""Collect a single frame and dumps it to the file."""

import asyncio
import json
import sys

import pyplumio
from pyplumio.const import DeviceType
from pyplumio.frames import requests, responses
from pyplumio.helpers.parameter import ParameterValues

# Set host and port here.
HOST = "localhost"
PORT = 8899

# ------------------------------------- #
# Do not edit anything below this line. #
# ------------------------------------- #
FILENAME = "schedules.json"

def encode_parameter_values(o):
    """Encode ParameterValues to JSON."""
    if isinstance(o, ParameterValues):
        o = {
            "value": o.value,
            "min_value": o.min_value,
            "max_value": o.max_value,
        }

    return o

async def main() -> int:
    """Collect a single schedule response frame and dump it to the JSON file.

    We'll use DummyProtocol here, since we'll need direct control over
    connection and access to a raw ecoMAX frame.
    """
    async with pyplumio.open_tcp_connection(
        host=HOST, port=PORT, protocol=pyplumio.DummyProtocol()
    ) as connection:
        print("Requesting schedules from the ecoMAX...")
        await connection.writer.write(
            requests.SchedulesRequest(recipient=DeviceType.ECOMAX)
        )

        while connection.connected:
            print("Waiting for response...")
            if isinstance(
                (response := await connection.reader.read()),
                responses.SchedulesResponse,
            ):
                print(f"Got response ({response.length} bytes): {response.hex()}")
                break

        print(f"Saving frame to {FILENAME}...")
        with open(FILENAME, "w", encoding="UTF-8") as file:
            # We'll open a file and save dictionary containing
            # our frame's message represented as hex string and
            # decoded frame data.
            file.write(
                json.dumps(
                    {
                        "message": response.hex(),
                        "data": response.data,
                    },
                    default=encode_parameter_values,
                    indent=2,
                )
            )

        print("All done!")

sys.exit(asyncio.run(main()))

Hi
It sends you the collected data. Are they helpful to you?
Regards, Jarek
czw., 14 gru 2023 o 03:19 Denis Paavilainen @.***>
napisał(a):

This is not good :(
If you still want to help and know how to run arbitrary python scripts,
could you please run one below and send me schedules.json file that it'll
produce.
If you don't know how to run python scripts or not comfortable with doing
so, don't worry, I'll still try to solve this issue, it's just gonna take
more time.
If you decided to help, this simple heavily-commented script will simply
send a request for schedules to your boiler and once it'll get a response,
it'll save raw bytes and decoded data into JSON file. This way I can obtain
raw bytes of the schedule response from your device and try to deduce why
it is decoded incorrectly.
Don't forget to install PyPlumIO via pip before running this script:
$ pip install pyplumio
and set HOST and PORT variables to point to your converter.
"""Collect a single frame and dumps it to the file."""
import asyncioimport jsonimport sys
import pyplumiofrom pyplumio.const import DeviceTypefrom pyplumio.frames import requests, responsesfrom pyplumio.helpers.parameter import ParameterValues
Set host and port here.HOST = "localhost"PORT = 8899
------------------------------------- ## Do not edit anything below this line. ## ------------------------------------- #FILENAME = "schedules.json"
def encode_parameter_values(o):
"""Encode ParameterValues to JSON."""
if isinstance(o, ParameterValues):
o = {
"value": o.value,
"min_value": o.min_value,
"max_value": o.max_value,
}
return o

async def main() -> int:
"""Collect a single schedule response frame and dump it to the JSON file.    We'll use DummyProtocol here, since we'll need direct control over    connection and access to a raw ecoMAX frame.    """
async with pyplumio.open_tcp_connection(
host=HOST, port=PORT, protocol=pyplumio.DummyProtocol()
) as connection:
print("Requesting schedules from the ecoMAX...")
await connection.writer.write(
requests.SchedulesRequest(recipient=DeviceType.ECOMAX)
)
    while connection.connected:
        print("Waiting for response...")
        if isinstance(
            (response := await connection.reader.read()),
            responses.SchedulesResponse,
        ):
            print(f"Got response ({response.length} bytes): {response.hex()}")
            break

    print(f"Saving frame to {FILENAME}...")
    with open(FILENAME, "w", encoding="UTF-8") as file:
        # We'll open a file and save dictionary containing
        # our frame's message represented as hex string and
        # decoded frame data.
        file.write(
            json.dumps(
                {
                    "message": response.hex(),
                    "data": response.data,
                },
                default=encode_parameter_values,
                indent=2,
            )
        )

    print("All done!")

sys.exit(asyncio.run(main()))
—
Reply to this email directly, view it on GitHub
https://github.com/denpamusic/PyPlumIO/issues/18#issuecomment-1855004032,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AR7UDQJPKSBZQB5EXE3DGVLYJJO3BAVCNFSM6AAAAABAK37CP2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNJVGAYDIMBTGI
.
You are receiving this because you authored the thread.Message ID:
@.***>

It doesn't send it to me, it simply writes it to the file named schedules.json next to the script itself. If you managed to run the script, please send me this file yourself, it will be very helpful, since I'll then have an undecoded bytes from your device and can then implement changes into decoder and test it right away using this data.

schedules.json

Thank you very much for your help! I'll plug this data into a test case and try to rewrite decoder until it matches this for heating schedule:

This is not correct because in the controller I have it set from 00.00 to 06.00 "night" from 6.00 to 15.00 "day" from 15.00 to 00.00 "night" "

Hi,
Today I had more time to look at the schedules. I have to apologize to you because I misled you earlier.
I will divide my explanation into two topics.

DHW schedule.

I once wrote to you that I can read the DHW schedule, but I cannot set it. It turned out that I could set it up, but I was doing it incorrectly. This is because, before I installed the integration, I had set a schedule on my room panel (ecoMAX 860P Touch) for: 00.00-06.00 night (means do not heat the water), 06.00-15.00 day (heat water), 15.00-24.00 night. Then I started the service and set, for example, 12.00-14.00 day. There was no change on the room panel so I thought the service was not working properly. Now I know that to set water heating between 12.00-14.00 I should call the service 06.00-11.30 night and the second service 14.00-15.00 night. Alternatively 00.00:23.30 night and then 12.00-13.30 day. I don't know how to do it in Lovelace yet - maybe you can tell me something ;)

CH schedule.

As I wrote earlier here, I could neither read nor save the schedule. Today I noticed that Plum ecoMAX 860P6-O + Plum ecoMAX 860P6-O TOUCH has two schedules for CH. One is in the pellet boiler and the other in the room panel. They are independent and their settings do not overlap. I checked that I use the service to set the schedule in the pellet boiler, but I don't use it (it's turned off), I use the one in the room panel. Tell me, are you able to improve the integration so that it allows you to change the schedule in the room panel?
If something is not clear to you, do not hesitate to ask.
Regards, Jarek

Hi!
Thank you for the clarification!

It's ok. Schedule services documentation are quite bad and need improvement, so it's no wonder you've got confused. Furthermore there's no easy way to use schedules with lovelace, because such card doesn't exist. The best possible way for now would probably to create separate datetime helpers for start of night mode and start of day mode and create a script that will parse those inputs and send it to the set_schedule service. I could try to create a HASS blueprint for such use case, I wanted to learn how to use them anyways.

As for heating schedule, you are right, PyPlumIO only knows how to handle ecoMAX schedules. ecoSTER panel schedules is requested with different request frame REQUEST_GET_ECOSTER_SCHEDULES[frame_type=88] which is unsupported by PyPlumIO yet, but shouldn't be very hard to implement since frame format should be literally the same as ecoMAX schedules. Could you please run another script for me. This one should request ecoSTER panel schedules and write them to schedules.json file same as before. This script is a bit larger, since we're trying to get a frame not yet supported by the library. Don't forget to change HOST and PORT variables.

"""Collect a ecoSTER schedules frame and dumps it to the file."""

import asyncio
import json
import sys
from typing import ClassVar

import pyplumio
from pyplumio import ChecksumError
from pyplumio.const import DeviceType
from pyplumio.frames import Request, Response, bcc
from pyplumio.helpers.parameter import ParameterValues
from pyplumio.stream import FrameReader, FrameWriter, struct_header

# Set host and port here.
HOST = "localhost"
PORT = 8899

# ------------------------------------- #
# Do not edit anything below this line. #
# ------------------------------------- #
FILENAME = "schedules.json"

class CustomFrameType:
    """Extend frame type enum with ecoSTER schedule frames."""

    REQUEST_ECOSTER_SCHEDULES = 88
    RESPONSE_ECOSTER_SCHEDULES = 216

class CustomRequest(Request):
    """Custom request frame."""

    __slots__ = ("frame_type",)

    frame_type: ClassVar[CustomFrameType | int]

class CustomResponse(Response):
    """Custom response frame."""

    __slots__ = ("frame_type",)

    frame_type: ClassVar[CustomFrameType | int]

class CustomFrameReader(FrameReader):
    """Custom frame reader that allows unknown frames."""

    async def read(self) -> CustomResponse | None:
        """Read any frames from the stream.."""
        (
            header,
            length,
            recipient,
            sender,
            sender_type,
            econet_version,
        ) = await self._read_header()

        if recipient not in (DeviceType.ECONET, DeviceType.ALL):
            return None

        payload = await self._reader.readexactly(length - struct_header.size)

        if payload[-2] != bcc(header + payload[:-2]):
            raise ChecksumError(f"Incorrect frame checksum ({payload[-2]})")

        response = CustomResponse(
            recipient=recipient,
            message=payload[1:-2],
            sender=sender,
            sender_type=sender_type,
            econet_version=econet_version,
        )
        response.frame_type = payload[0]

        return response

class CustomDummyProtocol(pyplumio.DummyProtocol):
    """A dummy protocol with a custom reader that accepts unknown frames."""

    def connection_established(
        self, reader: asyncio.StreamReader, writer: asyncio.StreamWriter
    ) -> None:
        """Set reader and writer attributes and set the connected event."""
        self.reader = CustomFrameReader(reader)
        self.writer = FrameWriter(writer)
        self.connected.set()

def encode_parameter_values(o):
    """Encode ParameterValues to JSON."""
    if isinstance(o, ParameterValues):
        o = {
            "value": o.value,
            "min_value": o.min_value,
            "max_value": o.max_value,
        }

    return o

async def main() -> int:
    """Collect a single schedule response frame and dump it to the JSON file.

    We'll use DummyProtocol here, since we'll need direct control over
    connection and access to a raw ecoMAX frame.
    """
    async with pyplumio.open_tcp_connection(
        host=HOST, port=PORT, protocol=CustomDummyProtocol()
    ) as connection:
        print("Requesting ecoSTER schedules from the ecoMAX...")
        request = CustomRequest(recipient=DeviceType.ECOMAX)
        request.frame_type = CustomFrameType.REQUEST_ECOSTER_SCHEDULES
        await connection.writer.write(request)

        print("Waiting for response...")
        while connection.connected:
            response: CustomResponse = await connection.reader.read()
            if (
                response is not None
                and response.frame_type == CustomFrameType.RESPONSE_ECOSTER_SCHEDULES
            ):
                print(f"Got response ({response.length} bytes): {response.hex()}")
                break

        print(f"Saving frame to {FILENAME}...")
        with open(FILENAME, "w", encoding="UTF-8") as file:
            # We'll open a file and save dictionary containing
            # our frame's message represented as hex string and
            # decoded frame data.
            file.write(
                json.dumps(
                    {
                        "message": response.hex(),
                        "data": response.data,
                    },
                    default=encode_parameter_values,
                    indent=2,
                )
            )

        print("All done!")

sys.exit(asyncio.run(main()))

Hi
There is some problem with this script.
When I run it, in the terminal I have:
Requesting ecoSTER schedules form tne ecoMAX...
wait for response...
The script doesn't end. On the RS485 to ethernet converter page, I see that the script is trying to send data, but ecoMAX returns only 10 bytes of data.
I checked, the previous script executes correctly, so it's not a hardware fault.
Regards, Jarek

It's means that ecoMAX didn't recognize a request and didn't respond to it. Let me check if there are any additional request body requirements...

Now it's ok. I see that the script collected very little data, but maybe this is what you need.
Regards, Jarek
schedules.json

Yes, thank you very much!
This is exactly what I need.
The collected data seemed short to you, because unlike previous script, it lacks decoded part, since PyPlumIO doesn't know how to decode this kind of message yet.
But most important part, which is the message itself is there:
683c0000513c00d81001011001fdfdfd000000000000000ffffc0000000ffffc0000000ffffc0000000ffffc0000000ffffc00000000000000001116
I'll need to think about how to best integrate this with HASS, since we now have separate schedule requests for two different devices, but I'll get it done until integration version 0.4.2.

Ok. I will wait for the development of integration. If you need additional data, do not hesitate to write.

Hello, I see that you have released version 0.42 of integration in which you have separated ecoSTER as a separate device. I updated the integration but I still don't see the option to change schedules on ecoSTER. Am I doing something wrong or have you not added this functionality yet?
Regards, Jarek

Hi,
ecoSTER schedules are not part of current minor release.
Development timeline got a bit mangled, due to me having very little time to work on the project during almost all of January and early February. Many small fixes and changes are accumulated during the time, so it made more sense to release them as separate minor version. I try not include many bugfixes and large features in the same release together, since large new features tend to cause issues for some people, and then they are forced to choose between downgrading and having old unfixed bugs or upgrading and getting new ones, introduced by the new features.
I'll revisit ecoSTER schedules once custom entities PR are done and close this issue, when schedules are implemented.
Sorry for the delay.

source: gharchive/issue

repo: denpamusic/PyPlumIO

license: MIT

license_type: permissive

license_source: github-api


text:
Vacms 14419 cms preview

Description
Relates to #14419. (or closes?)
Testing done
Screenshots
QA steps
What needs to be checked to prove this works?
What needs to be checked to prove it didn't break any related things?
What variations of circumstances (users, actions, values) need to be checked?
- [ ] Automated tests have passed
- [ ] Tugboat environment was generated without errors

Is this PR blocked by another PR?

Add the DO NOT MERGE label
Add links to additional PRs here:

Closing in favor of #227

source: gharchive/pull-request


text:
Merge existing callback implementations

Value Statement
As a VANotify developer
I want to use the same endpoints and tables to manage both service callback API objects
AND service inbound API objects
So that duplication is reduced
Acceptance Criteria
GIVEN an api request is made to create a service callback
WHEN the callback_type is delivery_status or complaint
THEN VANotify stores callback information in the service callback table with the type delivery_status or complaint
GIVEN an api request is made to create a service callback
WHEN the callback_type is delivery_status
AND the request contains a list of notification statuses
THEN VANotify stores callback information in the service callback table with the type delivery_status and notification statuses
GIVEN an api request is made to create a service callback
WHEN the callback_type is inbound_sms
AND the request contains a list of notification statuses
THEN 400 error is returned
GIVEN an api request is made to create a service callback
WHEN the callback_type is inbound_sms
THEN VANotify stores callback information in the service callback table with the type inbound_sms
GIVEN a service has a callback configured
AND the callback_type is inbound_sms
WHEN VANotify receives an inbound SMS for that service
THEN the inbound SMS is sent to the service using the callback
GIVEN a service has a callback configured
AND the callback_type is delivery_status
WHEN VANotify receives a status update for that service
THEN the delivery status is sent to the service using the callback
Checklist

[x] Merge ServiceInboundApi into ServiceCallbackApi by expanding service_callback_type to include inbound_sms
[x] Ensure appropriate Data Migrations are in place  - as a separate commit
[x] Rename ServiceCallbackApi to remove reference to API - just ServiceCallback?
[x] Validate that we can create Complaint and Inbound callbacks without specifying notification_statuses

[x] And if not, make notification_statuses nullable when callback_type is not delivery_status (using check constraints)

[x] Remove ServiceInboundApi-specific endpoints
[x] Regression test to ensure email still works as intended

Assumptions

400 error means you are trying to add notification statuses to a callback that doesn't require statuses e.g. inbound SMS or complaints

Additional Info/Resources

Out of Scope

Open Questions

Test Approach
Reviewed Unit Test Case with Vikram. Updated a unit test to address an acceptance criteria for this ticket.  Now all the ACs have corresponding Unit/Integration tests that have all been executed and passed.
Regression Test: All unit tests that support service callback API objects (before change is implemented) were executed as a regression test and they all pass.
The test coverage to  test the merging of the callback implementation is sufficiently met at the Unit / Integration test.

authors: TWs-DevenS miabecker


text:
use a single square-brocket in commandsSupportsOption() like we do in…

… all other calls to test()

Q
A

Bug fix?
Yes

New feature?
No

BC breaks?
No

Deprecations?
No

Fixed tickets
#1445

should fix "[[: not found" warning in commandSupportsOption()

Do not forget to add notes about your changes to CHANGELOG.md

Add description under added/changed/fixed section.
Add reference to closed issues [#000].
Add link to issue in the end of document.

I guess it will fix #1445  not sure it will, as I cannot really reproduce this IF-case error on bash-only.

this patch is wrong. I have no clue how to solve this warning.

repo: deployphp/deployer


text:
🛑 Derailed API is down

In b1dd03d, Derailed API (https://derailed.one/api) was down:

HTTP code: 0
Response time: 0 ms

Resolved: Derailed API is back up in 9305e32.

repo: derailed-org/derailed-oss-status


text:
[BUG] exo run receives all logs

Describe the bug
When running exo run you get all of the logs for the history of the workspace, not just the logs for the processes you just started.

Yes, it appears to still be true.
My expectation when running exo run would be that it only displays logs for the current run. I wouldn't expect it to display any historical logs. I don't necessarily have an issue with it displaying logs of old components so long as those components are actually running.

repo: deref/exo


text:
go-lang-idea-plugin--485  debug  error

Error running go_demos: Cannot run program "/Users/zhanglida/Library/Application Support/IntelliJIdea14/intellij-go.jar/lib/dlv/mac/dlv" (in directory "/Users/zhanglida/go_path"): error=20, Not a directory

Please report your issue to https://github.com/go-lang-plugin-org/go-lang-idea-plugin/issues/new

repo: derekparker/delve

license: mit

license_source: bigquery


text:
Please add this to nuget

Would be really great to have this as a nuget package (on nuget.org). It is the package manager for ASP.NET (bower and friends are not supported on .NET).
Preferably with the jquery.imagesloaded-version.js and jquery.imagesloaded-version.min.js naming convention.

Closing this feature request as it didn't get enough interest. :whale:

authors: desandro sammyfa

repo: desandro/imagesloaded


text:
Add UseLet style rule

I asked a question about my rule in the #detekt channel, and there seemed to be some appetite for the rule. This is what my rule currently looks like.
I found that in a code base I was working with, there were a lot of instances of if (x != null) { do_something(x) } else null and wanted to encourage the use of ?.let in this specific case. The plugin also looks for if (x == null) { null } else do_something(x) as we had some of that too.

Messages

:book:
Thanks for adding a new rule to detekt :heart:

:white_check_mark:
We detekted that you added tests, to your rule, that's awesome!

:white_check_mark:

We detekted that you updated the default-detekt-config.yml file, that's awesome!

  Generated by :no_entry_sign: dangerJS against 81968c4923b3a8b017a1d8ff691b90349fabb275

Thank you for the rule. It looks really good.
I know this style of tests is really popular but to me it feels harder to read than necessary and hard to maintain. But I may be the only one to see it that way.
I agree with @BraisGabin that the documentation change should be its own pr.

I agree they are hard to read. But test all the cases possible cases is really nice. All those tests would be a nightmare to maintain too if they are duplicated time over time... It's a difficult compromise.

I think I might have found a false positive.
    fun testCallToCreateTempFile(s: String?) {
        val x = if (s == null) {
            println("foo")
            null
        } else {
            "x"
        }
    }

In my opinion this cannot be easily rewritten using s?.let.

@marschwar I agree that that is the exception case. We are using that as the times to use @Suppress as I don't know a meaningful way to exclude that. In our code base, we found only a single time that we were doing that vs ~100 cases where we should have just used let.  That hit rate was acceptable for us.
It was pointed out that you could rewrite that as s?.let { "X" } ?: run { println("foo") } but internally we decided that wasn't really better.

@marschwar I agree that that is the exception case. We are using that as the times to use @Suppress as I don't know a meaningful way to exclude that. In our code base, we found only a single time that we were doing that vs ~100 cases where we should have just used let. That hit rate was acceptable for us.
It was pointed out that you could rewrite that as s?.let { "X" } ?: run { println("foo") } but internally we decided that wasn't really better.

Hi, @tresni thanks for contributing towards the detekt rule. Also regarding the above false positive you can ignore that if else branch has more statements other than returning null

Also regarding the above false positive you can ignore that if else branch has more statements other than returning null

Yes. And I think that with that, and a test to demonstrate it, this rule is ready to merge.

@tresni Could you please activate your rule in the config/detekt/detekt.yml.

authors: BraisGabin atulgpt detekt-ci marschwar tresni

repo: detekt/detekt


text:
Add release notes for 1.23.1

I'm adding the release notes for 1.23.1 in the release branch. I'll replicate this same PR on main.
I've also added a filterPickRequests flag to our changelog generator as that's what I used to generate the changelog for the point release.

Messages

:book:

Thank you very much for making our website better :heart:!

  Generated by :no_entry_sign: dangerJS against e08953478200ef4b134c00e7b10ff119b8f6a613

authors: cortinico detekt-ci


text:
For compositors that use animations, the border appears before the window does

If a compositor animates the moving of windows, the border appears where the window will be, while the window is still moving

Not much I could do about it since the compositor is moving windows on its own and not updating the window positions. You could if there was an api for the compositor, but then you would need to support a lot of compositors and afaik picom doesn't have one.

license: Unlicense


text:
🛑 OKTicket is down

In 312fa85, OKTicket (https://www.okticket.es) was down:

HTTP code: 0
Response time: 0 ms

Resolved: OKTicket is back up in b2efb52.

repo: dev-okticket/status


text:
Draft: feat(controller): nodes route

Overall explanation of our work
Implementation of routes to get nodes :

[x] GET /node : Retrieve all nodes saved with pagination
[x] GET/node/<node_id> : Retrive one node with his id

Architecture
Code is split in 3 parts:

Service : Implement all the logic to retrive nodes
Controller : It contains all routes and the functions called
Model : Contains all the models used by the two others

Please rebase on top of the project branch and the DCO will pass.

authors: GridexX sameo

repo: dev-sys-do/kudo


text:
It's not working for me.

The command is not recognized

Please provide repro steps with screenshots

Soory, I did it again and it works great, thanks

repo: devanshbatham/revwhoix


text:
Merge master with documentation branch

Merge and apply changes from "internal-documentation" branch to master

Branch is merged into master.

authors: VaclovasV kestas-devbridge

repo: devbridge/Front-End-Toolkit


text:
Fix FAB while scrolling on Dashboard

Fixes #145
Please let me know if there are any changes @kshitijalwadhi

Hey @rish07 . Please attach some GIF's to demonstrate the changes (similar to screenshots in your previous PR).

@kshitijalwadhi will fix the flutter analyze bug but I can't seem to find the hard wrapping option in my Android Studio:

You are at the correct place afaik. Try changing that 80 to 900 and save the files again.

@Deepanshu-Rohilla

@kshitijalwadhi Changed it to 900 and fixed the analyze bug.

The problem with hard-wrap still seems to be there.
@Deepanshu-Rohilla can you guide him how to fix that in Android Studio?
I have only worked on VS Code.

@kshitijalwadhi one way to fix it is to merge this PR, pull the new code on your system, change the formatting and push the changes as an amend to my previous commit

@rish07 This is the setting in my machine currently (macOS).
Make sure that after changing the settings from 80 to 900, you've again reformatted the changed files (using reformat code with dartfmt option).
If the problem still persists, you check https://github.com/devclub-iitd/ShareACab/blob/master/CONTRIBUTING.md for stackoverflow links.

@Deepanshu-Rohilla There doesn't seem to be any such option in my version of the Android Studio(4.1.1).

Ah right @kshitijalwadhi just saw it on my physical device. Let me find another approach to this. The problem is FAB is on Dashboard widget but the scrolling in the triplist.dart. So even tho I can detect the scroll direction in the child, the only way I can update the state of the parent is to call a function that sets the state of the Dashboard widget. That is what I have done here, I am not sure why is it setting states abruptly. Do you have any approach in mind?

@kshitijalwadhi fixed the hard wrapping issue

I would suggest moving the FAB on triplist.dart, so we can access setState only when needed. Or do let me know if there's any other approch

Try out the approach that you think might work out.

Closing this pull request now. Because this feature was already added in another pr.

authors: Deepanshu-Rohilla kshitijalwadhi rish07 tmibvishal

repo: devclub-iitd/ShareACab


text:
update maintainer name to 'The Dev Container Contrib Community'

@danielbraun89 - I was looking through our index and saw that we're currently listing your name for the contributions to your awesome devcontainers-contrib repos!
Please let me know if you'd like to keep it as-is, but I think it would be clearer to list these Features with something along the lines of 'The Dev Container Contrib Community'.

Note that only one member exists in devcontainers-contrib organization, and @danielbraun89 clearly declared in https://github.com/devcontainers-contrib/features/issues/316 that they had no intention of adding another member.
(@danielbraun89 has deleted https://github.com/devcontainers-contrib/features/issues/316 and cannot confirm this now, but I believe @jcbhmr, who was discussing this with @danielbraun89 in https://github.com/devcontainers-contrib/features/issues/316, has the right to comment on this PR)

My understanding is that the @devcontainers-contrib organization is a tad misleading in name. The organization functions more as a "@danielbraun89's namespace for devcontainer features" than it does as a proper "community hub" for features. Sure, you can suggest features, open PRs, but, as @eitsupi has already stated:

Note that only one member exists in devcontainers-contrib organization, and @danielbraun89 clearly declared in https://github.com/devcontainers-contrib/features/issues/316 that they had no intention of adding another member.

The gist is that it's less a "community hub" of sorts (like I originally thought; you can see this in the changes I made in hope that it would grow) and more of "danielbraun98's devcontainers stash" sorta like https://github.com/codspace is for @joshspicer. The maintenance and expansion will be limited due to it being, in essence, a side project or a custom namespace; and that's OK, I just don't know how you want to represent that in the name/author of the org.

Note that only one member exists in devcontainers-contrib organization, and @danielbraun89 clearly declared in https://github.com/devcontainers-contrib/features/issues/316 that they had no intention of adding another member.
(@danielbraun89 has deleted https://github.com/devcontainers-contrib/features/issues/316 and cannot confirm this now, but I believe @jcbhmr, who was discussing this with @danielbraun89 in https://github.com/devcontainers-contrib/features/issues/316, has the right to comment on this PR)

In reference to that deleted 316 issue, which I know you also mentioned in https://github.com/devcontainers-contrib/features/pull/317, it was where I inquired about how we could improve the workflow to avoid being tied to a single person's throughput. We discussed the outlines of what @danielbraun89 (the ultimate authority of @devcontainers-contrib) wanted as a vision. It was decided that maybe I could open some PRs to put a notice in the CONTRIBUTING.md of the various repos that this was a single-person led org that had no intention to expand due to time and other commitments. This clarified the vision and gradually led me to stop open PRs and retract my suggested improvements that I knew would never happen due to it being, in essence, danielbraun89/devcontainer-features just in a different namespace, not a true "community hub" like @vercel-community or other similar projects. All in all, I have zero influence over the @devcontainers-contrib project now.

Thanks for the context @jcbhmr and @eitsupi.  My intention here was only to fix what I thought was an oversight (@danielbraun89 was an early adopter to our index and the key maintainer in this YAML file might be a bit vague).
Given what you all have shared, i'll close this PR and allow Daniel to reopen if he so choose.
PS: Thank you both for your awesome contributions, both within the devcontainers-contrib org and outside :)

@danielbraun89 - I was looking through our index and saw that we're currently listing your name for the contributions to your awesome devcontainers-contrib repos!
Please let me know if you'd like to keep it as-is, but I think it would be clearer to list these Features with something along the lines of 'The Dev Container Contrib Community'.

Although this is now closed - I want to thank you for bringing this up
devcontainer-contrib repo has over 15+ (greatly welcomed!) contributers but indeed - currently it is mainly I who code, generate, and maintain the features. I now understand "devcontainer-contrib" is a loaded name. It comes with certain minimal expectations (for example of adding contributers as privileged organizational members). In order to avoid friction in the future, I simply plan to rename the organization to something different (Will have to make sure however, that old packages still remain under same repo name, in order to not break anybody who rely on them)

authors: danielbraun89 eitsupi jcbhmr joshspicer


text:
🛑 N1 is down

In d179776, N1 (http://n1.clusterciar.com.ar) was down:

HTTP code: 0
Response time: 0 ms

Resolved: N1 is back up in 54bcf25.


text:
HttpGetAsync functions return cached results when run on Windows Phone 8.1

Windows phone does auto caching if it detects the same network call more than once. So executing the same SOQL query will return cached results even if there was a change on the server side.
Adding the following before calls when running on Windows Phone fixes this:
request.Headers.IfModifiedSince = new DateTimeOffset(DateTime.Now);

Good to know. Did you want to submit a pull request with this addition?
Anyone see any reason why adding this globally would be problematic?

In theory - adding this globally would never return data. Since my client implementation does not have cache like Windows Phone, I would never see old data?
Maybe it would be better to expose somehow http request, because now there is only http client injected in constructor?
that's my guess.

Closing this. If it's something we should still consider please let me know and we can take a look.

authors: jhorst11 tomajar wadewegner


text:
use with react-addons-shallow-compare

I haven't looked at it closely, but this might be same issue as #14

@JoeMattie npm install react-addons-shallow-compare doesn't work?  That package just seems to be a basic diff: https://github.com/facebook/react/blob/master/src/addons/shallowCompare.js
Not sure why it wouldn't work, since it doesn't depend on React or anything.

The problem is that shallowCompare requires 'shallowEqual' from 'react/lib/shallowEqual'.
You can easily create your own version with something like:
import shallowequal from 'shallowequal';

const shallowCompare = (instance, nextProps, nextState) => {

    return (
        !shallowequal(instance.props, nextProps) ||
        !shallowequal(instance.state, nextState)
    );
};

export default shallowCompare;

I also wrote a little lib to take care of this The problem is that shallowCompare requires 'shallowEqual' from 'react/lib/shallowEqual'.
You can easily create your own version with something like:
import shallowequal from 'shallowequal';

const shallowCompare = (instance, nextProps, nextState) => {

    return (
        !shallowequal(instance.props, nextProps) ||
        !shallowequal(instance.state, nextState)
    );
};

export default shallowCompare;

I also wrote a little lib to take care of this
https://www.npmjs.com/package/preact-shallow-compare

@tkh44 Awesome work. We should get this added to the preact website. I can make a new section for "Libraries & Add-ons".

For those struggling with a similar error due to a dependency using this package (and are new to webpack), you have to add this line to your webpack.babel.js:
alias: {
   /* Other stuff */
   'react-addons-shallow-compare': 'preact-shallow-compare'
}

@TheNeikos I would use the https://github.com/tkh44/shallow-compare. I depreciated preact-shallow-compare in favor of the more generic name.

authors: JoeMattie TheNeikos developit tkh44

repo: developit/preact-compat


text:
webpack build fails with preact typescript radium

Before/After installing preact-compat getting the same error on webpack build
ERROR in ./node_modules/radium/lib/enhancer.js
Module not found: Error: Can't resolve 'react' in '/home/k1r0s/Works/qmenta-proto/node_modules/radium/lib'
 @ ./node_modules/radium/lib/enhancer.js 11:13-29
 @ ./node_modules/radium/lib/index.js
 @ ./src/my-button.tsx
 @ ./src/app.tsx
 @ multi ./src/app

package.json
  "name": "asd",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "npm run server:dev",
    "build": "webpack",
    "server:dev": "webpack-dev-server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "preact": "^8.2.5",
    "preact-compat": "^3.17.0",
    "radium": "^0.19.5",
    "ts-loader": "^2.3.7",
    "typescript": "^2.5.3",
    "webpack": "^3.6.0"
  },
  "devDependencies": {
    "webpack-dev-server": "^2.9.1"
  }
}

webpack.config.js
module.exports = {
    devtool: 'source-map',
    entry: ['./src/app'],
    output: {
        path: '/home/k1r0s/Works/qmenta-proto/dist',
        filename: 'app.js'
    },
    resolve: {
        extensions: ['.js', '.ts', '.tsx']
    },
    module: {
        loaders: [
            {
                test: /\.tsx?$/,
                loaders: ['ts-loader']
            }
        ]
    }
};

tsconfig.json
{
  "compilerOptions": {
    "sourceMap": true,
    "module": "commonjs",
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "jsx": "react",
    "jsxFactory": "h",
    "target": "es5"
  },
  "include": [
    "src/*.ts",
    "src/*.tsx"
  ]
}

solved with ..
$ touch ./node_modules/react.js
$ echo "export * from 'preact-compat';" >> ./node_modules/react.js
:\

I'll update this issue if something fails

Radium throwing Uncaught TypeError: Super expression must either be null or a function, not undefined :(((((


text:
Documentation about environment variables and XState

This adds some documentation about the use of environment variables and XState in the JavaScript component.
@kylebarron @batpad while XState is becoming increasingly popular, some JS devs might not be familiar with it. I tried to add basic instructions on how to develop with it. Please let me know if you have questions or suggestions on how to improve the developer documentation.

Thanks!

authors: kylebarron vgeorge

repo: developmentseed/lonboard


text:
Wheels not available for recent releases

It looks like there was an error during the CI job on recent releases when building the wheel for the overall titiler package, the subpackages seemed to build fine:
https://github.com/developmentseed/titiler/actions/runs/7452624450/job/20276373833#step:7:401
This results in an error when I try to install the package with pip (v23.3.1):
$ python3 -m pip install titiler
Collecting titiler
  Downloading titiler-0.16.1.tar.gz (5.3 kB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Preparing metadata (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [41 lines of output]
      Traceback (most recent call last):
        File "/private/tmp/venv/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 353, in <module>
          main()
        File "/private/tmp/venv/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 335, in main
          json_out['return_val'] = hook(**hook_input['kwargs'])
                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/tmp/venv/lib/python3.11/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py", line 152, in prepare_metadata_for_build_wheel
          whl_basename = backend.build_wheel(metadata_directory, config_settings)
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/build.py", line 58, in build_wheel
          return os.path.basename(next(builder.build(directory=wheel_directory, versions=['standard'])))
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/plugin/interface.py", line 155, in build
          artifact = version_api[version](directory, **build_data)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/wheel.py", line 412, in build_standard
          for included_file in self.recurse_included_files():
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/plugin/interface.py", line 176, in recurse_included_files
          yield from self.recurse_selected_project_files()
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/plugin/interface.py", line 180, in recurse_selected_project_files
          if self.config.only_include:
             ^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/config.py", line 781, in only_include
          only_include = only_include_config.get('only-include', self.default_only_include()) or self.packages
                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/wheel.py", line 231, in default_only_include
          return self.default_file_selection_options.only_include
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        File "/opt/homebrew/Cellar/python@3.11/3.11.6_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/functools.py", line 1001, in __get__
          val = self.func(instance)
                ^^^^^^^^^^^^^^^^^^^
        File "/private/var/folders/0b/ql7ss_5s1d5082x_3zcgszn80000gn/T/pip-build-env-2qt_2dyn/overlay/lib/python3.11/site-packages/hatchling/builders/wheel.py", line 219, in default_file_selection_options
          raise ValueError(message)
      ValueError: Unable to determine which files to ship inside the wheel using the following heuristics: https://hatch.pypa.io/latest/plugins/builder/wheel/#default-file-selection

      At least one file selection option must be defined in the `tool.hatch.build.targets.wheel` table, see: https://hatch.pypa.io/latest/config/build/

      As an example, if you intend to ship a directory named `foo` that resides within a `src` directory located at the root of your project, you can define the following:

      [tool.hatch.build.targets.wheel]
      packages = ["src/foo"]
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed

× Encountered error while generating package metadata.
╰─> See above for output.

note: This is an issue with the package mentioned above, not pip.
hint: See above for details.

Potentially the cause of #748

See https://github.com/developmentseed/titiler/discussions/750
The meta package shouldn't be used anyway and we should stop making it available IMO
The meta package has no python code so there is no need for wheels 🤷♂

Ah sorry, didn't think to check discussions first

ref https://github.com/pypa/hatch/discussions/1128

fixed in https://github.com/developmentseed/titiler/commit/a6af70307bd29ad5f4b48adc59dab99c5e7391a5

authors: JackDunnNZ vincentsarago

repo: developmentseed/titiler


text:
Add readiness and liveness probe for controller and webhook server

Add readiness and liveness probe for controller and webhook server.
It came from issues.redhat.com/browse/CRW-683
issues.redhat.com/browse/CRW-916

The related PR on Che Operator side https://github.com/eclipse/che-operator/pull/610/files#diff-435eecb1d2af40ee96747f88ab71eb2758da989c92f76dcb1f714fc1b300c633R116

Is implemented in https://github.com/devfile/devworkspace-operator/pull/309

repo: devfile/devworkspace-operator


text:
Add an ability to generate some secrets for workspace

Is your enhancement related to a problem? Please describe.
Currently, the reconcile loop works in the following way:

evaluate objects according to status of the devfile (no communication with cluster)
flush them onto cluster

And if the devfile is not changed then the first part should always have the same result.
We already have some piece which must be regenerated for each workspace, or even on each workspace start - it's cookies_secret for oauth-proxy container https://github.com/che-incubator/che-workspace-operator/blob/master/pkg/controller/workspacerouting/solvers/oauth_proxy_container.go#L85
Also, oauthclient is comming.
Describe the solution 1

evaluate objects according to status of the devfile. Generate some values with rand (no communication with cluster)
flush them onto cluster, but before flushing - override randomized values with cluster ones

Describe the solution 2

evaluate objects according to status of the devfile. Generate some values with rand if missing on the cluster or fill in with the already existing
flush them onto cluster

At this point we don't have a use-case for it since openshift oauth routing is removed.
Good proposal Josh prepared is located at https://github.com/devfile/devworkspace-operator/pull/68/files and is about having secret with fixed name - secret-store, that will be managed by DWO and component will be able to set key there without value, while value is going to be generated by DWO before flushing on the cluster.

Closing as out of date.

authors: amisevsk sleshchenko


text:
Propagate workspace .spec.started to DevWorkspaceRouting

What does this PR do?
Add field .spec.started to DevWorkspaceRouting and propagate the owning workspace's .spec.started there. When a workspace is stopped, currently we simply end the routing reconcile early, but in the future this could be used to perform cleanup (e.g. remove services/routes for stopped workspaces).
This change has the effect of always triggering at least one reconcile in the routing controller when a workspace is started.
What issues does this PR fix or reference?
Closes https://github.com/devfile/devworkspace-operator/issues/602
Is it tested? How?
Start a workspace, stop a workspace.
PR Checklist

[ ] E2E tests pass (when PR is ready, comment /test v8-devworkspace-operator-e2e, v8-che-happy-path to trigger)

[ ] v8-devworkspace-operator-e2e: DevWorkspace e2e test
[ ] v8-che-happy-path: Happy path for verification integration with Che

/test v8-devworkspace-operator-e2e, v8-che-happy-path

Seems it's a breaking chang and DWCO fails to route routing https://gcsweb-ci.apps.ci.l2s4.p1.openshiftapps.com/gcs/origin-ci-test/pr-logs/pull/devfile_devworkspace-operator/604/pull-ci-devfile-devworkspace-operator-main-v8-che-happy-path/1440398068900958208/artifacts/che-happy-path/che-happy-path/artifacts/eclipse-che-info/che-operator-65c7f8454d-tw5fp-che-operator.log
and screencast proves it, but happy test is too positive and happy with that ) Or it's just PR check. Will ask @musienko-maxim to discover the reason.
And we probably should revert it and the only safest solution I see - use annotation instead.

Should fix the problem with always happy happy path test https://github.com/devfile/devworkspace-operator/pull/609


text:
Any plans to make it compatible with Vue4?

I tried to upgrade my project to Vue4 and veaury is the only package stopping the show. Is there any plans for it to make it work with Vue4?

@rouralberto
As far as I know, the vue team has not released vue4, whether it is an alpha version or a beta version, or even a canary version.

Damn, sorry. You are right. I confused the Vite 4 with Vue 4 in the error message! I'll investigate how to make it work with Vite 4 first. Sorry!

@rouralberto
Ok, I will build a vite4 project for debugging

authors: devilwjp rouralberto

repo: devilwjp/veaury


text:
能否提供一份React项目中使用外部Vue组件(通过npm安装的业务组件)的示例代码

能否提供一份在React项目中是用通过npm 安装的Vue组件，我在现有的示例代码里面没有找到类似的代码，谢谢

@wo-xiaoxiao 使用通过npm安装的vue组件是最简单的了，你就直接使用就行，不用做什么初始配置

import { applyVueInReact } from 'veaury'
import VueComponent from 'xxxxxxx'
const TestFromVue = applyVueInReact(VueComponent )

authors: devilwjp wo-xiaoxiao


text:
erlang:get_stacktrace/0 removed from Erlang 24

Will there be an update for Erlang 24 that removes erlang:get_stacktrace/0?
poolboy.erl:26:-define(GET_STACK(_), erlang:get_stacktrace()).

My mistake.  It does build fine.

repo: devinus/poolboy

license: ISC


text:
Migrate code from oasp4j-ide to this repository

See also https://github.com/oasp/oasp4j/issues/662 and do the analogue thing for oasp4j-ide to devon-ide.

Considered done.

repo: devonfw/devon-ide


text:
Add devops4mecode's file

created a branch, created a file and made a commit, and opened a pull request

Add devops4mecode's file

created a branch, created a file and made a commit, and opened a pull request

created a branch, created a file and made a commit, and opened a pull request


text:
Feedback Loops - grammar/typos

In Examples of Critical Feedback Loops
users -> users'
consumer is -> consumer, is

Fixed in #28