Double precision floating point format decoder - C++

 

This was fun to do, but I can't remember why I decided to do it

  bits.txt

Ref: https://en.wikipedia.org/wiki/Double-precision_floating-point_format

Find the PHP session files that are older than 24 minutes

Shell

sudo find /var/lib/php/session -mmin +24 -type f -exec ls -{} \;

Yes, that's the whole post

Apache 2.4 virtual host specific PHP-FPM error logs

If you are using PHP-FPM with Apache and you would like to separate the error logging by user, directory or virtual host, you can use the ProxyFCGISetEnvIf directive

In a server level Apache .conf file

Code

<Directory /home/user/public_html>
ProxyFCGISetEnvIf "true" PHP_ADMIN_VALUE "error_log=/var/log/php-fpm/user/error.log"
</Directory>

In this case, the error log for user would be

/var/log/php-fpm/user/error.log

Set up the ACL (AMI 2 Linux)

setfacl -m u:user:x /var/log/php-fpm
setfacl -m u:user:rx /var/log/php-fpm/user
setfacl -d -m u:user:r /var/log/php-fpm/user

Test it with

sudo su user
more /var/log/php-fpm/user/error.log

Credit to:

Apache 2.4 virtual host specific PHP-FPM error logs
Comment from PHP.net (documentation)

https://www.php.net/manual/en/install.fpm.configuration.php#123335

Using wkhtmltopdf to generate a PDF from eZ Platform

I wanted to produce a polished PDF of restricted content managed by https://ezplatform.com/ with the least amount of effort possible and I wanted an approach that would allow me to run a single command on the command line.

My first approach was to try to use a browser's print to PDF feature, but I wasn't happy with the results. So I tried https://wkhtmltopdf.org/,

After tinkering with various roles/permissions and firewall configurations with eZ Platform and Symfony I chose to create a PDF user which was allowed to log in and view only the target content. I used curl to log in, extracted the eZ session id cookie and passed it to wkhtmltopdf for rendering.


#!/bin/bash
if [ "$#" -ne 1 ]; then
    echo "Usage: $0.sh url"
    exit;
fi;
USER=pdfuser
PASS=somepassword

URL=$1;
PDF=`echo $1 | sed "s/.*\/\([^\/]\+\)$/\1/"`
FOOTER_LEFT=${PDF^^}
LOGIN_URL=`echo $1 | sed "s/^\(https\?:\/\/[^\/]\+\/\).*$/\1login/"`
CSRF_TOKEN=`curl -s -X GET --cookie-jar cookie "$LOGIN_URL" | grep -o "name=\"_csrf_token\" value=\"\([^\"]\+\)\"" | sed "s/.*value=\"\([^\"]\+\)\"/\1/"`
LOGIN_DATA="_username=$USER&_password=$PASS&_csrf_token=$CSRF_TOKEN"
curl -L -s -b cookie --cookie-jar cookie -d "$LOGIN_DATA" "$LOGIN_URL"_check > /dev/null
COOKIE=`grep -o "\(eZSESS.*\)$" cookie | sed "s/\s\+/ /g"`
wkhtmltopdf --cookie $COOKIE --print-media-type --margin-left .5in --margin-right .5in --margin-top .5in --margin-bottom .5in "$URL" --footer-left "$FOOTER_LEFT" --footer-center 'Page [page] of [topage]' --footer-font-name 'Open Sans' --footer-font-size 8 --footer-right 'Updated [date]' "$PDF.pdf"

Thanks to: https://serverfault.com/a/306360/311430 for help with the cookies in the Apache log

Quiz analysis with Canvas API

I wanted to perform Item Analysis on quiz results under Canvas LMS.

Without working very hard.

I used a Web Inspector to look at the traffic, found the URL for quiz statistics and started trying to use curl to authenticate in and get the data.

When it didn't work right away, I Googled and found the Canvas REST API documentation. I spent a little time roaming through and found ...

curl -H "Authorization: Bearer REDACTED" https://canvas.instructure.com/api/v1/courses/:course_id/quizzes/:quiz_id/statistics

A single curl request delivers all the stats for a quiz. Absolutely excellent.

