Russ Allbery: Review: A Half-Built Garden
| Publisher: | Tordotcom |
| Copyright: | 2022 |
| ISBN: | 1-250-21097-6 |
| Format: | Kindle |
| Pages: | 340 |
| Publisher: | Tordotcom |
| Copyright: | 2022 |
| ISBN: | 1-250-21097-6 |
| Format: | Kindle |
| Pages: | 340 |
| Series: | Fall Revolution #2 |
| Publisher: | Tor |
| Copyright: | 1996 |
| Printing: | January 2001 |
| ISBN: | 0-8125-6864-8 |
| Format: | Mass market |
| Pages: | 339 |
We are happy to share that the RcppSimdJson
package has been updated to release 0.1.10.
RcppSimdJson
wraps the fantastic and genuinely impressive simdjson library by Daniel Lemire and collaborators. Via
very clever algorithmic engineering to obtain largely branch-free code,
coupled with modern C++ and newer compiler instructions, it results in
parsing gigabytes of JSON parsed per second which is quite
mindboggling. The best-case performance is faster than CPU speed as
use of parallel SIMD instructions and careful branch avoidance can lead
to less than one cpu cycle per byte parsed; see the video of the talk by Daniel Lemire
at QCon.
This release updates the underlying simdjson library to
version 3.1.8 (also made today). Otherwise we only made a minor edit to
the README and adjusted one tweek for code coverage.
The (very short) NEWS entry for this release follows.
Courtesy of my CRANberries, there is also a diffstat report for this release. For questions, suggestions, or issues please use the issue tracker at the GitHub repo. If you like this or other open-source work I do, you can now sponsor me at GitHub.Changes in version 0.1.10 (2023-05-14)
- simdjson was upgraded to version 3.1.8 (Dirk in #85).
This post by Dirk Eddelbuettel originated on his Thinking inside the box blog. Please report excessive re-aggregation in third-party for-profit settings.
Hello folks!
We recently received a case letting us know that Dataproc 2.1.1 was unable to write to a BigQuery table with a column of type JSON. Although the BigQuery connector for Spark has had support for JSON columns since 0.28.0, the Dataproc images on the 2.1 line still cannot create tables with JSON columns or write to existing tables with JSON columns.
The customer has graciously granted permission to share the code we developed to allow this operation. So if you are interested in working with JSON column tables on Dataproc 2.1 please continue reading!
Use the following gcloud command to create your single-node dataproc cluster:
IMAGE_VERSION=2.1.1-debian11
REGION=us-west1
ZONE=$ REGION -a
CLUSTER_NAME=pick-a-cluster-name
gcloud dataproc clusters create $ CLUSTER_NAME \
--region $ REGION \
--zone $ ZONE \
--single-node \
--master-machine-type n1-standard-4 \
--master-boot-disk-type pd-ssd \
--master-boot-disk-size 50 \
--image-version $ IMAGE_VERSION \
--max-idle=90m \
--enable-component-gateway \
--scopes 'https://www.googleapis.com/auth/cloud-platform'
The following file is the Scala code used to write JSON structured data to a BigQuery table using Spark. The file following this one can be executed from your single-node Dataproc cluster.
Main.scala
import org.apache.spark.sql.functions.col
import org.apache.spark.sql.types. Metadata, StringType, StructField, StructType
import org.apache.spark.sql. Row, SaveMode, SparkSession
import org.apache.spark.sql.avro
import org.apache.avro.specific
val env = "x"
val my_bucket = "cjac-docker-on-yarn"
val my_table = "dataset.testavro2"
val spark = env match
case "local" =>
SparkSession
.builder()
.config("temporaryGcsBucket", my_bucket)
.master("local")
.appName("isssue_115574")
.getOrCreate()
case _ =>
SparkSession
.builder()
.config("temporaryGcsBucket", my_bucket)
.appName("isssue_115574")
.getOrCreate()
// create DF with some data
val someData = Seq(
Row(""" "name":"name1", "age": 10 """, "id1"),
Row(""" "name":"name2", "age": 20 """, "id2")
)
val schema = StructType(
Seq(
StructField("user_age", StringType, true),
StructField("id", StringType, true)
)
)
val avroFileName = s"gs://$ my_bucket /issue_115574/someData.avro"
val someDF = spark.createDataFrame(spark.sparkContext.parallelize(someData), schema)
someDF.write.format("avro").mode("overwrite").save(avroFileName)
val avroDF = spark.read.format("avro").load(avroFileName)
// set metadata
val dfJSON = avroDF
.withColumn("user_age_no_metadata", col("user_age"))
.withMetadata("user_age", Metadata.fromJson(""" "sqlType":"JSON" """))
dfJSON.show()
dfJSON.printSchema
// write to BigQuery
dfJSON.write.format("bigquery")
.mode(SaveMode.Overwrite)
.option("writeMethod", "indirect")
.option("intermediateFormat", "avro")
.option("useAvroLogicalTypes", "true")
.option("table", my_table)
.save()
repro.sh:
#!/bin/bash PROJECT_ID=set-yours-here DATASET_NAME=dataset TABLE_NAME=testavro2 # We have to remove all of the existing spark bigquery jars from the local # filesystem, as we will be using the symbols from the # spark-3.3-bigquery-0.30.0.jar below. Having existing jar files on the # local filesystem will result in those symbols having higher precedence # than the one loaded with the spark-shell. sudo find /usr -name 'spark*bigquery*jar' -delete # Remove the table from the bigquery dataset if it exists bq rm -f -t $PROJECT_ID:$DATASET_NAME.$TABLE_NAME # Create the table with a JSON type column bq mk --table $PROJECT_ID:$DATASET_NAME.$TABLE_NAME \ user_age:JSON,id:STRING,user_age_no_metadata:STRING # Load the example Main.scala spark-shell -i Main.scala \ --jars /usr/lib/spark/external/spark-avro.jar,gs://spark-lib/bigquery/spark-3.3-bigquery-0.30.0.jar # Show the table schema when we use bq mk --table and then load the avro bq query --use_legacy_sql=false \ "SELECT ddl FROM $DATASET_NAME.INFORMATION_SCHEMA.TABLES where table_name='$TABLE_NAME'" # Remove the table so that we can see that the table is created should it not exist bq rm -f -t $PROJECT_ID:$DATASET_NAME.$TABLE_NAME # Dynamically generate a DataFrame, store it to avro, load that avro, # and write the avro to BigQuery, creating the table if it does not already exist spark-shell -i Main.scala \ --jars /usr/lib/spark/external/spark-avro.jar,gs://spark-lib/bigquery/spark-3.3-bigquery-0.30.0.jar # Show that the table schema does not differ from one created with a bq mk --table bq query --use_legacy_sql=false \ "SELECT ddl FROM $DATASET_NAME.INFORMATION_SCHEMA.TABLES where table_name='$TABLE_NAME'"Google BigQuery has supported JSON data since October of 2022, but until now, it has not been possible, on generally available Dataproc clusters, to interact with these columns using the Spark BigQuery Connector. JSON column type support was introduced in spark-bigquery-connector release 0.28.0.
Contributing to Debian
is part of Freexian s mission. This article
covers the latest achievements of Freexian and their collaborators. All of this
is made possible by organizations subscribing to our
Long Term Support contracts and
consulting services.
Welcome to the April 2023 report from the Reproducible Builds project!
In these reports we outline the most important things that we have been up to over the past month. And, as always, if you are interested in contributing to the project, please visit our Contribute page on our website.
Trisquel is a fully-free operating system building on the work of Ubuntu Linux. This month, Simon Josefsson published an article on his blog titled Trisquel is 42% Reproducible!. Simon wrote:
The absolute number may not be impressive, but what I hope is at least a useful contribution is that there actually is a number on how much of Trisquel is reproducible. Hopefully this will inspire others to help improve the actual metric.Simon wrote another blog post this month on a new tool to ensure that updates to Linux distribution archive metadata (eg. via
apt-get update) will only use files that have been recorded in a globally immutable and tamper-resistant ledger. A similar solution exists for Arch Linux (called pacman-bintrans) which was announced in August 2021 where an archive of all issued signatures is publically accessible.
[ ] the third reduction of the Guix bootstrap binaries has now been merged in the main branch of Guix! If you run guix pull today, you get a package graph of more than 22,000 nodes rooted in a 357-byte program something that had never been achieved, to our knowledge, since the birth of Unix.
More info about this change is available on the post itself, including:
The full-source bootstrap was once deemed impossible. Yet, here we are, building the foundations of a GNU/Linux distro entirely from source, a long way towards the ideal that the Guix project has been aiming for from the start.
There are still some daunting tasks ahead. For example, what about the Linux kernel? The good news is that the bootstrappable community has grown a lot, from two people six years ago there are now around 100 people in the #bootstrappable IRC channel.
Eleuther AI, a non-profit AI research group, recently unveiled Pythia, a collection of 16 Large Language Model (LLMs) trained on public data in the same order designed specifically to facilitate scientific research. According to a post on MarkTechPost:
Pythia is the only publicly available model suite that includes models that were trained on the same data in the same order [and] all the corresponding data and tools to download and replicate the exact training process are publicly released to facilitate further research.These properties are intended to allow researchers to understand how gender bias (etc.) can affected by training data and model scale.
alembic Debian package to build reproducibly. Although Chris Lamb was able to identify the source problem and provided a potential patch that might fix it, James Addison has taken the issue in hand, leading to a large amount of activity resulting in a proposed pull request that is waiting to be merged.
WireGuard is a popular Virtual Private Network (VPN) service that aims to be faster, simpler and leaner than other solutions to create secure connections between computing devices. According to a post on the WireGuard developer mailing list, the WireGuard Android app can now be built reproducibly so that its contents can be publicly verified. According to the post by Jason A. Donenfeld, the F-Droid project now does this verification by comparing their build of WireGuard to the build that the WireGuard project publishes. When they match, the new version becomes available. This is very positive news.
A software bill of materials (SBOM) is defined as a nested inventory for software, a list of ingredients that make up software components. When you receive a physical delivery of some sort, the bill of materials tells you what s inside the box. Similarly, when you use software created outside of your organisation, the SBOM tells you what s inside that software. The SBOM is a file that declares the software supply chain (SSC) for that specific piece of software. [ ]
#reproducible-builds IRC channel, but no solution appears to be in sight for now.
.zip file were different between two builds.
Holger Levsen gave a talk at foss-north 2023 in Gothenburg, Sweden on the topic of Reproducible Builds, the first ten years.
Lastly, there were a number of updates to our website, including:
: .lead appearing in the page [ ][ ][ ], made all the Back to who is involved links italics [ ], and corrected the syntax of the _data/sponsors.yml file [ ].
build-essential package set, which was inspired by how close we are to making the Debian build-essential set reproducible and how important that set of packages are in general . Vagrant mentioned that: I have some progress, some hope, and I daresay, some fears . [ ]
dinstalls that is to say, the snapshot service is not capturing 100% of all of historical states of the Debian archive. This is relevant to reproducibility because without the availability historical versions, it is becomes impossible to repeat a build at a future date in order to correlate checksums. .
build_path_in_line_annotations_added_by_ruby_ragel toolchain issue. [ ]
ghc (workaround a parallelism-related issue)ghc (report a parallelism-related issue)ruby-regexp-parser.pike8.0.binutils.lomiri-action-api.lomiri.nmodl.php8.2.qemu.twisted.boost1.74.php8.2.shaderc.jackd2.
diffoscope version 241 was uploaded to Debian unstable by Chris Lamb. It included contributions already covered in previous months as well a change by Chris Lamb to add a missing raise statement that was accidentally dropped in a previous commit. [ ]
The Reproducible Builds project operates a comprehensive testing framework (available at tests.reproducible-builds.org) in order to check packages and other artifacts for reproducibility. In April, a number of changes were made, including:
/tmp/archlinux-ci/ after three days. [ ][ ][ ]schroot sessions. [ ]stretch Debian distribution. [ ][ ][ ][ ]pyyaml 6.0 as present in Debian bookworm. [ ]#reproducible-builds on irc.oftc.net.
rb-general@lists.reproducible-builds.org
I do try not to report because right now every other day we see somewhere or the other the Govt. curtailing our rights and most people are mute
Signing out, till later
When I travel for a few days I don t usually1 bring any other shoe than the ones I m wearing, plus some kind of slippers for use inside hotel / B&B rooms.
It s good for not carrying useless weight, but it always leave me with a vague feeling of what if my only shoes break , followed by on a Sunday, when the shops are closed .
So I started to think in the general direction of hiking sandals, shoes that are designed to be worn when resting, and lightweight to carry, but are a passable substitute for regular shoes in case of an accident to the main ones, maybe with the help of an extra pair of socks2 (or when crossing fords, but that s not really a usecase I have).
My requirements are easier than the ones for real hiking sandals, since I m only going to be walking on paved streets (or at most easy unpaved ones), and the weight considerations are a thing, but not as strict as if I had to carry these on my back while hiking many hours in a day.
My first attempt was a pair of hiking sandals from things I already had in my stash, with vibram soles, neoprene padding and polyester webbing. After a couple fixes they sort of worked, but they had a few big issues.
For the soles I may have gone a bit overboard with the vibram claw, but:
As for the finished weight, at 235 g for the pair I thought I could do better, but apparently shoes are considered ultralight if they are around 500 g? Using just one layer of mesh rather than two would probably help, but it would have required a few changes to the pattern, and anyway I don t really to carry them around all day.
I ve also added a loop of fabric (polycotton) to the centre back to be able to hang the slippers to the backpack when wet or dirty; a bit of narrow webbing may have been better, but I didn t have any in my stash.
The pattern is the same as that used for the linen slippers, and of course it s released as #FreeSoftWear.
I ve worn these for a few days around the home and they worked just fine, except for the fact that I had to re-glue the sole in a few places (but I suspect it was glued badly in the first place, since the other sole had no issues).
Right now I have no plans to travel, so I don t know how much I will be able to test these in the next few months, but sooner or later I will (or I ll keep wearing them at home after I ve thoroughly tested the linen ones), and if there are issues I will post them here on the blog (and add a link to this post).
(Edit 2023-05-10: This has now launched for a subset of Twitter users. The code that existed to notify users that device identities had changed does not appear to have been enabled - as a result, in its current form, Twitter can absolutely MITM conversations and read your messages)/dev/sdf. Then:
# Create an msdos partition table $ sudo parted --script /dev/sdf mklabel msdos # Create, format, and label a 10M fat32 partition $ sudo parted --script /dev/sdf mkpart primary fat32 0% 10M $ sudo mkfs.vfat /dev/sdf1 $ sudo fatlabel /dev/sdf1 RPI-FW # Get the UEFI firmware onto the SD card $ sudo mount /dev/sdf1 /mnt/data/ $ sudo unzip Downloads/RPi3_UEFI_Firmware_v1.38.zip -d /mnt/data/ $ sudo umount /mnt/data
ESC and choose the USB stick from Boot Manager.
esp flag on makes the RPi unbootable. Either configuring the partition as ESP
in debian-installer, or manually with sudo parted --script /dev/sda set 1 esp
on, breaks boot. In case you accidentally do that, set it back to off and
the edk2 firmware will boot again.
efibootmgr or otherwise, but crucially the modifications do not survive
reboot. However, changes made from the firmware interface itself are
persistent. So enter the firmware with ESC right after booting the RPi,
select Boot Maintenance Manager Boot Options Add Boot Option
Your SD card Your ESP partition EFI debian shimaa64.efi.
Choose a creative name for your boot entry (eg: "debian"), save and exit the
firmware interface. Bookworm should be booting fine at this point!
PK-0001.der.pem
Subject: O = Debian, CN = Debian UEFI Secure Boot (PK/KEK key), emailAddress = debian-devel@lists.debian.org
DB-0001.der.pem
Subject: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Windows Production PCA 2011
DB-0002.der.pem
Subject: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Corporation UEFI CA 2011
KEK-0001.der.pem
Subject: O = Debian, CN = Debian UEFI Secure Boot (PK/KEK key), emailAddress = debian-devel@lists.debian.org
KEK-0002.der.pem
Subject: C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, CN = Microsoft Corporation KEK CA 2011
ESC.
Select Device Manager Secure Boot Configuration Secure Boot Mode
choose Custom Mode Custom Secure Boot Options PK Options Enroll
PK choose PK-0001.der. Do the same for DB Options, this time choose
DB-0001.der and DB-0002.der. As you may have guessed by now, the same must
be done for KEK Options, but adding KEK-0001.der and KEK-0002.der. Save,
exit, reboot. If everything went well, your RPi now has booted with Secure Boot
enabled.
This isn't a book review, although the reason that I am typing this now is
because of a book, You Are Not Alone: from the creator and host of
Griefcast, Cariad Lloyd, ISBN: 978-1526621870 and I include a handful of
quotes from Cariad where there is really no better way of describing things.
Many people experience death for the first time as a child, often relating to a
family pet. Death is universal but every experience of death is unique. One of
the myths of grief is the idea of the Five Stages but this is a
misinterpretation. Denial, Anger, Bargaining, Depression and Acceptance
represent the five stage model of death and have nothing to do with
grief. The five stages were developed from studying those who are
terminally ill, the dying, not those who then grieve for the dead person and
have to go on living without them. Grief is for those who loved the person who
has died and it varies between each of those people just as people vary in how
they love someone. The Five Stages end at the moment of death, grief is what
comes next and most people do not grieve in stages, it can be more like a
tangled knot.
Death has a date and time, so that is why the last stage of the model is
Acceptance. Grief has no timetable, those who grieve will carry that grief for
the rest of their lives. Death starts the process of grief in those who go on
living just as it ends the life of the person who is loved. "Grief eases and
changes and returns but it never disappears.".
I suspect many will have already stopped reading by this point. People do not
talk about death and grief enough and this only adds to the burden of those who
carry their grief. It can be of enormous comfort to those who have carried
grief for some time to talk directly about the dead, not in vague pleasantries
but with specific and strong memories. Find a safe place without distractions
and talk with the person grieving face to face. Name the dead person. Go to
places with strong memories and be there alongside. Talk about the times with
that person before their death. Early on, everything about grief is painful and
sad. It does ease but it remains unpredictable. Closing it away in a box inside
your head (as I did at one point) is like cutting off a damaged limb but
keeping the pain in a box on the shelf. You still miss the limb and eventually,
the box starts leaking.
For me, there were family pets which died but my first job out of university
was to work in hospitals, helping the nurses manage the medication regimen and
providing specialist advice as a pharmacist. It will not be long in that
environment before everyone on the ward gets direct experience of the death of
a person. In some ways, this helped me to separate the process of death from
the process of grief. I cared for these people as patients but these were not
my loved ones. Later, I worked in specialist terminal care units, including
providing potential treatments as part of clinical trials. Here, it was not
expected for any patient to be discharged alive. The more aggressive
chemotherapies had already been tried and had failed, this was about pain
relief, symptom management and helping the loved ones. Palliative care is not
just about the patient, it involves helping the loved ones to accept what is
happening as this provides comfort to the patient by closing the loop.
Grief is stressful. One of the most common causes of personal stress is
bereavement.
The death of your loved one is outside of your control, it has happened, no
amount of regret can change that. Then come all the other stresses, maybe about
money or having somewhere to live as a result of what else has changed after
the death or having to care for other loved ones.
In the early stages, the first two years, I found it helpful to imagine my life
as a box containing a ball and a button. The button triggers new waves of pain
and loss each time it is hit. The ball bounces around the box and hits the
button at random. Initially, the button is large and the ball is enormous, so
the button is hit almost constantly. Over time, both the button and the ball
change size. Starting off at maximum, initially there is only one direction of
change. There are two problems with this analogy. First is that the grief ball
has infinite energy which does not happen in reality. The ball may get smaller
and the button harder to hit but the ball will continue bouncing. Secondly, the
life box is not a predictable shape, so the pattern of movement of the ball is
unpredictable.
A single stress is one thing, but what has happened since has just kept adding
more stress for me. Shortly before my father died 5 years ago now, I had moved
house. Then, I was made redundant on the day of the first anniversary of my
father's death. A year or so later, my long term relationship failed and a few
months after that COVID-19 appeared. As the country eased out of the pandemic
in 2021, my mother died (unrelated to COVID itself). A year after that, I had
to take early retirement. My brother and sister, of course, share a lot of
those stressors. My brother, in particular, took the responsibility for
organising both funerals and did most of the visits to my mother before her
death. The grief is different for each of the surviving family.
Cariad's book helped me understand why I was getting frequent ideas about going
back to visit places which my father and I both knew. My parents encouraged
each of us to work hard to leave Port Talbot (or Pong Toilet locally) behind,
in no small part due to the unrestrained pollution and deprivation that is
common to small industrial towns across Wales, the midlands and the north of
the UK. It wasn't that I wanted to move house back to our ancestral roots. It
was my grief leaking out of the box. Yes, I long for mountains and the sea
because I'm now living in a remorselessly flat and landlocked region after
moving here for employment. However, it was my grief driving those longings -
not for the physical surroundings but out of the shared memories with my
father. I can visit those memories without moving house, I just need to arrange
things so that I can be undisturbed and undistracted.
I am not alone with my grief and I am grateful to my friends who have helped
whilst carrying their own grief. It is necessary for everyone to think and talk
about death and grief. In respect of your own death, no matter how far ahead
that may be, consider Advance Care Planning and Expressions of Wish as well
as your Will.
Help your loved ones cope with your death by describing what you would like to happen.
Document how your life has been arranged so that the executor of your Will can find the right documents to inform:
- your bank,
- your mortgage company,
- your energy company,
- your mobile phone company,
- your house and car insurers and the like.
If you've got a complex home setup with servers and other machines which would be unfamiliar to the executor of your Will, then entrust someone else with the information required to revoke your keys, access your machines etc. and then provide the contact information for that person to your executor.
Arrange for your pets to be looked after.
Describe how you would like your belongings to be handled - do you want every effort made to have your clothes and furnishing recycled instead of going to landfill?
Where are the documents for the oven, the dishwasher and the central heating system so that these can be included in the sale of your property?
If there are loans outstanding, make sure your executor or a trusted person knows where to find the account numbers and company names.
What about organ donation? Make sure your executor knows your wishes and make sure your loved ones either agree or are willing to respect your wishes.
Then the personal stuff, what do you want to happen to your social media accounts, your cloud data, your games, DVD and CD collection, your photos and other media? Some social media companies have explicit settings available in your account to describe if you want the data deleted after a certain amount of time, after a notification from some government service or to set up some kind of memorialised version or hand over control of the account to a trusted person.
After my father passed away, I brought home most of the personal items
he had, both at home and at his office. Among many, many (many, many,
many) other things, I brought two of his personal treasures: His photo
collection and a box with the 8mm movies he shot approximately between
1956 and 1989, when he was forced into modernity and got a portable
videocassette recorder.
I have talked with several friends, as I really want to get it all in
a digital format, and while I ve been making slow but steady advances
scanning the photo reels, I was particularly dismayed (even though it
was most expected most personal electronic devices aren t meant to
last over 50 years) to find out the 8mm projector was no longer in
working conditions; the lamp and the fans work, but the spindles won t
spin. Of course, it is quite likely it is easy to fix, but it is
beyond my tinkering abilities and finding photographic equipment
repair shops is no longer easy. Anyway, even if I got it fixed,
filming a movie from a screen, even with a decent camera, is a lousy
way to get it digitized.
But almost by mere chance, I got in contact with my cousin Daniel, ho
came to Mexico to visit his parents, and had precisely brought with
him a 8mm/Super8 movie scanner! It is a much simpler piece of
equipment than I had expected, and while it does present some minor
glitches (i.e. the vertical framing slightly loses alignment over the
course of a medium-length film scanning session, and no adjustment is
possible while the scan is ongoing), this is something
that can be decently fixed in post-processing, and a scanning session
can be split with no ill effects. Anyway, it is quite uncommon a
mid-length (5min) film can be done without interrupting i.e. to join a
splice, mostly given my father didn t just film, but also edited a lot
(this is, it s not just family pictures, but all different kinds of
fiction and documentary work he did).
So, Daniel lent me a great, brand new, entry-level film scanner; I
rushed to scan as many movies as possible before his return to the USA
this week, but he insisted he bought it to help preserve our family s
memory, and given we are still several cousins living in Mexico, I
could keep hold of it so any other of the cousins will find it more
easily. Of course, I am thankful and delighted!
So, this equipment is a Magnasonic FS81. It is entry-level, as it
lacks some adjustment abilities a professional one would surely have,
and I m sure a better scanner will make the job faster but it s
infinitely superior to not having it!
The scanner processes roughly two frames per second (while the nominal
8mm/Super8 speed is 24 frames per second), so a 3 minute film reel
takes a bit over 35 minutes And a long, ~20 minute film reel
takes Close to 4hr, if nothing gets in your way :- And yes, with
longer reels, the probability of a splice breaking are way higher than
with a short one not only because there is simply a longer film to
process, but also because, both at the unwinding and at the receiving
reels, mechanics play their roles.
The films don t advance smoothly, but jump to position each frame in
the scanner s screen, so every bit of film gets its fair share of
gentle tugs.
My professional consultant on how and what to do is my good friend
Chema
Serralde,
who has stopped me from doing several things I would regret later
otherwise (such as joining spliced tapes with acidic chemical
adhesives such as Kola Loka, a.k.a. Krazy Glue even if it s a
bit trickier to do it, he insisted me on best using simple transparent
tape if I m not buying fancy things such as film-adhesive). Chema also
explained me the importance of the loopers (las Lupes in his
technical Spanish translation), which I feared increased the
likelihood of breaking a bit of old glue due to the angle in which the
film gets pulled but if skipped, result in films with too much
jumping.
Not all of the movies I have are for public sharing Some of them are
just family movies, with high personal value, but probably of very
little interest to others. But some are! I have been uploading some of
the movies, after minor post-processing, to the Internet
Archive. Among them:
Anyway, I have a long way forward for scanning. I have 20 3min reels,
19 5min reels, and 8 20min reels. I want to check the scanning
quality, but I think my 20min reels are mostly processed (we paid for
scanning them some years ago). I mostly finished the 3min reels, but
might have to go over some of them again due to the learning process.
And Well, I m having quite a bit of fun in the process!
| Series: | Discworld #28 |
| Publisher: | HarperCollins |
| Copyright: | 2001 |
| Printing: | 2008 |
| ISBN: | 0-06-001235-8 |
| Format: | Mass market |
| Pages: | 351 |
I m in the process of getting super-strict about the code quality of cretrit, the comparison-revealing encryption library that underlies the queryable encryption of the Enquo project.
While I m going to write a whole big thing about Rust linting in the future, I bumped across a rather gnarly problem that I thought was worth sharing separately.
The problem, in short, is that the unused_crate_dependencies lint interacts badly with crates that are only needed for benchmarking, such as (in my case) criterion.
Rust has a whole bucketload of lints that can help your codebase adhere to certain standards, by warning (or exploding) if the problem is detected.
The unused_crate_dependencies lint, as the name suggests, gets snippy when there s a crate listed in your Cargo.toml that doesn t appear to be used anywhere.
All well and good so far.
However, while Rust has the ability to specify crates needed for running the testsuite (the [dev-dependencies] section of Cargo.toml) separately from crates needed for actually using this thing ([dependencies]), it doesn t have a way to specify crates needed for running the benchmarks .
That is a problem when you re using something like criterion for benchmarking, because it doesn t get refered to at all in your project code it only gets used in the benchmarks.
When building your codebase for running the test suite, the compiler sees that you ve specified criterion as one of your testsuite dependencies , but it never gets used in your testsuite.
This causes the unused_crate_dependencies lint to lose its tiny mind, and make your build look ugly (or fail).
Thankfully, the solution is very simple, once you know the trick (this could be the unofficial theme song of the entire Rust ecosystem).
You need to refer to the criterion crate somewhere in the code that gets built during the testsuite.
The lint tells you most of what you need to do (like most things Rust, it tries hard to be helpful), but since it s a development dependency, you need a little extra secret sauce.
All you need to do is add these two lines to the bottom of your src/lib.rs (or src/main.rs for a binary crate):
#[cfg(test)]
use criterion as _;
For the less Rust-literate, this means when the build-time configuration flag test is set, import the criterion crate, but don t, like, allow it to actually be referred to .
This is enough to make the lint believe that the dependency is being used, and making it only happen when the test build-time config flag is set avoids the ugliness of it trying to refer to the crate during regular builds (which would fail, because criterion is only a dev-dependency).
Simple?
Yes.
Did it take me a lot of skull-sweat to figure out?
You betcha.
That s why I m writing it down even if everyone else already knows this, at least future Matt will find this post next time he trips over this problem.
# get post ID and word count SELECT id, LENGTH(post_content) - LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(post_content, "\r", ""), "\n", ""), "\t", ""), " ", "")) + 1 AS wordcount FROM wp_posts where post_status = 'publish' and post_type='post'; # get average word count SELECT avg(LENGTH(post_content) - LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(post_content, "\r", ""), "\n", ""), "\t", ""), " ", "")) + 1) FROM wp_posts where post_status = 'publish' and post_type='post'; # get the first posts by length SELECT id, LENGTH(post_content) - LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(post_content, "\r", ""), "\n", ""), "\t", ""), " ", "")) + 1 AS wordcount, post_content FROM wp_posts where post_status = 'publish' and post_type='post' ORDER BY wordcount limit 10; # get a count of the posts less than 312 words SELECT count(*) from wp_posts where (LENGTH(post_content) - LENGTH(REPLACE(REPLACE(REPLACE(REPLACE(post_content, "\r", ""), "\n", ""), "\t", ""), " ", "")) + 1) < 312 and post_status = 'publish' and post_type='post'; # get a count of all posts select count(*) from wp_posts where post_status = 'publish' and post_type='post';It turns out that there are 333/1521 posts that are less than 312 words and the average length is 665 words. Of the shortest posts a large portion were written before Twitter became popular and had the sort of unimportant content that Twitter is good for. It seems ironic that ChatGPT says that I'm known for "depth" and then writes a short post allegedly in my style. As for the actual content of the "post", it's not something that I greatly disagree with but it's definitely not something I'd write. If some manager or marketing person wrote something like this and asked my opinion I'd probably suppress a sigh and say it's OK for it's target market. I think that free software is better in many ways and for many reasons and that separately from the issue of merit free software is important because of the ways that it is used. We could debate various issues related to the quality of free software vs proprietary software but even people who don't believe that free software is of high quality have to admit that software that runs most mobile phones and most web servers is important. As much as I dislike Windows most desktop PCs and laptops run it so I can't claim it to be unimportant. So my first disagreement with the content is the issue of importance vs quality. One thing that ChatGPT is known for is weak arguments that appear convincing. "This diversity often leads to better software, as bugs are found and fixed faster, and new features are added more quickly" could be opposed by "the payment for proprietary software often leads to better software, as bugs are found and fixed faster, and new features are added more quickly". I think that any case where "feature of option A gives this list of good results" can be rewritten as "feature of the opposite of option A gives the same list of good results" and be equally convincing is a poor argument. Also any argument that seems to rest on "free software is all written by hobbyists" is ignoring the demands of users who need things done on a non-hobby timeframe, the many profitable companies that develop and support free software, and the employment status of a large portion of my Facebook friends (many of whom are paid for ~2000 hours a year of free software development and many more of whom have paid free software development as part of their work supporting the use of free software). Really the entire blog post it wrote seems to me like something a human might write if their boss assigned them to write about the benefits of free software, and that they would then write a new article saying the exact opposite if their boss asked them to. Finally I prefer the term "free software" to "open source software". The difference doesn't seem important to some people, but any being that doesn't know the difference won't do well at impersonating me. ChatGPT Result Hello everyone, I'm ChatGPT, and today I'm going to try my best to write a blog post in the style of the great computer scientist and writer, Russell Coker. Russell Coker is a renowned software engineer and writer, who is best known for his contributions to the Linux community, especially the Debian project. He has authored several books and articles on topics ranging from security to software engineering, and his writing style is known for its clarity, precision, and depth. So, without further ado, let's dive into the topic of this blog post, which is the importance of open-source software. Open-source software is software whose source code is available for anyone to inspect, modify, and distribute. This means that anyone can use, study, and improve the software, without any restrictions or fees. Open-source software has been around for a long time, but it has become more prevalent and important in recent years, thanks to the rise of the internet and the digital economy. Open-source software has several benefits, both for individuals and for society as a whole. One of the most significant benefits is that it fosters innovation and collaboration. When software is open-source, it means that anyone can contribute to it, which leads to a diverse range of perspectives and ideas. This diversity often leads to better software, as bugs are found and fixed faster, and new features are added more quickly. Another benefit of open-source software is that it is often more secure than proprietary software. Because the source code is available for anyone to inspect, vulnerabilities and security flaws can be found and fixed faster. This means that open-source software is often more reliable and trustworthy than proprietary software, which may have hidden backdoors or vulnerabilities that can be exploited by attackers. Open-source software is also often more cost-effective than proprietary software. Because it is free to use and distribute, organizations can save money on licensing fees and other costs associated with proprietary software. This can be particularly important for non-profit organizations or small businesses that may not have the resources to invest in expensive software licenses. In conclusion, open-source software is an important part of the digital landscape, and its benefits are numerous. Whether you are a software developer, a business owner, or an individual user, open-source software has something to offer. So, the next time you are looking for software to use, consider open-source options, and help support the collaborative and innovative spirit of the open-source community.
I acquired some unusual input devices to experiment with, like a CNC control
panel and a bluetooth pedal page turner.
These identify and behave like a keyboard, sending nice and simple keystrokes,
and can be accessed with no drivers or other special software. However, their
keystrokes appear together with keystrokes from normal keyboards, which is the
expected default when plugging in a keyboard, but not what I want in this case.
I'd also like them to be readable via evdev and accessible by my own user.
Here's the udev rule I cooked up to handle this use case:
# Handle the CNC control panel
SUBSYSTEM=="input", ENV ID_VENDOR =="04d9", ENV ID_MODEL =="1203", \
OWNER="enrico", ENV ID_INPUT =""
# Handle the Bluetooth page turner
SUBSYSTEM=="input", ENV ID_BUS =="bluetooth", ENV LIBINPUT_DEVICE_GROUP =="*/ mac ", ENV ID_INPUT_KEYBOARD ="1" \
OWNER="enrico", ENV ID_INPUT ="", SYMLINK+="input/by-id/bluetooth- mac -kbd"
SUBSYSTEM=="input", ENV ID_BUS =="bluetooth", ENV LIBINPUT_DEVICE_GROUP =="*/ mac ", ENV ID_INPUT_TABLET ="1" \
OWNER="enrico", ENV ID_INPUT ="", SYMLINK+="input/by-id/bluetooth- mac -tablet"
/dev/input/by-id/
symlinks so I added them. In my own code, I watch /dev/input/by-id with
inotify to handle when devices appear or disappear.
I used udevadm info /dev/input/event to see what I could use to identify the
device.
The Static device configuration via udev
page of libinput's documentation has documentation on the various elements
specific to the input subsystem
Grepping rule files in /usr/lib/udev/rules.d was useful to see syntax
examples.
udevadm test /dev/input/event was invaluable for syntax checking and testing
my rule file while working on it.
Finally, this is an extract of a quick prototype Python code to read keys from
the CNC control panel:
import libevdev
KEY_MAP =
libevdev.EV_KEY.KEY_GRAVE: "EMERGENCY",
# InputEvent(EV_KEY, KEY_LEFTALT, 1)
libevdev.EV_KEY.KEY_R: "CYCLE START",
libevdev.EV_KEY.KEY_F5: "SPINDLE ON/OFF",
# InputEvent(EV_KEY, KEY_RIGHTCTRL, 1)
libevdev.EV_KEY.KEY_W: "REDO",
# InputEvent(EV_KEY, KEY_LEFTALT, 1)
libevdev.EV_KEY.KEY_N: "SINGLE STEP",
# InputEvent(EV_KEY, KEY_LEFTCTRL, 1)
libevdev.EV_KEY.KEY_O: "ORIGIN POINT",
libevdev.EV_KEY.KEY_ESC: "STOP",
libevdev.EV_KEY.KEY_KPPLUS: "SPEED UP",
libevdev.EV_KEY.KEY_KPMINUS: "SLOW DOWN",
libevdev.EV_KEY.KEY_F11: "F+",
libevdev.EV_KEY.KEY_F10: "F-",
libevdev.EV_KEY.KEY_RIGHTBRACE: "J+",
libevdev.EV_KEY.KEY_LEFTBRACE: "J-",
libevdev.EV_KEY.KEY_UP: "+Y",
libevdev.EV_KEY.KEY_DOWN: "-Y",
libevdev.EV_KEY.KEY_LEFT: "-X",
libevdev.EV_KEY.KEY_RIGHT: "+X",
libevdev.EV_KEY.KEY_KP7: "+A",
libevdev.EV_KEY.KEY_Q: "-A",
libevdev.EV_KEY.KEY_PAGEDOWN: "-Z",
libevdev.EV_KEY.KEY_PAGEUP: "+Z",
class KeyReader:
def __init__(self, path: str):
self.path = path
self.fd: IO[bytes] None = None
self.device: libevdev.Device None = None
def __enter__(self):
self.fd = open(self.path, "rb")
self.device = libevdev.Device(self.fd)
return self
def __exit__(self, exc_type, exc, tb):
self.device = None
self.fd.close()
self.fd = None
def events(self) -> Iterator[dict[str, Any]]:
for e in self.device.events():
if e.type == libevdev.EV_KEY:
if (val := KEY_MAP.get(e.code)):
yield
"name": val,
"value": e.value,
"sec": e.sec,
"usec": e.usec,
The more I say, the more depressed I will become so will leave it for now. In many ways the destruction seems similar to the destruction that happened in Brazil under Jair Bolsonaro. So as can be seen from what I have shared this book was mostly about environment and punitive damages and also how punitive damages have been ceiling in America (South). This was done via lobbying by the coal groups and apparently destroyed people s lives, communities, even whole villages. It also shared how most people called black lung and how those claims had been denied by Coal Companies all the time. And there are hardly any unions. While the book itself is a fiction piece, there is a large amount of truth in it. And that is one of the reasons people write a fiction book. You could write about reality using fictional names and nobody can sue you while you set the reality as it is. In many ways, it is a tell-all.
Next.