Saturday 30 September 2023

How to support push notification in capacitor with websocket

I'm not finding any correct solution to implement push notification with websocket

Question: My simple requirement like whatsApp when a message comes it show the message in the form of push notification.

Here is the documentation for push notification.

/**
 *  Push notification code
*/


import { PushNotifications } from '@capacitor/push-notifications';

const addListeners = async () => {
  await PushNotifications.addListener('registration', token => {
    console.info('Registration token: ', token.value);
  });

  await PushNotifications.addListener('registrationError', err => {
    console.error('Registration error: ', err.error);
  });

  await PushNotifications.addListener('pushNotificationReceived', notification => {
    console.log('Push notification received: ', notification);
  });

  await PushNotifications.addListener('pushNotificationActionPerformed', notification => {
    console.log('Push notification action performed', notification.actionId, notification.inputValue);
  });
}

const registerNotifications = async () => {
  let permStatus = await PushNotifications.checkPermissions();

  if (permStatus.receive === 'prompt') {
    permStatus = await PushNotifications.requestPermissions();
  }

  if (permStatus.receive !== 'granted') {
    throw new Error('User denied permissions!');
  }

  await PushNotifications.register();
}

const getDeliveredNotifications = async () => {
  const notificationList = await PushNotifications.getDeliveredNotifications();
  console.log('delivered notifications', notificationList);


/**
   Web Socket related code
*/

// Create WebSocket connection.
const socket = new WebSocket("ws://localhost:8080");

// Connection opened
socket.addEventListener("open", (event) => {
  socket.send("Hello Server!");
});

// Listen for messages
socket.addEventListener("message", (event) => {
  console.log("Message from server ", event.data);
  PushNotifications.send("Message from server ", event.data);  // added for testing but does not work
});

}

Please help me, thanks in advance!!



from How to support push notification in capacitor with websocket

How do you combine multiple filters in isotope JS?

I have two content type areas which contain unique filter options. These are:

  1. type
  2. tag

I'm trying to utilise isotope.js, to achieve a dual filtering layout, but it always gives the last clicked filter priority.

See use case here (reference below demo):

  1. If I click "Blog & News", I should see two posts (works)
  2. If I then also click "PDF", I should then see no posts (as no blog post that has pdf as a class exists). Instead, it shows me the case study post that has the pdf class.
  3. If I then also click "article", it should again show me no posts as no post exists that has the class blog-and-news pdf article. But instead shows me the case study post with it.

The filters in combination isn't working.

The documentation says the arrange() method can handle multiple filter instances, but it isn't working in my use case.

I've also tried using the concatValues() function to concatenate the values (as shown in many demos), but it still doesn't yield the correct results.

See interactive demo here.

document.addEventListener('DOMContentLoaded', function() {

  var container = document.querySelector('.grid');
  var gridItems = container.querySelectorAll('.grid-item');
  const optionLinks = document.querySelectorAll('.rSidebar__options-li');

  var iso = new Isotope(container, {
    itemSelector: '.resourceCard',
    layoutMode: 'fitRows',
    transitionDuration: '0.5s',
  });

  var filters = {};

  function concatValues( obj ) {
    var value = '';
    for ( var prop in obj ) {
      value += obj[ prop ];
    }
    return value;
  }

  function handleFilterClick(event, filters, iso) {
    var listItem = event.target;
    var filterGroup = listItem.closest('.rSidebar__options').getAttribute('data-filter-group');
    var filterValue = listItem.getAttribute('data-filter');

    if (filters[filterGroup] === filterValue) {
      delete filters[filterGroup];
    } else {
      filters[filterGroup] = filterValue;
    }

    // Combine filters
    var filterValues = Object.values(filters).join(', ');
    // var filterValues = concatValues( filters );


    // debugging
    console.log('List Item:', listItem);
    console.log('Filter Group:', filterGroup);
    console.log('Filter Value:', filterValue);
    console.log('Filters Object:', filters);
    console.log('Filter Values:', filterValues);

    iso.arrange({ filter: filterValues });
  }

  optionLinks.forEach(function(optionLink) {
    optionLink.addEventListener('click', function(event) {
      event.preventDefault();
      this.classList.toggle('selected');
      handleFilterClick(event, filters, iso);
    });
  });


});
.post {
  padding: 100px;
}

.rSidebar__box {
  margin-bottom: 30px;
}
.rSidebar__options {
  padding-left: 0;
}
.rSidebar__options-li {
  margin-bottom: 17px;
  display: flex;
  align-items: center;
  cursor: pointer;
  width: fit-content;
}
.rSidebar__options-li.selected .rSidebar__options-square {
  background-color: #185A7D;
}
.rSidebar__options-square {
  height: 20px;
  width: 20px;
  transition: all 0.5s ease;
  border: 2px solid #000000;
}
.rSidebar__options-label {
  margin-left: 10px;
}

