Popular shared stories on NewsBlur.
2760 stories
·
59932 followers

Tahoe to San Jose ride

1 Comment

Summer tingles my itch to travel afar. It has always been a season to go somewhere for me.

This year, when a bunch of people in my beloved local cycling group decided to sign up to an organized ride event to go around Lake Tahoe, I knew my summer adventure has to be to ride my bike from Tahoe all the way home, San Jose.

600km might not sound like a bike distance to most people, but I have done a longer ride, so I felt this was practical. The challenge with this one was how to map out a safe route, in uninhabited areas that I have zero familiarity with. If I get into a trouble and a nearest town is 20 miles away, I could be in a real bind.

I contacted a Facebook group of Sacramento cyclists about my plan, and they were able to tweak & validate the plan. People in the group must have felt this was a big adventure, and they chose to become a part of it by providing feedback. Cyclists take care of each other, and I love that.

Finding other riders to join this journey turned out to be harder. Most cyclist friends didn’t feel they are capable of this, even when in my eyes they probably can. In my own experience, confidence building takes time and gradual step up, so that’s understandable, but still disappointing. Even among capable riders, time availability was a problem. A whole week is a lot to ask.

But in the end, I managed to sign up one rider, Linda, who was willing to tag along with me all the way. Another rider, Larry, decided to join from Sacramento and onwards.

A 5 day trip across California was committed like that.

Day 0

On Sunday, I joined the “America’s most beautiful ride” event that goes around Lake Tahoe. For the rest of the folks in the group, this was the main event, but for me, this was just a prelude, a warm-up.

When I stepped out of my motel room at 6:15am, the air was bit misty and morning low light was bright. I could already see riders rolling out into chilly morning air of Tahoe. The start line was directly toward the morning sun, so it was as if riders were coming out of the light. That lifted my spirit.

As we joined this stream of riders, I felt the joy of being a part of something bigger. There must have been thousands of riders in this event. I got carried away with excitement. I went fast, wanting to feel the cold air on my body, so I kept calling out “on your left” and passed other riders by a dozen. I also stopped frequently to take pictures. This unusual pattern of riding meant there are some people I kept passing many times. I started recognizing them, and so did they. Spontaneous friendship emerged. Many of them said my voice is a great “radio voice”. I felt good.

Man, there’s no shortage of photo opportunities on this ride. The lake that gradually changes its color from emerald green to deep blue. Remote mountain range that’s still white with snow. Big blue sky. As the day went by, I started seeing people coming out to beach to have good time. I rode past pick-up trucks unloading a cooler box full of beer. A peaceful beautiful weekend. Such a picturesque place.

In hindsight, I wished I went more slowly. There’s no reasons to hurry; I could have made stops for coffee, ice cream, beer, better lunches. I got dropped from my group at this point anyway. But maybe such is life. Somehow you are always in a hurry, when you shouldn’t.

I got reunited with the group at the finish line party. We were all tired, but all happy. We had food and beer. Live music was going. We had some wonderful downtime there.

At the motel, Linda and I sent them off as they drive back home, and we settled in for the night. Tomorrow my real journey begins!

Day 1

This was an easy day with mere 50 miles to Truckee. Half the route was the exact same as yesterday.

I found that the big saddlebag I got to carry stuff changed the handling of the bike considerably, so I took this ride carefully. I didn’t want to stand up and dance on the bike, I didn’t want to go too fast on the downhill. On top of that, I was stopping to take pictures. All in all, I was going pretty slow.

So it was no wonder I got dropped at the first climb of the day. I asked Linda not to go too far ahead, but she wasn’t waiting for me at the top of the climb. As I kept going, I started to get worried. She doesn’t have a bike computer that can navigate her. Her cell phone doesn’t seem to have location tracking feature, and she can’t see my location tracking info, either. If she misses the turn, or if she waits for me but I miss her, then we might have a real trouble regrouping.

In hindsight, my fear was probably overblown. She was an experienced rider, and the road was basically straight. There’s still enough traffic, so if there was any mechanical problem, I could have probably gotten help. Still, it took me a few days to adjust my expectations and get into a proper groove with her.

We eventually rolled into Truckee without a hiccup, spent some wonderful time in a coffee shop and a local bar, settled into a hotel. We were off to a great start.

Day 2

To me, this was the biggest day of the whole journey. We had to cross 50 miles of uninhabited Sierra Nevada highlands forrest, then ride another 30 miles to Auburn. All brand-new route. Uncharted territory.

This route was incredible. We went by Donner Lake in the morning. The lake was calm, and surrounded by expensive looking cottages. I tried to imagine myself renting a vacation home for a few days. I could be sitting by the lake painting.

The road started climbing toward Donner Pass, winding left and right. Sharp, rocky mountains (I guess that’s where the name came from!) started defining the terrain. Snow capped mountain is no longer a backdrop, it’s now right in front of me. The view was spectacular. The top of the climb was the highest point in this whole ride — 7000ft above sea level.

From here, the road took a gentle but steady descent, creating an incredible ride experience. The bulky saddlebag meant I still couldn’t completely trust my bike at the high speed, but I couldn’t resist speeding up. There’s something primordial about going fast. The road kept on, so we kept going. This incredible descent went like this for whopping 35km/20 miles!