To create a .csv of the data, I used PHP, then translated it to Node.js

PHP

<?php
// The JavaScript code handles more types of questions - refer to that if you are planning to use this code
$shortopts "f:q:";
 
$longopts  = [
    "file:",
    "questions:"
];
$options getopt($shortopts$longopts);
 
$filename $options['f'];
if (is_file($filename)) {
        $questionList $options['q'];
        $questions explode(','$questionList);
        if (count($questions) < 1) {
                die('No questions');
        }       
} else {
        die('File not found');
}
 
$keys = [ 'responses''answered''correct''partially_correct''incorrect' ];
$assessmentData json_decode(file_get_contents('stats.json'));
if (json_last_error() === JSON_ERROR_NONE) {
        $quizStatistics $assessmentData->quiz_statistics[0];
        echo 'question,'.implode(','$keys).PHP_EOL;
        foreach ($questions as $q) {
                $data getData($keys$q$quizStatistics->question_statistics[$q]);
                echo implode(','$data).PHP_EOL;
        }
}
 
function getData($keys$question,$data) {
        $lineData = [ $question ];
        foreach ($keys as $k) {
                $lineData[] = isset($data->$k) ? $data->$k 0;
        }
        return $lineData;
}

Code

"use strict";
 
// Thanks to: https://stackabuse.com/command-line-arguments-in-node-js/
// Thanks to: https://flaviocopes.com/how-to-check-if-file-exists-node/
// Thanks to: https://code-maven.com/reading-a-file-with-nodejs
 
const fs = require('fs');
 
const path = process.argv[2];
try {
  if (fs.existsSync(path)) {
    let questionList = process.argv[3];
    let questions = questionList.split(',');
    if (questions.length < 1) {
      throw new Error('No questions');
    }
    fs.readFile(path, 'utf8', function(err,contents) {
        let csvData = createCSVData(contents,questions);
        process.stdout.write(csvData + '\n');
        });  
  } else {
    throw new Error('File not found');
  }
} catch (err) {
  console.error(err);
}
 
function createCSVData(fileData,questions){
  const keys = [ 'responses', 'answered', 'correct', 'partially_correct', 'incorrect' ];
  let csvData = '';
  let assessmentData = JSON.parse(fileData);
  if (assessmentData !== null && typeof assessmentData !== "undefined") {
    let quizStatistics = assessmentData.quiz_statistics[0];
    csvData = 'question,'+ keys.join(',') + '\n';
    questions.forEach((q) => {
                                q--; // questions are zero based
        let data = getData(keys, q, quizStatistics.question_statistics[q]);
        csvData += data.join(',') + '\n';
        });
  }
  return csvData;
}
 
function getData(keys, question, data) {
  let lineData = [ question ];
  keys.forEach(k => {
    let val = 0;
    if (typeof data[k] !== "undefined") {
      val = data[k];
    } else {
      if (typeof data[k + '_student_count'] !== "undefined") {
        val = data[k + '_student_count'];
      }
    }
    lineData.push(val);
  });
  switch (data.question_type) {
    case "essay_question":
      data.point_distribution.forEach(o => {;
        switch (o.score) {
          case data.full_credit:
            lineData[keys.indexOf('correct')+1] = o.count;
            break;
          case 0:
            lineData[keys.indexOf('incorrect')+1] = o.count;
            break;
          default:
            lineData[keys.indexOf('partially_correct')+1] += o.count;
            break;
        }          
      });
      break;
    case "true_false_question":
    case "short_answer_question":
      data.answers.forEach(o => {;
        if (o.correct === true) {
          lineData[keys.indexOf('correct')+1] = o.responses;
        } else {
          lineData[keys.indexOf('incorrect')+1] = o.responses;
        }          
      });
      break;      
    default:
          //console.log(question + ". "+data.question_type);
      //console.log(data);
  }
  return lineData;
}

Sample output:

question,responses,answered,correct,partially_correct,incorrect
2,11,11,3,4,6

Ref: https://canvas.instructure.com/doc/api/
Ref: https://canvas.instructure.com/doc/api/file.oauth.html#manual-token-generation - get a user auth token