.grid {
  display: flex;
  flex-wrap: wrap;
  margin: -14px 0 0 -14px;
}
.grid-item {
  box-sizing: border-box;
  width: calc(33.33% - 14px);
  margin: 14px 0 18px 14px;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://unpkg.com/isotope-layout@3/dist/isotope.pkgd.min.js"></script>


<div class="post">
  <div class="container">
    <div class="row justify-content-between">

      <!-- SIDEBAR -->
      <div class="col-3">
        <div class="rSidebar">

          <!-- tags -->
          <div class="rSidebar__box">
            <span class="rSidebar__label d-block fw-bold">Filter by tag</span>
            <ul class="rSidebar__options button-group" data-filter-group="type">
              <li class="rSidebar__options-li" data-filter=".pdf">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".pdf">PDF</span>
              </li>
                <li class="rSidebar__options-li" data-filter=".article">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".article">Article</span>
              </li>
            </ul>
          </div>

          <!--  type -->
          <div class="rSidebar__box">
            <span class="rSidebar__label d-block fw-bold">Filter by type</span>
            <ul class="rSidebar__options button-group" data-filter-group="type">
              <li class="rSidebar__options-li" data-filter=".blogs-and-news">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".blogs-and-news">Blog & News</span>
              </li>
                <li class="rSidebar__options-li" data-filter=".case-study">
                <span class="rSidebar__options-square"></span>
                <span class="rSidebar__options-label d-block buttonTemp" data-filter=".case-study">Case Studies</span>
              </li>
            </ul>
          </div>
          <!-- end -->
        </div>
      </div>
      <!-- END -->

      <!-- GRID -->
      <div class="col-7">
        <div class="grid">
          <article class="resourceCard grid-item case-study pdf"><span class="resourceCard__body-title">Case study, PDF post</span></article>
          <article class="resourceCard grid-item blogs-and-news"><span class="resourceCard__body-title">Blogs and news post</span></article>
          <article class="resourceCard grid-item blogs-and-news article"><span class="resourceCard__body-title">Blogs and news, article post</span></article>
        </div>
      </div>
      <!-- END -->

    </div>
  </div>
</div>

Latest attempt

document.addEventListener('DOMContentLoaded', function() {

  var container = document.querySelector('.grid');
  var gridItems = container.querySelectorAll('.grid-item');
  const optionLinks = document.querySelectorAll('.rSidebar__options-li');

  var iso = new Isotope(container, {
    itemSelector: '.resourceCard',
    layoutMode: 'fitRows',
    transitionDuration: '0.5s',
  });

  var filters = {};

  function concatValues( obj ) {
    var value = '';
    for ( var prop in obj ) {
      value += obj[ prop ];
    }
    return value;
  }

  function handleFilterClick(event, filters, iso) {
    var listItem = event.target;
    var filterGroup = listItem.closest('.rSidebar__options').getAttribute('data-filter-group');
    var filterValue = listItem.getAttribute('data-filter');

    var allowMultiple = listItem.closest('.rSidebar__options').getAttribute('data-multiple') === 'true';

    if (allowMultiple) {
      // toggle the filter value
      if (filters[filterGroup] && filters[filterGroup].includes(filterValue)) {
        // remove the filter value if it already exists
        filters[filterGroup] = filters[filterGroup].filter(value => value !== filterValue);
      } else {
        // add the filter value if it doesn't exist
        if (!filters[filterGroup]) {
          filters[filterGroup] = [];
        }
        filters[filterGroup].push(filterValue);
      }
    } else {
      // replace the filter value
      filters[filterGroup] = [filterValue];
    }

    var filterValues = concatValues( filters );

    // console.log('List Item:', listItem);
    // console.log('Filter Group:', filterGroup);
    // console.log('Filter Value:', filterValue);
    // console.log('Filters Object:', filters);
    // console.log('Filter Values:', filterValues);

    iso.arrange({ filter: filterValues });

  }


  optionLinks.forEach(function(optionLink) {
    optionLink.addEventListener('click', function(event) {
      event.preventDefault();
      this.classList.toggle('selected');
      handleFilterClick(event, filters, iso);
    });
  });


});


from How do you combine multiple filters in isotope JS?

How can I dynamically create and save user-defined combinations in R Shiny and shinyjqui?

This is my drag and drop app:

library(shiny)
library(shinyjqui)
library(shinyjs)
library(dplyr)


###### part 1 ------------------------------------------------------------------
#creating the list of items
df <- structure(list(AG = c("A",  "B", "C", "D")),
                row.names = c(NA,-4L), class = "data.frame")

# cells of table
connections1 <- paste0("droppable_cell", ifelse(1:2 == 1, "", 1:2), "_1")
connections2 <- paste0("droppable_cell", ifelse(1:2 == 1, "", 1:2), "_2")

connections <- c(connections1, connections2)

# Define a named list for vec_suggestion1 
vec_suggestion1 <- list(  
  droppable_cell_1 =   c("A", "B", "A", "B"),
  droppable_cell_2 =  c("A", "B", "B", "A")
)

# Create the data frame
my_df <- data.frame(connections = connections,
  stringsAsFactors = FALSE
)

my_df$vec_suggestion1 <- vec_suggestion1[my_df$connections]


###### part 2 ------------------------------------------------------------------

myComplexTableUI <-   div(id = "capture", class = "table-container",
                          div(class = "grid-table",
                              id = "montag",
                              div(class = "grid-row",
                                  div(class = "grid-cell grid-cell-text", "Montag"),
                                  lapply(1:2, function(i) {
                                    div(id = paste0("droppable_cell_", i), class = "grid-cell droppable-cell", "")
                                  })
                              )
                          )
                        
                        )

###### part 3 ------------------------------------------------------------------
# my js

jsCode <- "
$(function() {
    function createSortable(day) {
        $('[id^=droppable_cell' + day + '_]').sortable({
            connectWith: '#A, #B, [id^=droppable_cell' + day + '_]',
            drop: function(event, ui) {
                $(this).append(ui.draggable);
            }
        });
    }

    createSortable('1'); // For day1
    createSortable('2'); // For day2

  $('[id^=droppable_cell]').on('sortupdate', function(e, ui) {
        var cellId = $(this).attr('id');
        var item = ui.item.text();
        Shiny.setInputValue('dropEvent', {cell: cellId, item: item}, {priority: 'event'});
    });
});

shinyjs.pageCol = function(params) {
    $('[id^=droppable_cell]').sortable({
        connectWith: '#A, #B, [id^=droppable_cell_1], [id^=droppable_cell_2]',
        drop: function(event, ui) {
            $(this).append(ui.draggable);
        }
    });

    var dataArray = Object.values(params[0]);
    dataArray = dataArray[0].map((col, i) => dataArray.map(row => row[i]));

    console.log('dataArray: ', dataArray);

    var cacheA = $('#A').html();
    var cacheB = $('#B').html();

    var cacheGridCells1 = $('[id^=droppable_cell_1]').html();

shinyjs.setSuggestion = function (idxSuggestion) {
  $.each(dataArray, function (index, value) {
    var cellSelector = '#' + dataArray[index][0];
    var classIndex = idxSuggestion === 1 ? 1 : 2;
    
    // Retrieve the items for the current cell from dataArray
    var items = dataArray[index][idxSuggestion];
    if (typeof items === 'string') {
      items = [items]; // Convert to array if there is only one item
    }
    
    // Clear the cell content
    $(cellSelector).html('');
    
    // Append each item to the cell
    $.each(items, function (i, item) {
      if (item === null) {
        return true;
      }
      
      // Determine the style based on the item value
      var itemStyle = '';
      if (item === 'A') {
        itemStyle = 'background-color: #ffcc66;'; // Corresponding to Bootstrap's warning color
      } else if (item === 'B') {
        itemStyle = 'background-color: #5cb85c;'; // Corresponding to Bootstrap's success color
      }
      
      var cellHTML = '<div data-value=\"' + item
                   + '\" class=\"btn btn-default ui-sortable-handle\" style=\"' + itemStyle + ' margin: 1px;\" jqui_sortable_idx=\"letters__' 
                   + (index + 1).toString()
                   + '\">'
                   + item
                   + '</div>';
      
      $(cellSelector).append(cellHTML);
    });
  });
}
    shinyjs.resetDnD = function (params) {
    $('#A').html(cacheA).sortable('refresh');
    $('#B').html(cacheB).sortable('refresh');
    $('[id^=droppable_cell_1]').html(cacheGridCells1).sortable('refresh');
    }
};



      "
ui <- fluidPage(
  
  useShinyjs(),
  extendShinyjs(text = jsCode, functions = c("pageCol", "setSuggestion")),
  
  ###### part 4 ------------------------------------------------------------------
  
  # css table design
  tags$head(
    tags$style(
      HTML("
        .custom-title-panel button {
          margin-left: 10px;
          margin-top: 10px; 
        }
        .grid-table {
          width: 220px;
          border-collapse: collapse;
        }
        .grid-cell {
          width: 100%;
          height: 210px;
          border: 1px solid black;
          background-color: white;
          text-align: left;
          margin: 0;
          padding: 5px;
        }
        .grid-cell-text {
          display: flex;
          align-items: center;
          justify-content: center;
          height: 50px;
          background-color: steelblue;
          color: white;
          font-size: 18px;
        }
        .table-container {
          display: flex;
          position: absolute;
          left: 260px;
          top: 20px;
          margin-top: 0px;
          overflow: hidden;
        }
      ")
    )
  ),
  
  ##################################################################################
  
  
  # btn reset
  tags$script(
    HTML(
      "$(document).ready(function() {
          $('#btn_resetDnD').click(function() {
            $('.droppable-cell').html(''); // Remove content from all elements with the class 'droppable_cell'
          });
        });"
    )
  ),

  
  # my items:      
  tags$div(
    style = "position: relative; height: 50px;", # Setting a height to contain the buttons
    tags$div(style = "position: absolute; top: 30px; left: 20px;",
             orderInput("A", "", items = df$AG[1], as_source = TRUE, connect = connections, width = "100%", item_class = "warning")
    ),
    tags$div(style = "position: absolute; top: 30px; left: 65px;",
             orderInput("B", "", items = df$AG[2], as_source = TRUE, connect = connections, width = "100%", item_class = "success")
    )
  ),
  
  # my table:
  myComplexTableUI,
  
  # my buttons:
  tags$div(style = "position: absolute; top: 500px; left: 260px; display: flex; flex-direction: row;",
           actionButton("btn_suggestion1", "Suggestion1"),
           actionButton("btn_resetDnD", "Reset")
           
  )
  )


server <- function(input, output, session) {
  
  shinyjs::js$pageCol(my_df)
  
  observeEvent(input$btn_suggestion1, {
    shinyjs::disable("btn_suggestion1")
    shinyjs::js$setSuggestion(1)
    shinyjs::enable("btn_suggestion1")
  })
  
}

shinyApp(ui, server)

The app is doing basically this: enter image description here

I would like to dynamically create the 'vec_suggestion1' input, which is currently hardcoded. I want the system to recognize and save the user’s input when they drag it to 'droppable_cell1'.

vec_suggestion1 <- list(  
  droppable_cell_1 =   c("A", "B", "A", "B"),
  droppable_cell_2 =  c("A", "B", "B", "A")
)

I am aiming to provide the user with the ability to drag and drop their ideal combinations of A and B. This information should be dynamically saved to 'vec_suggestion2'. Subsequently, any additional combinations of A's and B's should also be saved, but to 'vec_suggestion3', 'vec_suggestion4', and so on. Along with the creation of each new vector, a corresponding new button should be added, such as 'btn_suggestion2', 'btn_suggestion3', etc.



from How can I dynamically create and save user-defined combinations in R Shiny and shinyjqui?

Invalid hook call importing an external module

I'm writing a package called "Formcomponent", with the help of React + React Bootstrap.

This is the index.tsx

/**
 * Renders a component for a form.
 */
import React from "react";
import Form from "react-bootstrap/Form";

/**
 * List of props
 * @returns
 */
interface FormcomponentProps {
  name: string;
}

export const Formcomponent = ({ name }: FormcomponentProps) => {
  return (
    <Form.Group controlId={name}>
      {/* input text */}
      <Form.Label>{name}</Form.Label>
      <Form.Control type="text" name={name} />
    </Form.Group>
  );
};

When I build it, I got in dist:

index.d.ts

/**
 * Renders a component for a form.
 */
import React from "react";
/**
 * List of props
 * @returns
 */
interface FormcomponentProps {
    name: string;
}
export declare const Formcomponent: ({ name }: FormcomponentProps) => React.JSX.Element;
export {};

and

index.js

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Formcomponent = void 0;
/**
 * Renders a component for a form.
 */
var react_1 = __importDefault(require("react"));
var Form_1 = __importDefault(require("react-bootstrap/Form"));
var Formcomponent = function (_a) {
    var name = _a.name;
    return (react_1.default.createElement(Form_1.default.Group, { controlId: name },
        react_1.default.createElement(Form_1.default.Label, null, name),
        react_1.default.createElement(Form_1.default.Control, { type: "text", name: name })));
};
exports.Formcomponent = Formcomponent;

I import in another React project in package.json as "@sineverba/form-component": "file:../../personali/npm-pkg-form-component", and in the App.jsx of React project I use it as

import * as React from "react";
import { Form } from "react-bootstrap";
import { Formcomponent } from "@sineverba/form-component";

export const App = () => {
  return (
    <Form>
      <FormComponent name="ciao" />
    </Form>
  );
};

export default App;

But I got in console

Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: [...]

and

Uncaught TypeError: Cannot read properties of null (reading 'useMemo') at FormGroup.js:11:26