We took the shoulder of Interstate Highway 80 for a few miles, then our route diverged from the highway toward Grass Valley. The road started climbing exposed under sun, then another 30km/20 miles descent through the dense pine forest continued. We average 30+km/h (20mph) on this section.

I felt dreamy. I entertained an illusion that this will continue forever. The car traffic was busy, and the shoulder was narrow, though.

The last 50km (30 miles) of the route was very hot, and over rolling hills. I could sense that Linda is tired, and I started to worry about her in a different way from yesterday. I made a crucial routing error that led us to push our bikes through gravel field, which didn’t help at all. I started to wonder if I took on a bigger responsibility than I should have. When you accept somebody into your ride, their safety is your responsibility. In the end, we prevailed. Beer tasted great that night.

Day 3

The air was already hot by the time we rolled out in 7:15am. The forecast said we’ll hit 38C/100F. Luckily, on this day the ride is short, just 80km/50 miles from Auburn to Sacramento, so the idea was to get to Sacramento before noon and spend the afternoon somewhere chilling.

Road from Auburn to Folsom was a nice smooth downhill. We went fast. The riverside trail from there to Sacramento was not that enjoyable for me, though I’m not sure why. It has every reason to like — no car traffic, trees casting shade from time to time, and the road went left and right, up and down. One thing I didn’t appreciate was a mileage marker. It kept reminding me how slow we are going and how far away Sacramento was.

We eventually rolled into the old Sacramento, and found ourselves in an air-conditioned British pub with a friendly bartender. We spent a couple of hours there. I had not only one but two pints from high noon.

I wasn’t quite done for the day, though. I had to go ride out another 10 miles to get to a car I parked, then I needed to drive it back to the hotel in order to swap clothes and resupply. It was a peak heat time out there, but I figured I could do it. I also needed some alone time.

This ride to the northeast of Sacramento went through some of the poorest area. Along the bike trail were various homeless encampments. And despite this life-threatening scorching heat, I saw some homeless people sunbathing! I worried about their psychological well-being, but I was also a little scared, so I went on. It’s always disheartening to see just how bad of a job we do to distribute the wealth, on this richest country in the world.

My basic technique to ride in heat is to apply water liberally over my body and let the air cool me. I spent an entire bottle just to go this 10 miles. A couple of hours later I drove the car back to the parking and then rode back, the same deal. I thought I managed it pretty well, but during the dinner I run out of the energy, so I was probably actually pretty tired and over-confident.

Day 4

Our route this day was almost the exact reverse of my earlier ride from San Jose to Sacramento. So it’s started to feel a little bit like getting close to home. When you know the route, it’s always easier. We went through the golden countryside of California.

The temperature was still high, but as the day went by, the wind became noticeably cool. The pacific ocean is sending help on our way! This is a headwind section, but in this case I actually enjoyed that. There was endless supply of cold air to cool me down. We went through towns, over rolling hills, steadily heading southwest.

We took a couple of big food stops along the way as well, which is my preferred way to go about rides like this. Local restaurants are filled with local people who give me a glimpse of a life in here. Weekday day time is always relaxed. Old ladies having a get-together. Families together where kids were doing one thing while adults were doing another.

I would have loved to take another drink stop, but there was no suitable coffee shop, so we just marched on, and arrived at Walnut Creek to end the day.

Day 5

The last day was another short ride day, so we started late. At the roll out, my legs were tired, but in a few hours it became OK. This is how it always is in multi-day rides. You just need to get going, and it will feel better.

The road down to Sunol was a long straight stretch with little change, but the weather was even better than yesterday. A perfect California summer of warm sun and cool air. We went through many nice towns and communities. The road kept on, so did we.

Near Sunol, Linda had her shifter cable snapped, so we made a stop at a local bike shop in Fremont. This added another hour or two.

By this point, the roads were really starting to feel familiar. As we approach the finish line, the sense of familiarity got stronger almost minute by minute. I could sense that everyone was getting excited. We are near home!

I set our finish line to be at Peet’s that we always go after the end of our Saturday ride. We sat on the same spot we always do, and reflected a bit on this adventure. I wasn’t sure what to think really, but I hugged them tight.

We parted ways with Linda, but Larry came along with me further. I sensed that he didn’t want the day to end just yet, so I suggested that we have a beer stop.

As the bartender was pouring my beer, she remarked that I was riding. So I was able to tell her I just rode back from Tahoe. It took a bit for her to grok that I had just crossed California. This must have been inconceivable to her; She started telling around other staffs that “this guy just rode his bike from Tahoe!” and pretty soon everyone knew it. I felt flattered. I never had any doubt with my ability to finish this ride, but this made me realize just how far I came in my capabilities.

A random dude offered to buy me beer. I blushed and declined, but I kind of wish I took that offer.

I fist-bumped Larry and parted ways, and I rode last one mile back home. I felt a bit emotional rolling into my driveway. That’s how my 725km/450 mile journey came to an end.

Epilogue

The day after, I woke up 6am, biked (yes!) to San Jose train station, and took 8am train back to Sacramento in order to pick up my car I left behind there.

The train slowly went back north, criss-crossing with some of the routes we took a few days ago. I could see the intersections we turned, roads we travelled, and bridges we crossed. I stared at them as they went past the window. I hoped those cut scenes might help make sense of the intense week.

When I set my foot again on Sacramento, it was in a much cooler air, and the weekend atmosphere was a lot more festive. I thought about stopping at the same pub we spent hours a few days ago, to see if that might help me feel something, but I decided my summer vacation is over, and I just drove away.

To this day, even after writing this blog post, I still don’t really know what to make sense of the experience. It feels simultaneously very long and very short, very easy and very hard. What I remember is mostly bits and pieces of cut scenes. Individually they are meaningless, but collectively somehow it seems to represent something much bigger. But I don’t know how to describe that.

I’m just left with the feeling of deep content. I feel rather satisfied. Maybe that’s what drives me to travel like this.

I wonder where my next multi-day ride is.

References

Details of the route if anybody wants to try: The entire route

More pictures from the trip: Lake Tahoe ride 2024

Read the whole story
acdha
2 hours ago
reply
The “America’s Most Beautiful Bike Ride” lives up to the name.
Washington, DC
Share this story
Delete

Building search-based RAG using Claude, Datasette and Val Town

1 Share

Retrieval Augmented Generation (RAG) is a technique for adding extra "knowledge" to systems built on LLMs, allowing them to answer questions against custom information not included in their training data. A common way to implement this is to take a question from a user, translate that into a set of search queries, run those against a search engine and then feed the results back into the LLM to generate an answer.

I built a basic version of this pattern against the brand new Claude 3.5 Sonnet language model, using SQLite full-text search running in Datasette as the search backend and Val Town as the prototyping platform.

The implementation took just over an hour, during a live coding session with Val.Town founder Steve Krouse. I was the latest guest on Steve's live streaming series where he invites people to hack on projects with his help.

You can watch the video below or on YouTube. Here are my own detailed notes to accompany the session.

Bonus: Claude 3.5 Sonnet artifacts demo

We started the stream by chatting a bit about the new Claude 3.5 Sonnet release. This turned into an unplanned demo of their "artifacts" feature where Claude can now build you an interactive web page on-demand.

Screenshot of the Claude AI interface showing an interactive Mandelbrot fractal explorer and the prompts used to create it

At 3m02s I prompted it with:

Build me a web app that teaches me about mandelbrot fractals, with interactive widgets

This worked! Here's the code it wrote - I haven't yet found a good path for turning that into a self-hosted interactive page yet.

This didn't support panning, so I added:

Again but let me drag on the canvas element to pan around

Which gave me this. Pretty impressive!

Animated demo of Mandelbrot Fractor Explorer - I can slide the zoom and max iterations sliders and pan around by dragging my mouse on the canvas

Ingredients for the RAG project

RAG is often implemented using vector search against embeddings, but there's an alternative approach where you turn the user's question into some full-text search queries, run those against a traditional search engine, then feed the results back into an LLM and ask it to use them to answer the question.

SQLite includes surprisingly good full-text search, and I've built a lot of tools against that in the past - including sqlite-utils enable-fts and Datasette's FTS features.

My blog has a lot of content, which lives in a Django PostgreSQL database. But I also have a GitHub Actions repository which backs up that data as JSON, and then publishes a SQLite copy of it to datasette.simonwillison.net - which means I have a Datasette-powered JSON API for running searches against my content.

Screenshot of Datasette interface running a search with a custom SQL query for ruby on rails

Step one then was to prototype up a SQL query we could use with that API to get back search results. After some iteration I got to this:

select
  blog_entry.id,
  blog_entry.title,
  blog_entry.body,
  blog_entry.created
from
  blog_entry
  join blog_entry_fts on blog_entry_fts.rowid = blog_entry.rowid
where
  blog_entry_fts match :search
order by
  rank
limit
  10

Try that here. The query works by joining the blog_entry table to the SQLite FTS blog_entry_fts virtual table, matched against the ?search= parameter from the URL.

When you join against a FTS table like this a rank column is exposed with the relevance score for each match.

Adding .json to the above URL turns it into an API call... so now we have a search API we can call from other code.

A plan for the build

We spent the rest of the session writing code in Val Town, which offers a browser editor for a server-side Deno-based environment for executing JavaScript (and TypeScript) code.

The finished code does the following:

  1. Accepts a user's question from the ?question= query string.
  2. Asks Claude 3.5 Sonnet to turn that question into multiple single-word search queries, using a Claude function call to enforce a schema of a JSON list of strings.
  3. Turns that list of keywords into a SQLite FTS query that looks like this: ``
  4. Runs that query against Datasette to get back the top 10 results.
  5. Combines the title and body from each of those results into a longer context.
  6. Calls Claude 3 again (originally Haiku, but then we upgraded to 3.5 Sonnet towards the end) with that context and ask it to answer the question.
  7. Return the results to the user.

The annotated final script

Here's the final script we ended up with, with inline commentary. Here's the initial setup:

import Anthropic from "npm:@anthropic-ai/sdk@0.24.0";

/* This automatically picks up the API key from the ANTHROPIC_API_KEY
environment variable, which we configured in the Val Town settings */
const anthropic = new Anthropic();