(FormGroup.js from react bootstrap is defined as

import * as React from 'react';
import { useMemo } from 'react';
import FormContext from './FormContext';
import { jsx as _jsx } from "react/jsx-runtime";
const FormGroup = /*#__PURE__*/React.forwardRef(({
  controlId,
  // Need to define the default "as" during prop destructuring to be compatible with styled-components github.com/react-bootstrap/react-bootstrap/issues/3595
  as: Component = 'div',
  ...props
}, ref) => {
  const context = useMemo(() => ({
    controlId
  }), [controlId]);
  return /*#__PURE__*/_jsx(FormContext.Provider, {
    value: context,
    children: /*#__PURE__*/_jsx(Component, {
      ...props,
      ref: ref
    })
  });
});
FormGroup.displayName = 'FormGroup';
export default FormGroup;

Update 1

In index.tsx (external component) I imported React as import * as React from "react"; but got same errors.

Update 2

I uploaded the repository here: https://github.com/sineverba/npm-pkg-form-component

Of course it is not published (yes), to test it can be cloned on local and used with "@sineverba/form-component": "file:../../personali/npm-pkg-form-component"

A small news. I tried to export a simply <p>Hello World</p> (so a simple HTML) and it works only if I use as name Formcomponent and not FormComponent (see the capital of C).

By the way, changing the name to Formcomponent and introducing the React Bootstrap Form, got same errors.



from Invalid hook call importing an external module

Friday 29 September 2023

How can I prevent the overwriting of an implicit user image in this Firebase 9 app?

I am making a chat app with React 18 and Firebase 9.

In the Register form, I have an input of type file, for uploading user's avatar.

The avatar form field is optional and there is a default-avatar.png file that I uploaded manually in Storage and is intended for as default user image.

In Register.jsx I have:

import React, { useState } from "react";
import md5 from "md5";
import FormCard from "../components/FormCard/FormCard";
import Success from "../components/Alerts/Success";
import Error from "../components/Alerts/Error";
import { make, register } from "simple-body-validator";
import { createUserWithEmailAndPassword, updateProfile } from "firebase/auth";
import { ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";
import { doc, setDoc } from "firebase/firestore";
import { auth, db, storage } from "../firebaseConfig";

// Custom validation rule
register('image-only', function (value) {
  let allowedFormats = ["jpg", "jpeg", "png"];
  let format = value.name.split('.')[1].toLowerCase();
  return allowedFormats.includes(format);
}, function() {
  return "Only JPG, JPEG, and PNG files are allowed.";
});

export default function Register() {
  const initialFormData = {
    firstName: "",
    lastName: "",
    email: "",
    avatar: "",
    password: "",
    password_confirmation: ""
  };

  const validationRules = {
    firstName: ["required", "string", "min:3", "max:255"],
    lastName: ["required", "string", "min:3", "max:255"],
    email: ["required", "email"],
    avatar: ["image-only"],
    password: ["required", "min:6", "confirmed"],
    password_confirmation: ["required"]
  };

  const validator = make(initialFormData, validationRules);
  const [formData, setFormData] = useState(initialFormData);

  // Form validation errors
  const [errors, setErrors] = useState(validator.errors());
  // Firebase errors
  const [error, setError] = useState(false);

  const [pristineFields, setPristineFields] = useState(() =>
    Object.keys(initialFormData)
  );

  const handleChange = (event) => {
    const { name, value, files } = event.target;
    setFormData((prevFormData) => {
      const newValue = files?.length > 0 ? files[0] : value;
      const newFormData = { ...prevFormData, [name]: newValue };
      const newPristineFields = pristineFields.filter((f) => f !== name);

      validator.setData(newFormData).validate();
      const validationErrors = validator.errors();
      newPristineFields.forEach((f) => validationErrors.forget(f));
      setErrors(validationErrors);

      setPristineFields(newPristineFields);

      return newFormData;
    });
  };

  const handleSubmit = async (event) => {
    event.preventDefault();

    if (!validator.setData(formData).validate()) {
      setErrors(validator.errors());
    } else {

      const email = formData.email;
      const password = formData.password;
      const successContainer = document.getElementById('successAlert');
      const errContainer = document.getElementById('errorAlert');

      try {
        const response = await createUserWithEmailAndPassword(auth, email, password);
        // Hide error
        errContainer.classList.add('d-none');

        // Show success
        successContainer.classList.remove('d-none');

        // Create avatar filename
        const meta = { contentType: 'image/jpeg, image/png' };
        const date = new Date().getTime();
        let userAvatar = formData.avatar
          ? md5(`${formData.email}-${date}`) + '.' + formData.avatar.name.split(".")[1]
          : "default-avatar.png";
        const storageRef = ref(storage, userAvatar);

        // Upload image
        await uploadBytesResumable(storageRef, formData.avatar, meta).then(() => {
          getDownloadURL(storageRef).then(async (url) => {
            try {
              // Update profile
              await updateProfile(response.user, {
                avatar: url,
              });

              // Store user
              await setDoc(doc(db, "users", response.user.uid), {
                uid: response.user.uid,
                firstName: formData.firstName,
                lastName: formData.lastName,
                email: formData.email,
                avatar: userAvatar,
              });
            } catch (error) {
              setError(true);
              console.log(error)
            }
          })
        })

      } catch (error) {
        setError(true);
        errContainer.append(error.message);
        errContainer.classList.remove('d-none');
      }
    }

    setPristineFields([]);
  };

  return (
    <FormCard title="Register">

      {/* Alerts */}
      <Error dismissible={true} error={error} />
      <Success dismissible={true} message="You have registered successfully. You can sign in!" />

      <form onSubmit={handleSubmit}>
        <div
          className={`mb-2 form-element ${errors.has("email") ? "has-error" : null
            }`}
        >
          <label for="email" className="form-label">
            Email address
          </label>
          <input
            type="email"
            id="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
            className="form-control form-control-sm"
          />
          {errors.has("email") ? (
            <p className="invalid-feedback">{errors.first("email")}</p>
          ) : null}
        </div>

        <div
          className={`mb-2 form-element ${errors.has("avatar") ? "has-error" : null
            }`}
        >
          <label for="avatar" className="form-label">
            Avatar
          </label>
          <input
            type="file"
            id="avatar"
            name="avatar"
            onChange={handleChange}
            className="form-control form-control-sm"
          />
          {errors.has("avatar") ? (
            <p className="invalid-feedback">{errors.first("avatar")}</p>
          ) : null}
        </div>

        <div className="pt-1">
          <button type="submit" className="btn btn-sm btn-success fw-bold">
            Submit
          </button>
        </div>
      </form>
    </FormCard>
  );
}

The problem

If the user does not upload an avatar, the image I uploaded manually in Storage (default-avatar.png) is overwritten by an empty image.

Questions

  1. What am I doing wrong?
  2. What is the most reliable way to fix the issue?


from How can I prevent the overwriting of an implicit user image in this Firebase 9 app?

How to make navigator.mediaDevices.getUserMedia({ video: true }) work on mobile

I am trying to record video with my phone and use it as a background on the site I am building. The goal is to do stuff with the video stream, but first I need to just be able to render it at all. I have the code below:

https://codepen.io/jasperkennis/pen/yLGjOrw

That I am also testing as a simple html page exposed via python -m http.server over ngrok to make sure it is sitting on https. On my laptop it happily takes the webcam, but on phone (iphone 12 and 15 tested) I can see that it gets access to the camera (the permission modal shows correctly) and I can place an alert to see how far it gets, but it never seems to try to render anything.

I'm not sure where to go from here, maybe it should not work, any help would be appreciated.



from How to make navigator.mediaDevices.getUserMedia({ video: true }) work on mobile

How can I use django-filter's DateTimeFromToRangeFilter with Graphene?

I'm attempting to use an instance of django-filter's DateTimeFromToRangeFilter in conjunction with a custom FilterSet. However, this does not work when I attempt to do the following:

class CustomFilterSet(FilterSet):
    modified = django_filters.IsoDateTimeFromToRangeFilter()

    class Meta:
        fields = "__all__"
        model = Custom

This does not result in additional fields or annotations being created, like I'd expect based on the docs. Something like:

f = F({'modified_after': '...', 'modified_before': '...'})

If I inspect the single field (modified) which has been added to my DjangoFilterConnectionField, I see the following:

{'creation_counter': 395, 'name': None, '_type': <String meta=<ScalarOptions name='String'>>, 'default_value': Undefined, 'description': None, 'deprecation_reason': None}

So, how do I configure this filter such that I can write a query like the following?

query {
    allTheSmallThings(
        modified_before: "2023-09-26 17:21:22.921692+00:00"
    ) {
        edges {
            node {
                id
            }
        }
    }
}

UPDATE: I can confirm that I'm able to use the FilterSet subclass as documented. The issue seems to be with the fields that are/not being generated by Graphene.



from How can I use django-filter's DateTimeFromToRangeFilter with Graphene?

How to understand the output of scipy's quadratic_assignment function?

I'm trying to use scipy's quadratic_assignment function but I can't understand how the output can describe an optimal solution. Here is a minimal example where I compare a small matrix to itself:

import numpy as np
from scipy.optimize import quadratic_assignment

# Parameters
n = 5
p = np.log(n)/n   # Approx. 32%

# Definitions
A = np.random.rand(n,n)<p

# Quadratic assignment
res = quadratic_assignment(A, A)

print(res.col_ind)

and the results seem to be random assignments:

[3 0 1 4 2]
[3 2 4 1 0]
[3 2 1 0 4]
[4 3 1 0 2]
[2 3 0 1 4]
...

However, according to the docs col_ind is supposed to be the Column indices corresponding to the best permutation found of the nodes of B. Since the input matrices are equal (B==A), I would thus expect the identity assignment [0 1 2 3 4] to pop out. Changing n to larger values does not help.

Is there something I am getting wrong?



from How to understand the output of scipy's quadratic_assignment function?

Does PyTorch support stride_tricks as in numpy.lib.stride_tricks.as_strided?

It is possible to make cool things by changing the strides of an array in Numpy like this:

import numpy as np
from numpy.lib.stride_tricks import as_strided

a = np.arange(15).reshape(3,5)

print(a)
# [[ 0  1  2  3  4]
#  [ 5  6  7  8  9]
#  [10 11 12 13 14]]

b = as_strided(a, shape=(3,3,3), strides=(a.strides[-1],)+a.strides)

print(b)
# [[[ 0  1  2]
#   [ 5  6  7]
#   [10 11 12]]

#  [[ 1  2  3]
#   [ 6  7  8]
#   [11 12 13]]

#  [[ 2  3  4]
#   [ 7  8  9]
#   [12 13 14]]]


# Get 3x3 sums of a, for example
print(b.sum(axis=(1,2)))
# [54 63 72]

I searched a similar method in PyTorch and found as_strided, but it does not support strides which makes an element have multiple indices referring to it, as the warning says:

The constructed view of the storage must only refer to elements within the storage or a runtime error will be thrown, and if the view is “overlapped” (with multiple indices referring to the same element in memory) its behavior is undefined.

In particular it says that the behavior is undefined for the example above where elements have multiple indices.

Is there a way to make this work (with documented, specified behavior)? If not, then why PyTorch does not support this?



from Does PyTorch support stride_tricks as in numpy.lib.stride_tricks.as_strided?

Testing invoking Sagemaker endpoint for Computer Vision Classification

I built a out-of-box CNN and deployed using AWS Step Functions. I have these custom functions for the endpoint:

def input_fn(data, content_type):
    '''
    take in image
    '''
    if content_type == 'application/json':
        img = Image.open(io.BytesIO(data))
        img_arr = np.array(img)
        resized_arr = cv2.resize(img_arr, (img_size, img_size)) 
        return resized_arr[None,...]
    else:
        raise RuntimeException("{} type is not supported by this endpoint.".format(content_type))
        
    
    
def model_fn():
    '''
    Return model
    '''

    client = boto3.client('s3')
    client.download_file(Bucket=s3_bucket_name, Key='model/kcvg_cv_model.h5', Filename='kcvg_cv_model.h5')
    model = tf.keras.saving.load_model('kcvg_cv_model.h5')   

    return model

def predict_fn(img_dir):
    model = model_fn()
    data = input_fn(img_dir)
    prob = model.predict(data)
    return np.argmax(prob, axis=-1)

When I run this code

from sagemaker.predictor import RealTimePredictor
from sagemaker.serializers import JSONSerializer

endpoint_name = 'odi-ds-belt-vision-cv-kcvg-endpoint-Final-Testing4'

# Read image into memory
payload = None
with open("117.jpg", 'rb') as f:
    payload = f.read()
    
predictor = RealTimePredictor(endpoint_name = endpoint_name, sagemaker_session=sm_sess, serializer=JSONSerializer)
inference_response = predictor.predict(data=payload)
print (inference_response)

I get the following error

The class RealTimePredictor has been renamed in sagemaker>=2.
See: https://sagemaker.readthedocs.io/en/stable/v2.html for details.

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[14], line 11
      8     payload = f.read()
     10 predictor = RealTimePredictor(endpoint_name = endpoint_name, sagemaker_session=sm_sess, serializer=JSONSerializer)
---> 11 inference_response = predictor.predict(data=payload)
     12 print (inference_response)

    File ~/anaconda3/envs/odi-ds/lib/python3.9/site-packages/sagemaker/base_predictor.py:177, in Predictor.predict(self, data, initial_args, target_model, target_variant, inference_id, custom_attributes)
        129 def predict(
        130     self,
        131     data,
       (...)
        136     custom_attributes=None,
        137 ):
        138     """Return the inference from the specified endpoint.
        139 
        140     Args:
       (...)
        174             as is.
        175     """
    --> 177     request_args = self._create_request_args(
        178         data,
        179         initial_args,
        180         target_model,
        181         target_variant,
        182         inference_id,
        183         custom_attributes,
        184     )
        185     response = self.sagemaker_session.sagemaker_runtime_client.invoke_endpoint(**request_args)
        186     return self._handle_response(response)
    
    File ~/anaconda3/envs/odi-ds/lib/python3.9/site-packages/sagemaker/base_predictor.py:213, in Predictor._create_request_args(self, data, initial_args, target_model, target_variant, inference_id, custom_attributes)
        207     args["EndpointName"] = self.endpoint_name
        209 if "ContentType" not in args:
        210     args["ContentType"] = (
        211         self.content_type
        212         if isinstance(self.content_type, str)
    --> 213         else ", ".join(self.content_type)
        214     )
        216 if "Accept" not in args:
        217     args["Accept"] = self.accept if isinstance(self.accept, str) else ", ".join(self.accept)
    
    TypeError: can only join an iterable

I am guessing there is something I am doing wrong in the input_fn but I am not exactly sure, any suggestions?



from Testing invoking Sagemaker endpoint for Computer Vision Classification

Thursday 28 September 2023

What does an uncaught products in collection error mean and how can I fix it?

I have a next.js website that get's products from Shopify. It was working well until a couple of months ago when the site stopped building on the development server.

When I run the website locally I now get a Cannot read properties of undefined error and the page doesn't load.

What are likely causes of the issue and how do I go about fixing it?

error - lib/shopify.js (353:31) @ getProductsInCollection
TypeError: Cannot read properties of undefined (reading 'collectionByHandle')
  351 |       const cursor = response.data.products.edges[num - 1].cursor;
  352 | 
> 353 |       return data.concat(await recursiveCatalog(cursor));
      |                               ^
  354 |     } else {
  355 |       return data;
  356 |     }

This is how I get the data from Shopify

    const domain = process.env.SHOPIFY_STORE_DOMAIN
    const storefrontAccessToken = process.env.SHOPIFY_STOREFRONT_ACCESSTOKEN
    
    async function ShopifyData(query) {
      const URL = `https://${domain}/api/2021-07/graphql.json`
    
      const options = {
        endpoint: URL,
        method: "POST",
        headers: {
          "X-Shopify-Storefront-Access-Token": storefrontAccessToken,
          "Accept": "application/json",
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ query })
      }
    
      try {
        const data = await fetch(URL, options).then(response => {
          return response.json()
        })
    
        return data
      } catch (error) {
        throw new Error("Products not fetched")
      }
    }