We're using the very latest release of the Anthropic TypeScript SDK, which came out just a few hours prior to recording the livestream.

I set the ANTHROPIC_API_KEY environment variable to my Claude 3 API key in the Val Town settings, making it available to all of my Vals. The Anthropic() constructor picks that up automatically.

Next, the function to suggest keywords for a user's question:

async function suggestKeywords(question) {
  // Takes a question like "What is shot-scraper?" and asks 3.5 Sonnet
  // to suggest individual search keywords to help answer the question.
  const message = await anthropic.messages.create({
    max_tokens: 128,
    model: "claude-3-5-sonnet-20240620",
    // The tools option enforces a JSON schema array of strings
    tools: [{
      name: "suggested_search_keywords",
      description: "Suggest individual search keywords to help answer the question.",
      input_schema: {
        type: "object",
        properties: {
          keywords: {
            type: "array",
            items: {
              type: "string",
            },
            description: "List of suggested single word search keywords",
          },
        },
        required: ["keywords"],
      },
    }],
    // This forces it to always run the suggested_search_keywords tool
    tool_choice: { type: "tool", name: "suggested_search_keywords" },
    messages: [
      { role: "user", content: question },
    ],
  });
  // This helped TypeScript complain less about accessing .input.keywords
  // since it knows this object can be one of two different types
  if (message.content[0].type == "text") {
    throw new Error(message.content[0].text);
  }
  return message.content[0].input.keywords;
}

We're asking Claude 3.5 Sonnet here to suggest individual search keywords to help answer that question. I tried Claude 3 Haiku first but it didn't reliably return single word keywords - Sonnet 3.5 followed the "single word search keywords" instruction better.

This function also uses Claude tools to enforce a response in a JSON schema that specifies an array of strings. More on how I wrote that code (with Claude's assistance) later on.

Next, the code to run the search itself against Datasette:

// The SQL query from earlier
const sql = `select
  blog_entry.id,
  blog_entry.title,
  blog_entry.body,
  blog_entry.created
from
  blog_entry
  join blog_entry_fts on blog_entry_fts.rowid = blog_entry.rowid
where
  blog_entry_fts match :search
order by
  rank
limit
  10`;

async function runSearch(keywords) {
  // Turn the keywords into "word1" OR "word2" OR "word3"
  const search = keywords.map(s => `"${s}"`).join(" OR ");
  // Compose the JSON API URL to run the query
  const params = new URLSearchParams({
    search,
    sql,
    _shape: "array",
  });
  const url = "https://datasette.simonwillison.net/simonwillisonblog.json?" + params;
  const result = await (await fetch(url)).json();
  return result;
}

Datasette supports read-only SQL queries via its JSON API, which means we can construct the SQL query as a JavaScript string and then encode it as a query string using URLSearchParams().

We also take the list of keywords and turn them into a SQLite FTS search query that looks like "word1" OR "word2" OR "word3".

SQLite's built-in relevance calculations work well with this - you can throw in dozens of words separated by OR and the top ranking results will generally be the ones with the most matches.

Finally, the code that ties this together - suggests keywords, runs the search and then asks Claude to answer the question. I ended up bundling that together in the HTTP handler for the Val Town script - this is the code that is called for every incoming HTTP request:

export default async function(req: Request) {
  // This is the Val Town HTTP handler
  const url = new URL(req.url);
  const question = url.searchParams.get("question").slice(0, 40);
  if (!question) {
    return Response.json({ "error": "No question provided" });
  }
  // Turn the question into search terms
  const keywords = await suggestKeywords(question);

  // Run the actual search
  const result = await runSearch(keywords);

  // Strip HTML tags from each body property, modify in-place:
  result.forEach(r => {
    r.body = r.body.replace(/<[^>]*>/g, "");
  });

  // Glue together a string of the title and body properties in one go
  const context = result.map(r => r.title + " " + r.body).join("\n\n");

  // Ask Claude to answer the question
  const message = await anthropic.messages.create({
    max_tokens: 1024,
    model: "claude-3-haiku-20240307",
    messages: [
      { role: "user", content: context },
      { role: "assistant", content: "Thank you for the context, I am ready to answer your question" },
      { role: "user", content: question },
    ],
  });
  return Response.json({answer: message.content[0].text});
}

There are many other ways you could arrange the prompting here. I quite enjoy throwing together a fake conversation like this that feeds in the context and then hints at the agent that it should respond next with its answer, but there are many potential variations on this theme.

This initial version returned the answer as a JSON object, something like this:

{
    "answer": "shot-scraper is a command-line tool that automates the process of taking screenshots of web pages..."
}

Screenshot of the Val Town interface returning the JSON answer to the question in a preview window

We were running out of time, but we wanted to add an HTML interface. Steve suggested getting Claude to write the whole thing! So we tried this:

  const message = await anthropic.messages.create({
    max_tokens: 1024,
    model: "claude-3-5-sonnet-20240620", // "claude-3-haiku-20240307",
    system: "Return a full HTML document as your answer, no markdown, make it pretty with exciting relevant CSS",
    messages: [
      { role: "user", content: context },
      { role: "assistant", content: "Thank you for the context, I am ready to answer your question as HTML" },
      { role: "user", content: question },
    ],
  });
  // Return back whatever HTML Claude gave us
  return new Response(message.content[0].text, {
    status: 200,
    headers: { "Content-Type": "text/html" }
  });

We upgraded to 3.5 Sonnet to see if it had better "taste" than Haiku, and the results were really impressive. Here's what it gave us for "What is Datasette?":

Screnshot of a What is Datasette? page created by Claude 3.5 Sonnet - it includes a Key Features section with four different cards arranged in a grid, for Explore Data, Publish Data, API Access and Extensible.

It even styled the page with flexbox to arrange the key features of Datasette in a 2x2 grid! You can see that in the video at 1h13m17s.

There's a full copy of the final TypeScript code available in a Gist.

Some tricks we used along the way

I didn't write all of the above code. Some bits of it were written by pasting things into Claude 3.5 Sonnet, and others used the Codeium integration in the Val Town editor (described here).

One pattern that worked particularly well was getting Sonnet to write the tool-using TypeScript code for us.

The Claude 3 documentation showed how to do that using curl. I pasted that curl example in, added some example TypeScript and then prompted:

Guess the JavaScript for setting up a tool which just returns a list of strings, called suggested_search_keywords

Here's my full prompt:

#!/bin/bash
IMAGE_URL="https://upload.wikimedia.org/wikipedia/commons/a/a7/Camponotus_flavomarginatus_ant.jpg"
IMAGE_MEDIA_TYPE="image/jpeg"
IMAGE_BASE64=$(curl "$IMAGE_URL" | base64)
curl https://api.anthropic.com/v1/messages \
     --header "content-type: application/json" \
     --header "x-api-key: $ANTHROPIC_API_KEY" \
     --header "anthropic-version: 2023-06-01" \
     --data \
'{
    "model": "claude-3-sonnet-20240229",
    "max_tokens": 1024,
    "tools": [{
        "name": "record_summary",
        "description": "Record summary of an image using well-structured JSON.",
        "input_schema": {
            "type": "object",
            "properties": {
                "key_colors": {
                    "type": "array",
                    "items": {
                        "type": "object",
                        "properties": {
                            "r": { "type": "number", "description": "red value [0.0, 1.0]" },
                            "g": { "type": "number", "description": "green value [0.0, 1.0]" },
                            "b": { "type": "number", "description": "blue value [0.0, 1.0]" },
                            "name": { "type": "string", "description": "Human-readable color name in snake_case, e.g. \"olive_green\" or \"turquoise\"" }
                        },
                        "required": [ "r", "g", "b", "name" ]
                    },
                    "description": "Key colors in the image. Limit to less then four."
                },
                "description": {
                    "type": "string",
                    "description": "Image description. One to two sentences max."
                },
                "estimated_year": {
                    "type": "integer",
                    "description": "Estimated year that the images was taken, if is it a photo. Only set this if the image appears to be non-fictional. Rough estimates are okay!"
                }
            },
            "required": [ "key_colors", "description" ]
        }
    }],
    "tool_choice": {"type": "tool", "name": "record_summary"},
    "messages": [
        {"role": "user", "content": [
            {"type": "image", "source": {
                "type": "base64",
                "media_type": "'$IMAGE_MEDIA_TYPE'",
                "data": "'$IMAGE_BASE64'"
            }},
            {"type": "text", "text": "Describe this image."}
        ]}
    ]
}'