The error seems to occur when I get products from a collection.

export async function getProductsInCollection() {
  const query = `
  {
    collectionByHandle(handle: "frontpage") {
      title
      products(first: 60) {
        edges {
          node {
            id
            title
            productType
            handle
            metafields(first: 2) {
              edges {
                  node {
                      namespace
                      key
                      value
                  }
              }
          }
        }
      }
    }
  }`
  const response = await ShopifyData(query);
  const allProducts = response.data.collectionByHandle.products.edges
    ? response.data.collectionByHandle.products.edges
    : [];
  return allProducts;
}
export async function recursiveCatalog(cursor = '', initialRequest = true) {
  let data;

  if (cursor !== '') {
    const query = `{
      products(after: "${cursor}", first: 250) {
        edges {
          cursor
          node {
            id
            handle
          }
        }
        pageInfo {
          hasNextPage
        }
      }
    }`;

    const response = await ShopifyData(query);
    data = response.data.products.edges ? response.data.products.edges : [];

    if (response.data.products.pageInfo.hasNextPage) {
      const num = response.data.products.edges.length;
      const cursor = response.data.products.edges[num - 1].cursor;
      console.log('Cursor: ', cursor);

      return data.concat(await recursiveCatalog(cursor));
    } else {
      return data;
    }
  } else {
    const query = `{
      products(first: 250) {
        edges {
          cursor
          node {
            id
            handle
          }
        }
        pageInfo {
          hasNextPage
        }
      }
    }
    `;

    const response = await ShopifyData(query);
    data = response.data.products.edges ? response.data.products.edges : [];

    if (response.data.products.pageInfo.hasNextPage) {
      const num = response.data.products.edges.length;
      const cursor = response.data.products.edges[num - 1].cursor;

      return data.concat(await recursiveCatalog(cursor));
    } else {
      return data;
    }
  }
}


from What does an uncaught products in collection error mean and how can I fix it?

Is there any way to autofill text fields for a web-embedded internet speed test?

Such a simple thing, yet I'm beginning to think it's not possible. OpenSpeedTest provides HTML5 code to embed a speed test widget in your webpage. I have implemented this for my website, however there is no API to fetch the results and autofill my text fields. Obviously I also cannot access a cross-origin frame using Javascript, so I don't know what to do. Speedtest Ookla no longer has an accessible API to do this, so I'm not sure what other options I have here.

<script>
    function getSpeedTestResults() {
        // Attempt to access the iframe content
        let iframe = document.getElementById('speedtest');
        let iframeContent = iframe.contentDocument || iframe.contentWindow.document;

        // Attempt to access the results inside the iframe (this will likely be blocked)
                let downloadSpeed = iframeContent.getElementById('downResult').textContent;
        let uploadSpeed = iframeContent.getElementById('upRestxt').textContent;
        let ping = iframeContent.getElementById('pingResult').textContent;

        // Set the values in your fields
        document.getElementById('download').value = downloadSpeed;
        document.getElementById('upload').value = uploadSpeed;
        document.getElementById('ping').value = ping;
    }
</script>


from Is there any way to autofill text fields for a web-embedded internet speed test?

How to calculate a Gaussian kernel matrix efficiently in numpy?

def GaussianMatrix(X,sigma):
    row,col=X.shape
    GassMatrix=np.zeros(shape=(row,row))
    X=np.asarray(X)
    i=0
    for v_i in X:
        j=0
        for v_j in X:
            GassMatrix[i,j]=Gaussian(v_i.T,v_j.T,sigma)
            j+=1
        i+=1
    return GassMatrix
def Gaussian(x,z,sigma):
    return np.exp((-(np.linalg.norm(x-z)**2))/(2*sigma**2))

This is my current way. Is there any way I can use matrix operation to do this? X is the data points.



from How to calculate a Gaussian kernel matrix efficiently in numpy?

How to retrieve source documents via LangChain's get_relevant_documents method only if the answer is from the custom knowledge base

I am making a chatbot which accesses an external knowledge base docs. I want to get the relevant documents the bot accessed for its answer, but this shouldn't be the case when the user input is something like "hello", "how are you", "what's 2+2", or any answer that is not retrieved from the external knowledge base docs. In this case, I want retriever.get_relevant_documents(query) or any other line to return an empty list or something similar.

import os
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.chains import ConversationalRetrievalChain 
from langchain.memory import ConversationBufferMemory
from langchain.chat_models import ChatOpenAI
from langchain.prompts import PromptTemplate

os.environ['OPENAI_API_KEY'] = ''

custom_template = """
This is conversation with a human. Answer the questions you get based on the knowledge you have.
If you don't know the answer, just say that you don't, don't try to make up an answer.
Chat History:
{chat_history}
Follow Up Input: {question}
"""
CUSTOM_QUESTION_PROMPT = PromptTemplate.from_template(custom_template)

llm = ChatOpenAI(
    model_name="gpt-3.5-turbo",  # Name of the language model
    temperature=0  # Parameter that controls the randomness of the generated responses
)

embeddings = OpenAIEmbeddings()