Based on that example and this JavaScript code:

const anthropic = new Anthropic();
const message = await anthropic.messages.create({
  max_tokens: 1024,
  system: "Suggest individual search keywords to help answer this question. No yapping.",
  messages: [
    { role: "user", content: question },
  ],
  model: "claude-3-haiku-20240307",
});
console.log(message.content[0].text);

Guess the JavaScript for setting up a tool which just returns a list of strings, called suggested_search_keywords

It gave me back this, which was the exact code I needed to make my tool-enabled API call from Val Town:

const anthropic = new Anthropic();
const message = await anthropic.messages.create({
  max_tokens: 1024,
  model: "claude-3-haiku-20240307",
  tools: [{
    name: "suggested_search_keywords",
    description: "Suggest individual search keywords to help answer the question.",
    input_schema: {
      type: "object",
      properties: {
        keywords: {
          type: "array",
          items: {
            type: "string"
          },
          description: "List of suggested search keywords"
        }
      },
      required: ["keywords"]
    }
  }],
  tool_choice: { type: "tool", name: "suggested_search_keywords" },
  messages: [
    { role: "user", content: question }
  ]
});

console.log(message.content[0].text);

I really like this trick, and I use it often in my own work. Find some example code that illustrates the pattern you need, paste in some additional context and get the LLM to figure the rest out for you.

This is just a prototype

It's important to reiterate that this is just a prototype - it's the version of search-backed RAG I could get working in an hour.

Putting something like this into production requires a whole lot more work. Most importantly, good RAG systems are backed by evals - it's extremely hard to iterate on and improve a system like this if you don't have a good mechanism in place to evaluate if your changes are making things better or not. Your AI Product Needs Evals by Hamel Husain remains my favourite piece of writing on how to go about putting these together.

Here are some of the other projects and links mentioned during our conversation:

Read the whole story
acdha
2 hours ago
reply
Washington, DC
Share this story
Delete

Supermajority: The Covenant Moms

1 Share
undefined

In 2023, a mass shooter attacked The Covenant School, a private Christian school in Nashville, Tennessee, and three mothers were compelled to act. Their mission: help pass some kind of gun control in one of the reddest states in the country, a state where the Republican Party has a supermajority in the legislature. But these women aren't your typical gun control activists. They're lifelong conservatives, believers in the Second Amendment and – at first – sure that their own party will understand their concerns. In episode 1 of Supermajority from NPR's Embedded, host Meribah Knight follows the women as they enter the state capitol for the first time in their adult lives. Will these political newcomers get what they came for? And what happens if they challenge those in power to do it? To listen to this series sponsor-free and support NPR, sign up for Embedded+ in Apple Podcasts or at plus.npr.org.

Read the whole story
acdha
3 hours ago
reply
Washington, DC
Share this story
Delete

Why SMBs Don't Deploy SSO

1 Share
Comments

In CISA’s Secure by Design whitepaper, we urge software manufacturers to consider how their business practices may inadvertently reduce the security posture of their customers. We recommend that essential security features should be available as part of the basic service offering. Consumers should not need to pay premium pricing, hidden surcharges, or additional fees for basic security hygiene. In particular, we mention that single sign-on capability should be available by default as part of the base offering—consumers should not need to bear an onerous “SSO tax” to get this necessary security measure.  

While it might seem reasonable to charge more for some features, this practice can hinder improvements in security posture by discouraging organizations from adopting a robust identity and access management (IAM) system. Organizations, including those below the security poverty line, deserve basic security hygiene. We argue that security should not be priced as a luxury good but instead should be considered a customer right. 

But the SSO tax is not the only barrier to adoption of SSO by small and medium sized businesses (SMBs). Customers have differing perspectives about SSO.  Some SMBs see it as adding value that improves their security posture, while others do not believe the expense of SSO delivers significant operational improvement and commensurate returns. This latter view reflects the need for clear messaging on the advantages of SSO.  We wanted to learn more about the uptake of SSO at SMBs and began work on a report to shine a brighter light on this topic. We conducted focus groups with SMBs to learn how well they understood SSO and its benefits, hear about their user experience with implementing and maintaining SSO, and understand the barriers SMBs encountered in implementing an SSO program. 

The report cites the following key findings: 

First, small enterprises often opt for manual passwords and hands-on approaches over an SSO option. These methods tend to have a reduced initial adoption cost, but this initial cost difference does not reflect the hidden administrative costs associated with maintaining manual passwords. A primary reason for the difference in the purchase cost for SSO is that SSO is often available only as a premium enterprise-level service. Such an enterprise service can cost significantly more per user than a lower-tier service that lacks SSO and typically requires a minimum number of users. These can be substantial barriers for many organizations. 

Second, a lack of technical know-how and awareness poses another significant barrier to SSO adoption. Vendors feel confident that they offer sufficient training materials and how-to guides to support customers in effectively deploying SSO technology. However, customers have different perceptions and user experiences. Customers see SSO as a complex solution with numerous moving parts that may impede its successful deployment. These implementation challenges need to be addressed before customers consider adopting SSO. 

Third, customers have varying degrees of satisfaction with the accuracy and completeness of support materials and instructions. Even some of the more experienced and technically savvy users reported the need to submit numerous support tickets and engage in multiple interactions with their vendor’s customer support staff to fill gaps or resolve inaccuracies and omissions. For SMBs with limited resources, the opportunity cost of that time and the hassles with support materials make the pursuit of proper SSO implementation seem prohibitively expensive and result in a negative user experience. 

Clearly there is work to be done not only on the economics aspects, but also on the user experience, the SSO service offering structure and product design, feature awareness, as well as requisite technical guidelines and instructions to properly implement and maintain SSO in order to increase adoption by SMBs. Manufacturers should recognize these unique challenges for their SMB customers and configure their settings to reduce operational friction and frustration. Doing so is in line with Secure by Design Principle 1: Take ownership of customer security outcomes. At the same time, CISA will continue to raise awareness about the benefits of SSO. Together we can meaningfully improve the security and safety of our nation.

You can find the report and accompanying fact sheet at Barriers to Single Sign-On (SSO) Adoption for Small and Medium-Sized Businesses: Identifying Challenges and Opportunities.


Comments
Read the whole story
fxer
5 hours ago
reply
Bend, Oregon
Share this story
Delete

Internet Archive forced to remove 500,000 books after publishers’ court win

1 Share
Internet Archive forced to remove 500,000 books after publishers’ court win

Enlarge (credit: Tim Macpherson | Image Source)

As a result of book publishers successfully suing the Internet Archive (IA) last year, the free online library that strives to keep growing online access to books recently shrank by about 500,000 titles.

IA reported in a blog post this month that publishers abruptly forcing these takedowns triggered a "devastating loss" for readers who depend on IA to access books that are otherwise impossible or difficult to access.

To restore access, IA is now appealing, hoping to reverse the prior court's decision by convincing the US Court of Appeals in the Second Circuit that IA's controlled digital lending of its physical books should be considered fair use under copyright law. An April court filing shows that IA intends to argue that the publishers have no evidence that the e-book market has been harmed by the open library's lending, and copyright law is better served by allowing IA's lending than by preventing it.