docs = [
    "Buildings are made out of brick",
    "Buildings are made out of wood",
    "Buildings are made out of stone",
    "Buildings are made out of atoms",
    "Buildings are made out of building materials",
    "Cars are made out of metal",
    "Cars are made out of plastic",
  ]

vectorstore = FAISS.from_texts(docs, embeddings)

retriever = vectorstore.as_retriever()

memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True)

qa = ConversationalRetrievalChain.from_llm(
    llm,
    vectorstore.as_retriever(),
    condense_question_prompt=CUSTOM_QUESTION_PROMPT,
    memory=memory
)

query = "what are cars made of?"
result = qa({"question": query})
print(result)
print(retriever.get_relevant_documents(query))

I tried setting a threshold for the retriever but I still get relevant documents with high similarity scores. And in other user prompts where there is a relevant document, I do not get back any relevant documents.

retriever = vectorstore.as_retriever(search_type="similarity_score_threshold", search_kwargs={"score_threshold": .9})


from How to retrieve source documents via LangChain's get_relevant_documents method only if the answer is from the custom knowledge base

Wednesday 27 September 2023

Swipe gesture without change UI and animation

I can find many tutorials on swiping for navigation or swiping on a component, but I would like to be able to swipe on the entire page like with navigation. Still, instead of navigating or doing anything at all with the UI, I would like a completed swipe to call a method so I can fetch some new data depending on if the user swiped left or right.

How would I do this? By using a PanGestureHandler and somehow trigger a function to load new content of the swipe performed? How do I detect a horizontal swipe without making any UI changes?



from Swipe gesture without change UI and animation

The block is cut off when scrolling a fixed element on the page

I made a small adaptation here for adding cart items and added a script that I use for my cart itself

This cart should stick to the right edge and always scroll up and down on the page

In principle, everything works, but there is a small problem, when I click on Add 1 and Add 2, the items will supposedly be added to the cart and my page will look like this

enter image description here

I deliberately circled the empty white space in red because this indentation should always remain, but it turns out that when I scroll down the page and the cart intersects the blue block, this indentation disappears, which should not happen

What could be the problem? The entire main script is implemented in the VPDetail function

let VPDetail = {
    init: function () {
        let _self = this;
        $(window).resize(function () {
            _self.positionContainer();
        });

        $(window).scroll(function () {
            _self.positionContainer();
        });

        _self.positionContainer();
    },
    positionContainer: function () {
        let rp = $(".js-real-position");
        let column = $('.js-column-to-scroll-block');
        let columnAdd = $('.js-column-to-scroll-block-additional');
        let sp = $(".js-static-position");
        let topDelta = 20;
        let top = topDelta;

        if (column.position().top + column.height() + columnAdd.height() - sp.height() < $(document).scrollTop() + topDelta) {
            top = column.position().top + column.height() + columnAdd.height() - sp.height() - $(document).scrollTop();
        }

        if ($(document).scrollTop() + topDelta > rp.position().top) {
            sp.css({top: top + 'px', 'position': 'fixed'});
        } else {
            sp.css({top: '0', 'position': 'static'});
        }

        sp.width(sp.parent().width());
    },
}

$(function (){
    VPDetail.init();
})

$(".add1").click(function () {
  $('.add1').css('display', 'none');
  $('.added1').css('display', 'block');
});

$(".add2").click(function () {
  $('.add2').css('display', 'none');
  $('.added2').css('display', 'block');
});

$(".added1").click(function () {
  $('.added1').css('display', 'none');
  $('.add1').css('display', 'block');
});

$(".added2").click(function () {
  $('.added2').css('display', 'none');
  $('.add2').css('display', 'block');
});
.color-block {
    padding: 24px;
    background: #08e8de;
    border-radius: 10px;
}

.cart-block {
    padding: 24px;
    background: #8A2BE2;
    border-radius: 10px;
}

.add1, .add2 {
  height: 300px;
  cursor: pointer;
}

.added1, .added2 {
  cursor: pointer;
  height: 150px;
  display: none;
}

.package-detail-info {
  margin-top: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/css/bootstrap.min.css" integrity="sha512-t4GWSVZO1eC8BM339Xd7Uphw5s17a86tIZIj8qRxhnKub6WoyhnrxeCIMeAqBPgdZGlCcG2PrZjMc+Wr78+5Xg==" crossorigin="anonymous" referrerpolicy="no-referrer"
/>


<div class="row margin-block-small pt-4">
    <div class="col-12 col-md-8 col-lg-9">
        <h1 class="h2"><strong>Package</strong></h1>
        <div class="vp-tickets js-vp-tickets">
            <div class="mb-3"></div>
            <div class="please-select-items alert alert-info"><i class="fa fa-info-circle"></i> Please select items</div>
            <div class="color-block mb-4" id="ticket-1">
                <div class="item">
                    <div class="add1">Add 1</div>
                </div>
            </div>
      <div class="color-block mb-4" id="ticket-2">
                <div class="item">
                    <div class="add2">Add 2</div>
                </div>
            </div>
        </div>
    </div>
    <div class="col-12 col-md-4 col-lg-3 js-column-to-scroll-block" style="">
        <div class="package-detail-info">
            <div class="js-real-position" style="">
                <div class="js-static-position static-position" style="top: 0px; position: static; width: 337.25px;">
                    <div class="vp-small-order-info cart-block mb-3">
                        <div class="js-selected-info"></div>
                        <div><small>Options:</small></div>
            <div class="added1">Added 1</div>
            <div class="added2">Added 2</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

<div class="row margin-block-small">
    <div class="col-12 col-md-8 col-lg-9 js-column-to-scroll-block-additional">
        <div style="height: 1000px; background: blue;"></div>
    </div>
</div>


from The block is cut off when scrolling a fixed element on the page

Vite is ignoring compiler errors until the file is used at runtime

For some reason vite is letting me login to my app and do whatever, until I navigate to a page that makes use of the file with the compilation error. At that point it refuses to render and throws the error in the console.

I also do not see the errors in the terminal output from vite. However, my linter AND the problems tab in VSCode both see the error.

enter image description here

Any idea how to fix vite to revert back to the default behaviour where the entire app must compile and only then the website renders?

Thanks



from Vite is ignoring compiler errors until the file is used at runtime

Python port of R's 'relaimpo' package

I need to calculate Lindeman-Merenda-Gold (LMG) scores, for my regression analysis. I've found that is is available under relaimpo package in R-Language.

Unfortunatelly, I don't have any experience with R. I checked the internet but I couldn't find. Is there a python port of this package ? If it doesn't exist, is it possible to use that package through python somehow ?



from Python port of R's 'relaimpo' package

How can I manually split a model amongst multiple GPU's using pytorch lightning?

I have a model that is too large for a single GPU. It has a list of transformers on it that once I run it through the 17th hidden layer, I get a CUDA out of memory error I want to therefore run it on multiple GPUs.

import torch
import torch.nn as nn
import pytorch_lightning as pl

class SplitModel(pl.LightningModule):
    def __init__(self, device1, device2):
        super(SplitModel, self).__init__()

        # Define your model segments
        self.segment1 = #arbitraty in layer
        self.transformers = #a torch.nn.ModuleList of transformers
        self.segment2 = #arbitrary out layer

        self.loss_fn = nn.CrossEntropyLoss()
        self.device1 = torch.device('cuda:0')
        self.device2 = torch.device('cuda:1')

    def forward(self, x):
        # Forward pass for segment1 on device1
        x = self.segment1(x)
        for i, transformer in enumerate(self.transformers):
             current_device = '['+''.join("{}: {} ".format(name, next(child.parameters()).device if list(child.parameters()) else "CPU") for name, child in transformer.named_children()) + ']'
              print("itterating through transformer {} on device {}".format(i, current_device))
               attn, ff = transformer
               x = attn(x) + x
               x = ff(x) + x

        # Forward pass for segment2 on device2
        x = self.segment2(x)

        return x

    def training_step(self, batch, batch_idx):
        inputs, labels = batch

        # Forward pass
        outputs = self(inputs)

        # Calculate loss using segment2 outputs
        loss = self.loss_fn(outputs, labels)

        # Log loss for monitoring (optional)
        self.log('train_loss', loss)

        return loss

    def configure_optimizers(self):
        optimizer = torch.optim.Adam(self.parameters(), lr=1e-3)
        return optimizer

model = SplitModel()
ddp_strategy = DDPStrategy(find_unused_parameters=True)
Trainer = pl.Trainer(precision="16-mixed", accelerator="cuda", devices=[0, 1], strategy=ddp_strategy)
data_loader = #some dataloader
Trainer.fit(model, data_loader)

So then this would be an example output:

itterating through transformer 0 on device [0: cuda:0]
itterating through transformer 1 on device [0: cuda:0 1: cuda:0]
itterating through transformer 2 on device [0: cuda:0 1: cuda:0]
itterating through transformer 3 on device [0: cuda:0 1: cuda:0]
itterating through transformer 4 on device [0: cuda:0 1: cuda:0]
itterating through transformer 5 on device [0: cuda:0 1: cuda:0]
itterating through transformer 6 on device [0: cuda:0 1: cuda:0]
itterating through transformer 7 on device [0: cuda:0 1: cuda:0]
itterating through transformer 8 on device [0: cuda:0 1: cuda:0]
itterating through transformer 9 on device [0: cuda:0 1: cuda:0]
itterating through transformer 10 on device [0: cuda:0 1: cuda:0]
itterating through transformer 11 on device [0: cuda:0 1: cuda:0]
itterating through transformer 12 on device [0: cuda:0 1: cuda:0]
itterating through transformer 13 on device [0: cuda:0 1: cuda:0]
itterating through transformer 14 on device [0: cuda:0 1: cuda:0]
itterating through transformer 15 on device [0: cuda:0 1: cuda:0]
itterating through transformer 16 on device [0: cuda:0 1: cuda:0]
itterating through transformer 17 on device [0: cuda:0 1: cuda:0]
CUDA out of memory error

However, if I were to add this line of code to the forward pass:

self.Segment2 = self.Segment2.to(self.device2)
for i, transformer in enumerate(self.transformers):
     if i == 17:
         x = x.to(self.device2)
     if i > 16:
         transformer = transformer.to(self.device2)
    #the rest of iterating through the transformers
return self.Segment2(x).to(self.device1)

Then I do not get a CUDA out of memory error however, I do get the following error from the backward pass:

RuntimeError: grad.device() == bucket_view.device() INTERNAL ASSERT FAILED at "../torch/csrc/distributed/c10d/reducer.cpp":314, please report a bug to PyTorch.

I have also looked into sharding the model, instead of manually deciding which parts to put on the GPU. The strategy in the pl.Trainer module would be strategy="fsdp", I have gotten an error about the batch norm variables one being torch.cuda.FloatTensor and torch.cuda.HalfTensor.

Is there maybe a way to do this where I create a custom backward layer that changes the device manually?



from How can I manually split a model amongst multiple GPU's using pytorch lightning?

Tuesday 26 September 2023

open3d create_from_point_cloud_poisson adds weird plane not present in original point cloud model

I have this script which is supposed to convert a point cloud into a reconstructed surface using open3d. It works for most point cloud models, but I don't understand why it always adds this generated plane between the original shape. How do I get rid of it?

enter image description here

Here's the script:

import bpy
import numpy as np
import open3d as o3d

mesh_obj = bpy.data.objects['Sphere']
vertices = np.array([v.co.xyz for v in mesh_obj.data.vertices], dtype=np.float64)

pd = o3d.geometry.PointCloud()
pd.points = o3d.utility.Vector3dVector(vertices)
pd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=0, max_nn=100))

mesh_path = 'C:/Users/harry/OneDrive/Desktop/pc.ply'
o3d.io.write_point_cloud(mesh_path, pd)

surface, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pd, depth=10, width=0, scale=1, linear_fit=True)

vertices = np.asarray(surface.vertices)
faces = np.asarray(surface.triangles)

mesh_name = 'reconstructed_mesh'
mesh = bpy.data.meshes.new(mesh_name)
mesh.from_pydata(vertices, [], faces)
obj = bpy.data.objects.new(mesh_name, mesh)

scene = bpy.context.scene
scene.collection.objects.link(obj)


from open3d create_from_point_cloud_poisson adds weird plane not present in original point cloud model

firebase generic filtering needs indexes for each combination

i have the following code to query properties (paginated) with filters:

const propertyCollectionRef = db.collection('properties')

    let queryRef = propertyCollectionRef;

    let query: any = db.collection('properties');

    if (filters) {
        for (const [key, value] of Object.entries(filters)) {
            if (key !== 'page') {
                switch (key) {
                    case "price":
                        query = query.where(key, '<=', parseInt(value));
                        break;
                    case "bathrooms":
                        query = query.where(key, '==', parseInt(value));
                        break;
                    case "beds":
                        query = query.where(key, '==', parseInt(value));
                        break;
                    case "min-area":
                        query = query.where("area", '>=', parseInt(value));
                        break;
                    case "max-area":
                        query = query.where("area", '<=', parseInt(value));
                        break;
                    case "typ":
                        query = query.where(key, '==', value);
                        break;
                    default:
                        query = query.where(key, '==', value);
                        break;
                }
            }
        }
    }



    const offset = (page - 1) * pageSize

    const querySnapshot = await query
        .limit(pageSize)
        .offset(offset).get();

firebase wants me to create an index for each query combination (

code: 9,
  details: 'The query requires an index. You can create it here:...

) made when choosing different filters, for example i need to create one for filtering price and typ. but also one when filtering for price, typ and bathrooms

how is it possible to make this more "generic" - i can't think of firebase to make it such complicated...



from firebase generic filtering needs indexes for each combination

Scroll Animation component does not work with Next.js but worked with create react app

I recently migrated a small project from create react app to next js.

All is fine besides that my code for scroll animations suddenly does not work in Next js and I am not sure why. A it does not throws errors, the animation just does not happen at all. But it worked perfectly fine inside my create react app project.

I am not sure where the issue is. Has anyone a tip?

Thats the component.

 'use client';
import { useEffect, useRef, useState } from 'react';

export interface IProps {
  children: React.ReactNode;
  variant: 'slideFromRight' | 'slideFromLeft';
}

function useIsVisible(ref: React.RefObject<HTMLDivElement>) {
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(([entry]) => {
      //remove if for more than one animation
      if (entry.isIntersecting) setVisible(entry.isIntersecting);
    });
    if (ref.current !== null && observer.takeRecords().length === 0)
      observer.observe(ref.current);
    return () => {
      observer.disconnect();
    };
  });

  return visible;
}

export default function ScrollAnimation(props: IProps) {
  //state handling
  const ref = useRef<HTMLDivElement>(null);
  const visible = useIsVisible(ref);

  return (
    <div ref={ref}>
      <div className={visible ? 'animate-' + props.variant : 'notVisible'}>
        {props.children}
      </div>
    </div>
  );
}

And then I import it and wrap it this way:

<ScrollAnimation variant="slideFromRight">
    <h1 className="text-white font-bold text-2xl ">Lorem Ipsum</h1>
        <hr className="border border-white my-4" />
        <p className="text-white font-montserrat text-left font-bold">
          Lorem Ipsum is simply dummy text of the printing and typesetting
          industry. Lorem Ipsum has been the industrys standard dummy text ever
          since the 1500s, when an unknown printer took a galley of type and
          scrambled it to make a type specimen book. It has survived not only
          five centuries, but also the leap into electronic typesetting,
          remaining essentially unchanged. It was popularised in the 1960s with
          the release of Letraset sheets containing Lorem Ipsum passages, and
          more recently with desktop publishing software like Aldus PageMaker
          including versions of Lorem Ipsum
        </p>
      </ScrollAnimation>

the slideFromLeft and Right is declared in my tailwind config:

keyframes: {
        slideFromLeft: {
          '0%': {
            transform: 'translate3d(-100%, 0, 0)',
            visibility: 'hidden',
          },
          '100%': {
            transform: 'translateZ(0)',
          },
        },
        slideFromRight: {
          '0%': {
            transform: 'translate3d(100%, 0, 0)',
            visibility: 'hidden',
          },
          '100%': {
            transform: 'translateZ(0)',
          },
        },
      },
       animation: {
        slideFromLeft: '3s both slideFromLeft ',
        slideFromRight: '3s both slideFromRight ',
      },

Here is a codesandbox with a minimal reproducible code example, but the animation never gets triggered, however the same code works in a create react app (CRA) setup without issues.

Codesanbox

EDIT:

Here are some additional information regarding the answer of Siavash1991.

  1. There are no errors in the browser console
  2. Intersection Observer is supported in all browsers, I do not use an old environment
  3. refCurrent is not null
  4. Css animations are correctly defined in my tailwind conf. As I said the same setup works in CRA.
  5. Parent component is rendered properly. Same here, the setup is identical on CRA
  6. All deps are up to date, I just use react and next and no other deps for the animation
  7. Check SSR (Server-Side Rendering) Issues: This component is a client component but the page where I import my animation is not marked with use client. However marking is as use client also did not bring any change
  8. Rebuild: I did in fact rebuild the project from scratch. Created a new next project and migrated page by page adapting tot he next js logic.
  9. Test in different browsers: Does not work in all major browsers
  10. No compat issues
  11. Consider using a different animation library: I do not use any animation library, ist my custom code and do not want to. As this would be a regression.


from Scroll Animation component does not work with Next.js but worked with create react app

Debug Failure. Unhandled SyntaxKind: ImportClause

I'm trying to build a React app using Webpack inside Docker container.

Running the command webpack --mode production --progress --config webpack.prod.js ends up with the following error:

ERROR in ./src/app/App.tsx
Module build failed (from ./node_modules/ts-loader/index.js):
Error: Debug Failure. Unhandled SyntaxKind: ImportClause.
    at pipelineEmitWithHintWorker (/app/node_modules/typescript/lib/typescript.js:114180:22)
    at pipelineEmitWithHint (/app/node_modules/typescript/lib/typescript.js:113711:17)
    at pipelineEmitWithSourceMaps (/app/node_modules/typescript/lib/typescript.js:117731:13)
    at pipelineEmitWithComments (/app/node_modules/typescript/lib/typescript.js:117399:13)
    at pipelineEmit (/app/node_modules/typescript/lib/typescript.js:113651:13)
    at emitExpression (/app/node_modules/typescript/lib/typescript.js:113635:13)
    at emitImportDeclaration (/app/node_modules/typescript/lib/typescript.js:115606:13)
    at pipelineEmitWithHintWorker (/app/node_modules/typescript/lib/typescript.js:113912:32)
    at pipelineEmitWithHint (/app/node_modules/typescript/lib/typescript.js:113711:17)
    at pipelineEmitWithSourceMaps (/app/node_modules/typescript/lib/typescript.js:117731:13)
 @ ./src/index.tsx 5:0-36 13:36-39

Running the same command to build on host machine (MacOS) works as expected. The container runs on node:16.13.1-alpine official image.



from Debug Failure. Unhandled SyntaxKind: ImportClause

find out if the write end of a pipe is closed

I'm trying to figure a way to know when the write end of a pipe gets closed. Is there a way to do that somehow ?

from subprocess import Popen, PIPE
p = subprocess.Popen('ls -lh', stdout = PIPE, shell = True)

def read_output(out,queue):
    for line in iter(out.readline,b''):
        print('.')

t = Thread(target=enqueue_output, args=(p.stdout,q))
t.daemon = True
t.start()

while True:
    #this only works if I put 
    #if line == '' : 
    #    out.close()
    #in the for loop of read_output, which I want to avoid.

    if p.stdout.closed :  #need to find something else than closed here...
        break

iow I'm trying to avoid to have to do out.close() in the io Thread.... I want to somehow read a property or a method of p.stdout to know if its write end has been closed.