"We use industry-standard technology to prevent our books from being downloaded and redistributed—the same technology used by corporate publishers," Chris Freeland, IA's director of library services, wrote in the blog. "But the publishers suing our library say we shouldn’t be allowed to lend the books we own. They have forced us to remove more than half a million books from our library, and that’s why we are appealing."

IA will have an opportunity to defend its practices when oral arguments start in its appeal on June 28.

"Our position is straightforward; we just want to let our library patrons borrow and read the books we own, like any other library," Freeland wrote, while arguing that the "potential repercussions of this lawsuit extend far beyond the Internet Archive" and publishers should just "let readers read."

"This is a fight for the preservation of all libraries and the fundamental right to access information, a cornerstone of any democratic society," Freeland wrote. "We believe in the right of authors to benefit from their work; and we believe that libraries must be permitted to fulfill their mission of providing access to knowledge, regardless of whether it takes physical or digital form. Doing so upholds the principle that knowledge should be equally and equitably accessible to everyone, regardless of where they live or where they learn."

Internet Archive fans beg publishers to end takedowns

After publishers won an injunction stopping IA's digital lending, which "limits what we can do with our digitized books," IA's help page said, the open library started shrinking. While "removed books are still available to patrons with print disabilities," everyone else has been cut off, causing many books in IA's collection to show up as "Borrow Unavailable."

Ever since, IA has been "inundated" with inquiries from readers all over the world searching for the removed books, Freeland said. And "we get tagged in social media every day where people are like, 'why are there so many books gone from our library'?" Freeland told Ars.

In an open letter to publishers signed by nearly 19,000 supporters, IA fans begged publishers to reconsider forcing takedowns and quickly restore access to the lost books.

Among the "far-reaching implications" of the takedowns, IA fans counted the negative educational impact of academics, students, and educators—"particularly in underserved communities where access is limited—who were suddenly cut off from "research materials and literature that support their learning and academic growth."

They also argued that the takedowns dealt "a serious blow to lower-income families, people with disabilities, rural communities, and LGBTQ+ people, among many others," who may not have access to a local library or feel "safe accessing the information they need in public."

"Your removal of these books impedes academic progress and innovation, as well as imperiling the preservation of our cultural and historical knowledge," the letter said.

"This isn't happening in the abstract," Freeland told Ars. "This is real. People no longer have access to a half a million books."

In an IA blog, one independent researcher called IA a "lifeline," while others claimed academic progress was "halted" or delayed by the takedowns.

"I understand that publishers and authors have to make a profit, but most of the material I am trying to access is written by people who are dead and whose publishers have stopped printing the material," wrote one IA fan from Boston.

"These books being available on archive.org is a vital resource for me and many like me," wrote another from Australia. "A large amount of the Archive was never released in my corner of the globe, meaning I have few if any options for reading on niche subjects."

Publishers defend takedowns

On a help page, IA explained that half a million books are now gone because the takedown requests went beyond just the books at issue in the lawsuit.

"The Association of American Publishers (AAP), the trade organization behind the lawsuit, worked with some of its member publishers" that "were not named in the lawsuit to demand that we remove their books from our library," the help page said.

Asked for comment, an AAP spokesperson provided Ars with a statement defending the takedown requests. The spokesperson declined to comment on readers' concerns or the alleged social impacts of takedowns.

"As Internet Archive is certainly aware, removals of literary works from Internet Archive’s transmission platform were ordered by a federal court with the mutual agreement of Internet Archive, following the court’s unequivocal finding of copyright infringement," AAP's statement said. "In short, Internet Archive transmitted literary works to the entire world while refusing to license the requisite rights from the authors and publishers who make such works possible."

In the open letter to publishers—which Techdirt opined "will almost certainly fall on extremely deaf ears"—the Internet Archive and its fans "respectfully" asked publishers "to restore access to the books" that were removed.

They also suggested that "there is a way" to protect authors' rights and ensure they're fairly compensated "while still allowing libraries to do what they have always done—help readers read."

"We urge you to explore solutions with the Internet Archive that support both authors and the public good, such as selling eBooks to libraries to own, lend, and preserve," the letter said.

Internet Archive’s fair use defense

If publishers won't bring back the books, IA plans to fight to restore access to the titles in court. Ars was not immediately able to reach IA for comment, but a court brief filed in April sheds light on how IA plans to convince the appeals court to reverse the lower court's injunction on its digital lending.

For the appeals court, the "key question," IA's brief said, is whether controlled digital lending serves copyright's purposes and important public interests. IA argues that it does because its open library is used for "purposes of teaching, research, and scholarship." Publishers cannot dispute that, IA claimed, just because "some books are also borrowed for recreational use (just as they are at all libraries)."

"The record is replete with examples of IA facilitating access to books needed for classroom use and academic research that would not have been possible otherwise," IA's brief said.

For IA's digital lending to be considered fair use, the brief said, the court must balance all factors favoring a ruling of fair use, including weighing that IA's use is "non-commercial, serves important library missions long recognized by Congress, and causes no market harm."