This is really not about finding another way to read Popen's p.stdout gracefully, I have 2 others ways already. It's more about learning something I thought should be possible, but I havn't figured how to do...

Cheers !



from find out if the write end of a pipe is closed

Monday 25 September 2023

Events are not loading into the webix scheduler calendar

I want to show events in webix scheduler UNIT view But events are not getting displayed on calendar. My url is fine and receiving a successful response from the server with the data I need for the events. The response contains an array of events, and each event object has properties such as id, title, start, end, and url.

JSON response and code

var data = {
  "response": "success",
  "events": [
    {
      "id": 46,
      "url": "",
      "title": "Jeremy Madison",
      "start": "2023/09/28 09:45:00 AM",
      "end": "2023/09/28 09:45:00 AM",
      "extendedProps": {
        "calendar": "business",
        "model": {
          "id": 46,
          "appointment_type": "medical",
          "user_id": 1,
          "service_id": 1,
          "company_id": 1,
          "patient_id": 20,
          "location_id": 1,
          "time_id": null,
          "start": "2023-09-28 09:30:00",
          "end": "2023-09-28 09:45:00",
          "time": "9:30 AM",
          "duration": "15",
          "allDay": 0,
          "appointment_alert": null,
          "frequency": "1 day",
          "status": 0,
          "created_at": "2023-08-04 15:08:41",
          "updated_at": "2023-08-04 15:08:41",
          "policy_holder": null,
          "location": "peshawar",
          "code": "34214",
          "payer_name": null,
          "mobile_no": "+1 (907) 769-9091\n",
          "dob": "2006-10-23",
          "admin_sex": "female",
          "clinician_name": "Sudais Khan",
          "patient_name": "Jeremy Madison"
        }
      }
    }
  ]
}
webix.ready(function () {
    webix.CustomScroll.init();
    var id = 1;
    var apiUrl = "schedules?nid=" + id;
    var eventsLoaded = false;
    var scheduler = webix.ui({
       view: "scheduler",
       container: "my_schedules",
       id: "myScheduler",
       width: 1000,
       height: 1000,
       save: "rest->" + apiUrl,
       url: apiUrl,
       monthSelect: true,
       weekHeader: true,
       events: new webix.DataCollection({
          scheme: {
             $init: function (obj) {
                obj.start_date = webix.Date.isDate(obj.start)
                   ? obj.start
                   : webix.Date.strToDate("%Y/%m/%d %H:%i")(obj.start);
                obj.end_date = webix.Date.isDate(obj.end)
                   ? obj.end
                   : webix.Date.strToDate("%Y/%m/%d %H:%i")(obj.end);
             },
          },
       }),
       on: {
          onBeforeEventSave: function (id, data, update) {
             if (update) {
                data.start = webix.Date.dateToStr("%Y/%m/%d %H:%i")(data.start_date);
                data.end = webix.Date.dateToStr("%Y/%m/%d %H:%i")(data.end_date);
             } else {
                data.start = webix.Date.dateToStr("%Y/%m/%d %H:%i")(data.start_date);
                data.end = webix.Date.dateToStr("%Y/%m/%d %H:%i")(data.end_date);
             }
          },
       },
    });
    scheduler.attachEvent("onViewChange", function (newView) {
       if (!eventsLoaded && newView === "month") {
          scheduler.clearAll(); 
          scheduler.load(apiUrl, "json");
          eventsLoaded = true;
       }
    });
 });


from Events are not loading into the webix scheduler calendar

Sagemaker experiment tracking duplication

I am trying to train a model using script mode via AWS Sagemaker. I would like to track this training job with AWS Sagemaker Experiments together with some calculated metrics in the training job. When I start the training job a new experiment run is created successfully that tracks all the provided hyperparameters (e.g. nestimators).

However, as said earlier, additionally, I also want to track other metrics (e.g. Accuracy) in the custom script. Here I use load_run() before I fit the model and then for example log a metric with run.log_metric(). However when I do that, Sagemaker creates a new separate experiment entry in the UI which means that my hyperparameters and metrics are stored separately in two individual experiment runs:

two separate runs created by sagemaker

I would like to see the metrics and hyperparameters all in one Experiment run combined. What am I doing wrong?

Here is the abbreviated code I am using to kick off the training process:

 
exp_name = "sklearn-script-mode-experiment"

with Run(
    experiment_name=exp_name,
    sagemaker_session=sess,
) as run:

    sklearn_estimator = SKLearn('train.py',
                                    instance_type='ml.m5.large',
                                    framework_version='1.0-1',
                                    role="arn:aws:iam:::role/service-role/AmazonSageMaker-ExecutionRole-",
                                    hyperparameters={'nestimators': 100},
                                    environment={"REGION": REGION})

    sklearn_estimator.fit({'train': f's3://{BUCKET}/{S3_INPUT_PATH}'})

Here is the abbreviated train.py:

    #parsing arguments here ... etc ...
    

    model = RandomForestClassifier(n_estimators=args.nestimators,
                                   max_depth=5,
                                   random_state=1)

    with load_run(sagemaker_session=sagemaker_session) as run:

        model.fit(X, y)

        run.log_metric(name = "Final Test Loss", value = 0.9)


from Sagemaker experiment tracking duplication

Login to this site with requests

I try to automate the login to this site via requests, by working with session for the first time.

https://www.tennisenpadelvlaanderen.be/login

I would like to for example get the contents of this page, when a user is logged in.

https://www.tennisenpadelvlaanderen.be/dashboard/mijn-gegevens?

I created a login on the site, for this purpose only:

Login: hoegje+pepepepe@gmail.com Password: PepePepe

But when I try to do the POST to the login page, I get a 200 OK response, while on the site with devtools I get a 302 redirect and it redirects me to the first page of the site.

        s = requests.session()
        #Try to accept cookies
        cookieData = {'cookies_functional': 'true', 'cookies_analytics': 'true', 'cookies_social': 'false',
                      'cookies_media': 'false', 'cookies_accepted': 'true'}
        expires = datetime.datetime.utcnow() + datetime.timedelta(weeks=52)  # expires in 1 year
        for aCookieKey, aCookieValue in cookieData.items():
            acceptCookiesCookie = requests.cookies.create_cookie(aCookieKey, aCookieValue, domain='www.tennisenpadelvlaanderen.be', path='/', expires=expires.timestamp())
            s.cookies.set_cookie(acceptCookiesCookie)
            acceptCookiesCookie = requests.cookies.create_cookie(aCookieKey, aCookieValue, path='www.tennisenpadelvlaanderen.be/', expires=expires.timestamp())
            s.cookies.set_cookie(acceptCookiesCookie)
        # Response sets cookie: INGRESSCOOKIE = 1695315839.247.1714.732149|60903facce0df50e07e804a3a5c147b8
        firstResponse = s.get("https://www.tennisenpadelvlaanderen.be/login", headers={
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9,nl;q=0.8,fr;q=0.7,de;q=0.6",
            "referer": "https://www.tennisenpadelvlaanderen.be/", "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31"})
        print('=' * 50)
        print(s.cookies)
        print(firstResponse.cookies)
        print('=' * 50)

        print(s.cookies)
        submitCookies = s.cookies
        #{originalJsessionId}
        lfrSessionStateTs = str(int(datetime.datetime.now().timestamp() * 1000))
        originalJsessionId = s.cookies.get('JSESSIONID')
        originalIngressCookie = s.cookies.get('INGRESSCOOKIE')
        print(f"originalJsessionId {originalJsessionId}")
        print(f'f1 {firstResponse}')
        print(f'f2 {firstResponse.cookies}')
        print(f'f3 {firstResponse.headers}')
        print(f'f4 {firstResponse.request}')
        print(f'f5 {firstResponse.text.find("Liferay.authToken")}')
        i1 = firstResponse.text.find("Liferay.authToken")
        i2 = firstResponse.text.find(";", i1)
        Liferay_authToken = firstResponse.text[i1:i2]
        print(Liferay_authToken)
        i1 = Liferay_authToken.find("'") + 1
        i2 = Liferay_authToken.rfind("'")
        pAuthRandom = Liferay_authToken[i1:i2]
        secondResponse = s.get("https://www.tennisenpadelvlaanderen.be/login", headers={
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9,nl;q=0.8,fr;q=0.7,de;q=0.6",
            "cache-control": "max-age=0",
            "cookie": f"INGRESSCOOKIE={originalIngressCookie}; JSESSIONID={originalJsessionId}; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=nl_NL; LFR_SESSION_STATE_20101={lfrSessionStateTs}; cookies_functional=true; cookies_analytics=true; cookies_social=true; cookies_media=true; cookies_accepted=true",
            "referer": "https://www.tennisenpadelvlaanderen.be/login", "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31"},
              cookies=submitCookies)
        print(f's1 {secondResponse}')
        print(f's2 {secondResponse.cookies}')
        print(f's3 {secondResponse.headers}')
        print(f's4 {secondResponse.request}')
        print(f's5 {secondResponse.request}')

        # Redirects to: https://www.tennisenpadelvlaanderen.be/dashboard/nieuws-en-evenementen
        # TODO add content-length to headers: 'content-length': str(contentLength),
        # import string
        # characters = string.ascii_letters + string.digits
        # pAuthRandom = ''.join(random.choice(characters) for _ in range(8))
        print(f"pAuthRandom {pAuthRandom}")
        dataToSubmit = {
                     "_com_liferay_login_web_portlet_LoginPortlet_formDate": f"{lfrSessionStateTs}",
                     "_com_liferay_login_web_portlet_LoginPortlet_saveLastPath": "false",
                    "_com_liferay_login_web_portlet_LoginPortlet_redirect": "",
                    "_com_liferay_login_web_portlet_LoginPortlet_doActionAfterLogin": "false",
                     "_com_liferay_login_web_portlet_LoginPortlet_portletPath": "%2Flogin",
                     "_com_liferay_login_web_portlet_LoginPortlet_login": "hoegje%2Bpepepepe%40gmail.com",
                     "_com_liferay_login_web_portlet_LoginPortlet_password": "PepePepe",
                     "p_auth": pAuthRandom
                        }
        dataStringToSubmit = ''
        for aKey, aValue in dataToSubmit.items():
            dataStringToSubmit += f'{aKey}={aValue}&'
        dataStringToSubmit = dataStringToSubmit[:-1]
        contentLength = len(str(dataStringToSubmit))   # 2 brackets, 4 for None
        postReply = s.post("https://www.tennisenpadelvlaanderen.be/login",
               params={"p_p_id": "com_liferay_login_web_portlet_LoginPortlet", "p_p_lifecycle": "0", "p_p_state": "normal",
                       "p_p_mode": "view",
                       "_com_liferay_login_web_portlet_LoginPortlet_javax.portlet.action": "%2Flogin%2Flogin",
                       "_com_liferay_login_web_portlet_LoginPortlet_mvcRenderCommandName": "%2Flogin%2Flogin"},
               data=dataStringToSubmit,
               headers={
                "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
                "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9,nl;q=0.8,fr;q=0.7,de;q=0.6",
                "cache-control": "max-age=0", 'Content-Type': 'application/x-www-form-urlencoded',
                "cookie": f"INGRESSCOOKIE={originalIngressCookie}; JSESSIONID={originalJsessionId}; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=nl_NL; cookies_functional=true; cookies_analytics=true; cookies_social=true; cookies_media=true; cookies_accepted=true; LFR_SESSION_STATE_20101={lfrSessionStateTs}",
                "origin": "https://www.tennisenpadelvlaanderen.be", 'content-length': str(contentLength),
                "referer": "https://www.tennisenpadelvlaanderen.be/login", "upgrade-insecure-requests": "1",
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31",
                           'sec-ch-ua-mobile': '?0','sec-ch-ua-platform': "Windows", 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate',
                   'Sec-Fetch-Site': 'same-origin', 'Sec-Fetch-User': '?1', 'sec-gpc': '1', 'Upgrade-Insecure-Requests':'1',
                   'Connection': 'keep-alive'
                },
               cookies=s.cookies)
        print(f'p1 {postReply}')
        print(f'p2 {postReply.cookies}')
        print(f'p3 {postReply.headers}')
        print(f'p4 {postReply.request}')
        print(f'p5 {postReply.request}')
        # Response sets cookie: JSESSIONID = DECCD37CCA427785F666166AB6CB085E
        finalResponse = s.get("https://www.tennisenpadelvlaanderen.be/dashboard/nieuws-en-evenementen", headers={
            "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
            "accept-encoding": "gzip, deflate, br", "accept-language": "en-US,en;q=0.9,nl;q=0.8,fr;q=0.7,de;q=0.6",
            "cache-control": "max-age=0",
            "cookie": f"INGRESSCOOKIE={originalIngressCookie}; JSESSIONID={originalJsessionId}; COOKIE_SUPPORT=true; GUEST_LANGUAGE_ID=nl_NL; cookies_functional=true; cookies_analytics=true; cookies_social=true; cookies_media=true; cookies_accepted=true; LFR_SESSION_STATE_20101={lfrSessionStateTs}",
            "referer": "https://www.tennisenpadelvlaanderen.be/login", "upgrade-insecure-requests": "1",
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.31"},
              cookies=s.cookies)
        print(finalResponse)
        print(finalResponse.headers)
        print(finalResponse.text.find('Pepe'))
        print(postReply.text)

Edit: added unredacted code, since the shorter version was not enough to reproduce the issue.



from Login to this site with requests

Vue 3 shows previous route in onMounted

I'm using Vue with a dynamic navigation based on my backend. An endpoint decides what page to display based on the current route.

I've made a simplified version below with the relevant parts. Everything works fine, except for when I use a <router-link> or router.push to one of my routes. In the onMounted callback of my target page, the route seems to be the previous route (see AboutView.vue below).

I've tried await router.isReady(), but as far as I can tell it's not relevant here, it's only used for an initial page view.

Sample repo built with node 16.13.2: https://github.com/tietoevry-johan/vue-routing

App.vue

<template>
  <router-view/>
</template>

router.ts

export const currentPage = ref('HomeView')

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      name: "PageSelector",
      path: "/:catchAll(.*)",
      component: PageSelector
    }
  ]
});

router.beforeEach(async (to, _, next) => {
  currentPage.value = await getComponentByPath(to.path)
  next()
})

async function getComponentByPath(path: string) {
  return path === '/' ? 'HomeView' : 'AboutView'
}

PageSelector.vue

<template>
  <component :is="currentPage" />
</template>

<script lang="ts">
import { defineComponent } from "vue"
import AboutView from "@/views/AboutView.vue"
import HomeView from "@/views/HomeView.vue"
import { currentPage } from "@/router"

export default defineComponent({
  // eslint-disable-next-line vue/no-unused-components
  components: { HomeView, AboutView },
  setup() {
    return {
      currentPage
    }
  }
})
</script>

AboutView.vue

<template>
  about
</template>

<script lang="ts">
import router from "@/router";
import { defineComponent, onMounted } from "vue";

export default defineComponent({
  setup() {
    onMounted(() => {
      console.log(router.currentRoute.value?.fullPath) // prints / instead of /about
      // when clicking a router link or router push to this page
    })
  }
})

</script>


from Vue 3 shows previous route in onMounted

Sunday 24 September 2023

combine subtree merge with sparse checkout in git

I'm trying to emulate svn:externals in git. In project 'A' I need to pull down library 'B' into a sub folder of 'A'. Both A and B are separate git repos. I know I can do this with either submodules or subtree merge. However, to further complicate things, I need to pull down a subfolder of 'B' into 'A', not the whole project because it is a python module that I need to import directly and I can't have the root directory structure there or it can't be imported.

This is pretty easy to do with svn:externals. With git it seems complicated or even impossible.

Here is an example:

Project B:

-B
  - src
    __init__.py
 - test
   ...

Project A:

- A
   - src
     A.py (imports B)
     - B (partial check of sub folder 'src' as name 'B')
        __init__.py
   - test
     ...


from combine subtree merge with sparse checkout in git

My Application is Loading CSS files twice?

I accidentally noticed that my website is loading the same CSS file twice.

I use Laravel with Inertia, Vue, and Vite.

This cache postfix: 23c49378, is appearing twice

enter image description here

If I look In the networks tab, it is only appears once, which means it's only fetched once, which is good, however... if I look at elements, they have the same styles applied twice.

enter image description here

This is my app.blade.php file:

    <!DOCTYPE html>
    <html lang="">
        @if(Route::is('admin.*'))
            @php($__inertiaSsrDispatched = true)
            @php($__inertiaSsrResponse = null)
        @endif
    
        <head>
            <meta charset="utf-8">
    
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta name="theme-color" content="" />
            <meta name="msapplication-TileColor" content="#2b5797">
    
            <link rel="canonical" href=""  />
            @if(Route::current())
            <link rel="alternate" hreflang="x-default" href="" />
    
            @if(isset($locales) && Route::current() !== null)
            @foreach($locales as $locale)
            <link rel="alternate" hreflang="" href="" />
            @endforeach
            @endif
            @endif
    
            <!-- Scripts -->
            @routes(nonce: Vite::cspNonce())
    
            @if(Route::is('admin.*'))
                @vite(['resources/js/admin.ts', "resources/js/Pages/{$page['component']}.vue"])
            @else
                @vite(['resources/js/app.ts', "resources/js/Pages/App/{$page['component']}.vue"])
            @endif
            @inertiaHead
    
            <!-- Global site tag (gtag.js) - Google Analytics -->
            <script src="https://www.googletagmanager.com/gtag/js?id=G-SDK4391YJ7" defer async nonce=""></script>
            <script defer nonce="">
                window.dataLayer = window.dataLayer || [];
                function gtag(){window.dataLayer.push(arguments);}
                gtag('js', new Date());
                gtag('config', 'G-SDK4391YJ7');
            </script>
        </head>
    
        <body class="font-sans overflow-y-scroll antialiased @if(Cookie::get('theme') === 'dark') dark @endif @if (Cookie::get('expansion') == 'deflated')  @endif bg-white dark:bg-black">
        @inertia
        </body>
    </html>

This is my app.ts:

import './bootstrap';
import '../css/app.css';

import {createApp, h} from 'vue';
import {createInertiaApp} from '@inertiajs/inertia-vue3';

import {InertiaProgress} from '@inertiajs/progress';
import {resolvePageComponent} from 'laravel-vite-plugin/inertia-helpers';
import {io} from 'socket.io-client';

import {Ziggy} from './ziggy';
import {ZiggyVue} from '../../vendor/tightenco/ziggy/dist/vue.m';

createInertiaApp({
    title: (title) => `${title}`,
    // @ts-ignore
    resolve: (name) => resolvePageComponent(`./Pages/App/${name}.vue`, import.meta.glob('./Pages/App/**/*.vue')),
    // @ts-ignore
    setup({ el, app, props, plugin }) {
        //const application = createSSRApp({ render: () => h(app, props) })
        const application = createApp({ render: () => h(app, props) })
            .use(plugin)
            .use(ZiggyVue, Ziggy)
            .mount(el)
        return application;
    },
})

vite.config.js

import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import path from 'path';

export default defineConfig({
    resolve: {
        alias: {
            '@': path.resolve(__dirname, './resources/js'),
            '@ziggy': path.resolve(__dirname, './resources/js/ziggy')
        },
    },
    plugins: [
        laravel({
            input: {
                main: 'resources/js/app.ts',
                admin: 'resources/js/admin.ts',
            },
            ssr: 'resources/js/ssr.ts',
            refresh: true,
        }),
        vue({
            reactivityTransform: true,
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
    ssr: {
        noExternal: [
            '@inertiajs/server'
        ],
    },
});

Im a bit confused as to where to start... it looks like its being done as part of the inertia insertions?



from My Application is Loading CSS files twice?