Publishers with surging profits have so far struggled to show any evidence of market harm, while IA has offered multiple expert opinions showing that ebook licensing was not negatively impacted by IA's digital lending.

"Publishers' ebook revenues have grown since IA began its lending," IA argued.

And even when IA temporarily stopped limiting the number of loans to provide emergency access to books during the pandemic—which could be considered a proxy for publishers' fear that IA's lending could pose a greater threat if it became much more widespread—IA's expert "found no evidence of market harm."

"Yet they ask the Court to assume, without support, that their profits could have been even higher without IA's lending," IA's brief said.

The prior court ruling also erred, IA suggested, in basing its commerciality ruling on supposed "benefits" to IA—like donations and small payments from bookseller Better World Books. Donations don't "render a nonprofit use commercial," IA argued, and profits from small payments went right back into funding IA's lending.

"Many nonprofits do the same, and those partnerships do not transform them into commercial entities," IA argued.

But for IA, the biggest oversight of the prior ruling was "the district court's failure to consider" that "promoting availability" of knowledge and information is a primary consideration for copyright law.

"To the contrary, the decision barely mentions copyright's ultimate purpose of promoting broad public availability of literature, music, and the other arts," it said.

IA hopes the appeals court will agree that publishers' ebook licenses are in a separate market from the nonprofit's controlled digital lending, which IA argued serves a different purpose than ebooks. "Publishers' licenses cannot serve library missions such as preserving permanent collections, widening reach and resources through interlibrary loans, and protecting patron privacy," IA argued in defense of controlled digital lending.

"IA's lending is noncommercial, transformative, and supportive of copyright's purposes," IA's brief said, arguing that affirming the prior court's decision "would harm not only IA but also many other libraries and the publics they serve."

Freeland told Ars it could take months or even more than a year before a decision is reached in the case.

While IA fights to end the injunction, its other library services continue growing, IA has said. IA "may still digitize books for preservation purposes" and "provide access to our digital collections" through interlibrary loan and other means. IA can also continue lending out-of-print and public domain books.

One IA fan in rural India fears that if publishers win, it would permanently cut many people like her off from one of the few reliable resources she has to access rare books.

"If you are going to ban online availability of these resources, what about us?" she asked.

Read Comments

Read the whole story
fxer
6 hours ago
reply
Bend, Oregon
Share this story
Delete

Dell said return to the office or else—nearly half of workers chose “or else”

1 Share

Return to office —

Workers stayed remote even when told they could no longer be promoted.

Big tech companies are still trying to rally workers back into physical offices, and many workers are still not having it. Based on a recent report, computer-maker Dell has stumbled even more than most.

Dell announced a new return-to-office initiative earlier this year. In the new plan, workers had to classify themselves as remote or hybrid.

Those who classified themselves as hybrid are subject to a tracking system that ensures they are in a physical office 39 days a quarter, which works out to close to three days per work week.

Alternatively, by classifying themselves as remote, workers agree they can no longer be promoted or hired into new roles within the company.

Business Insider claims it has seen internal Dell tracking data that reveals nearly 50 percent of the workforce opted to accept the consequences of staying remote, undermining Dell's plan to restore its in-office culture.

The publication spoke with a dozen Dell employees to hear their stories as to why they chose to stay remote, and a variety of reasons came up. Some said they enjoyed more free time and less strain on their finances after going remote, and nothing could convince them to give that up now. Others said their local offices had closed since the pandemic or that they weren't interested in promotions.

Others still noted that it seemed pointless to go in to an in-person office when the teams they worked on were already distributed across multiple offices around the world, so they'd mostly still be on Zoom calls anyway.

One person said they'd spoken with colleagues who had chosen to go hybrid, and those colleagues reported doing work in mostly empty offices punctuated with video calls with people who were in other mostly empty offices.

Many interviewed admitted they were looking for work at other companies that aren't trying to corral employees back into the office.

Dell is not the only company struggling with this. For example, we've reported several times on Apple's internal struggles and employee revolts over remote work.

Executive management at the companies trying to restore in-person work culture claim that working together in a physical space allows for greater collaboration and innovation.

Research on this topic has offered mixed insights, but there does seem to be some consensus that remote work is accompanied by very modest drops in productivity—for example, a working study at the Stanford Institute for Economic Policy Research suggested around a 10 percent drop in productivity, even as it noted that the cost-saving benefits of remote work could make up for some of that.

Read the whole story
dreadhead
6 hours ago
reply
Vancouver Island, Canada
Share this story
Delete

Make a Home Assistant Dashboard with a Pi Zero 2 W and a RGB Matrix Bonnet

1 Comment

Have you been looking for that perfect home assistant display? Maybe Anthony DeChiaro’s build on Hackster.io is exactly what you’ve been dreaming of!

There were a number of competing requirements I had, which ultimately resulted in the hardware chosen:

  • High-contrast display and easily visible from across the room in various lighting conditions
  • Highly reliable with a long service life and minimal risk of requiring to replace a burnt-out display
  • Low-profile, which I could easily mount to the wall
  • Fairly moderate cost
  • Low power usage

Read more


Read the whole story
JayM
9 hours ago
reply
Neat.
Atlanta, GA
Share this story
Delete
Next Page of Stories