• NaN years ago - link
    by @ghost

    Javascript Destructuring

    The quickest way to explain javascript destructuring is with an example.

    Consider this object deconstruction:

    This syntax translates to:

    Consider what it would take to construct the object in Mark A, rather than to deconstruct an existing object?

    You may construct an object like so:

    You'll notice the syntax for constructing this payload object is the exact same syntax for destructuring it, only we reversed which side of the assignment payload was on.

    Object deconstructors

    Next I'll provide a quick overview of different destructuring operations and then we will combine them to get the result above.

    Object destructuring

    Providing defaults

    Renaming destructured properties

    Destructuring arrays

    Destructuring with spread operators

    The spread operator is generally used to collect varargs, like function(...args) {} however, in the context of deconstruction, it collects any elements not explicitly deconstructed.

    For instance, spread deconstruction for an object:

    For instance, spread deconstruction for array:

    Note: You can see how this is some pretty handy syntactic sugar. You can save a lot of writing time and screen space by using these.

    Dynamic property name deconstruction

    That's the extent of my off-hand knowledge of very fun javascript deconstruction patterns.

    Putting it all together

    Initially we considered this example and set out to understand its meaning:

    We'll take this section by section

    Deconstruct collection property of payload and assign value to local const.

    Deconstruct result property.

    In each, the right hand side of a destructured property name is the value of that property itself which can then be further deconstructed.

    Since result is an array, we can use array deconstruction as we demonstrated before to simply get the first result of the result array.

    They all effectively do the same thing. / If object destructuring ever looks confusing to you, just remember its the reverse of constructing objects.

    Given this, what might code to construct the payload look like?

    Take a gander first.

    Here's a solution:

    Now if we run:

    What will the value of data be?

    If you've figured that out, you are well on your way to understanding destructuring.

    The answer is { rid: 'RID1'}.

    Continuing on:

    First consider the complimentary object construction:

    We see we are defining a payload object with a context property with a hooks property that is an array.

    However, perhaps context may be undefined? That's why we provide a default in the destructure.

    Consider the following code:

    Question: What are the values of hooks and hooks2?

    Take a moment if you want.

    Answer: The value of each is [].

    Now, we've examined each portion of the deconstruction separately, let's look at it one more time:

    Ahhh, there we go. Not so confusing now, is it?

    Stay tuned for my next destructuring article where we discuss advanced destructuring.


    Post script: as one final test:

    What is the value of soSad?


    tags: rixfeed dev log programming glossary cbs

  • NaN years ago - link
    by @ghost

    what does "highly granular" mean? hibefisfkdk

    bepiis bappas

    nebbllbly

    burbess

  • NaN years ago - link
    by @ghostin typescript, generate a nextjs page with getServerSideProps and a default exported react component
  • NaN years ago - link
    by @ghost

    Ivy Collegiate Social Media Manager Responsibilities

    Every week we publish two or more headlines for the satire website https://www.theivycollegiate.com/

    I'll send you two articles each week that we want to post.

    Example Article: https://www.theivycollegiate.com/post/we-were-always-gay-confirm-frogs

    Posting Instructions

    Twitter/X:

    • Open twitter on your mobile phone
    • Login to your authorized account for https://twitter.com/ivycollegiate
    • Set app appearance to "Dark Mode"
    • Copy the headline from the article
    • Save the image from the article
    • Create a new tweet
    • Paste the headline for the article
    • Add the image from the article
    • Post the tweet
    • Screenshot the tweet
    • Crop the tweet

    Example Tweet: https://x.com/ivycollegiate/status/1696681431278530875?s=20

    Example Screenshot: tweet

    Instagram Account:

    • Open instagram on your mobile phone
    • Login to your authorized account for https://instagram/theivycollegiate
    • Create new post
    • Select your Twitter screenshot
    • Copy the headline from the article
    • Add the image from the article
    • Paste the headline from the article as the caption
    • Add tag #satire
    • Add 2 - 3 relevant tags of your choice
    • Post the instagram post
    • Share post to @theivycollegiate's public story

    Example Post: https://www.instagram.com/p/CwjHWFDpilv/

    Additional Guidelines:

    • Please try to post each article 3 - 4 days apart
  • NaN years ago - link
    by @ghost

    Note - Juked by a Chicken

    I swear, I almost had a stroke putting the chicken away today.

    I have had way too little sleep, way too little to eat, and stretched myself out way too thin to function.

    Almost twice in the past 48 hours, I nearly fainted from standing up too fast.

    I remember feeling the onset of faintness, bracing myself against a wall or preparing to fall safely in case I couldn't control my landing.

    So when I say I thought I almost died chasing this chicken, I mean it.

    Chasing chickens is an art.

    You have to juke the chickens.

    They'll run circles around tables or go under things you can't go under.

    They'll run under chairs or through bushes, under fences, between your legs. All you can do is limit their escape routes until you're close enough to gently grab them without hurting them.

    It's a mindless game of chess.

    Like chess, the first two moves decide the winner.

    Like chess, the rules have no meaning.

    Like chess, it can take you 30 seconds, or it could take you an hour.

    But a chicken plays chess like a hedge fund manager plays the stock market: mindless gambles with zero calculation.

    Their brains have the exact required caloric intake to function at any level.

    They are min-max machines of stupidity and survival.

    Yesterday, she made no fuss coming inside, but today I could tell it was going to be a struggle. We began with the customary dance of slowly strafing around each other, assessing the layout of the battlefield.

    This was the cease-fire.

    After a few laps around the patio table, I realized this was going to be difficult.

    You grow slower as the hunt drags on. There was no time to waste.

    I began to increase my pace, hone my agility, and juke the chicken.

    I had juked her into a corner: between two plant cages and a reclining patio chair. I was straddling the chair, slowly moving my hands to guard the left and right exit opportunities she had.

    To catch a chicken, you have to think like a chicken.

    And the only way to think like a chicken is to not think at all.

    I rendered my mind a blank slate, regressed to my most basal nature.

    I approached carefully, mindful she could make the bolt at any second, and I wouldn't be able to counter because I was wrapping my arms and legs around this chair.

    I'm closing in, and I get to the point where I know I'm in range.

    She usually surrenders once she knows you're in range. I relax my guard. The hunt is complete.

    But suddenly, I could sense she was not going to freeze.

    In her eyes, I witnessed the very incarnation of the words fight or flight. I saw the gunpowder spark of the starter pistol itself.

    The world came to slow motion. Space collapsed around us, and we became alone together, locked in this singular moment in time for eternities.

    I could see her mind executing quantum-speed processing: solving the single-source shortest path exit, solving the traveling salesmen problem while she was at it.

    I saw her navigate the maze of the bars of the patio chair, my arms, and the plant cages like she was Neo from the Matrix. It was like watching water flow through river rocks, like wind through trees.

    She bolted underneath the patio chair and forced me to nearly about-face to try and meet her.

    As soon as I lurched up, a sharp shock was sent to my nervous system. My vision blacked out for a moment. Those shapes and colors you see when you're rubbing your eyes too much appeared, those strange wavy patterns and avant-garde paintings that flash in your mind when you do. Then, I felt a sharpness, like needles punching through all the veins in my forearms and neck.

    A pain so intense it made me contemplate the pain of death.

    And that was my thought:

    "This is the end."

    "This is how I will die."

    "Out juked by a chicken."

  • NaN years ago - link
    by @ghost

    you know what would be wild?

    three gates in my garage.

    one gate right by the garage door

    another gate about 4 or 5 feet from there

    a final gate about 4 or 5 feet from the house entrance

    keep everything that needs to stay secure in in the central gated section.

    so, to get to the secure area through the garage, you must:

    • get through the garage door
    • get through the first gate
    • get through the second gate

    to get to the secure area through the front, you must:

    • get through the front door
    • get through the house gate
    • get through the third gate

    Reasonably secure.

    Then I should have a gun safe bolted to the ground.

    Inside will be two more safes.

    Sound secure?

  • NaN years ago - link
    by @ghost

    Certainly! Here's an example of a function that creates a 2D grid of null elements based on the specified number of rows and columns:

    In this example, the createGrid function accepts two parameters - rows and columns, representing the desired number of rows and columns in the grid.

    The function initializes an empty grid array and then uses nested loops to create the rows and fill them with null values. The outer loop iterates rows times, while the inner loop iterates columns times, pushing null elements into each row.

    Finally, the created grid is returned and printed to the console.

    You can adjust the rows and columns variables with the desired values to create a grid of the desired size.

    Let me know if you need any further assistance or have any other questions!

  • NaN years ago - link
    by @ghost

    create a function that creates a 2d grid of null elements with length equal to rows and inner length equal to columns

  • NaN years ago - link
    by @ghost

    Rixfeed Dev Log

    I just finished writing my first VS Code extension!

    Below is the README.md.

    Line Note Plus

    Line Note Plus is a VSCode extension to add Markdown notes to your code that are visible when hovering over the noted line. Based on Line Note.

    basic-demo

    VSCode Marketplace

    Features

    Invoke Add note at current position from the command palette or context menu. You can see the note you wrote as hover text.

    Notes are saved by default in $PROJECT_ROOT/.vscode/.linenoteplus like .vscode/.linenoteplus/<short-uid>.md.

    Overview

    • Edit/open or remove note via Cmd + Click
    • Markdown note previews on hover
    • Right-click to add note to line
    • Right-click to reveal notated line
    • Delete a note marker by manually deleting in text editor
    • Add a note marker by manually typing in text editor
    • Custom note names
    • Command to add note
    • Command to edit/open note
    • Command to remove note
    • Command to reveal notated line
    • Notes move with code changes
    • Notes can be moved between files
    • Notes are not affected by refactors
    • Add notes within your notes
    • Customize notes directory, note marker background color, and annoted line ruler color
    • Configure to delete orphaned notes on-save, on-inteveral, on-save-and-on-interval, or never

    API

    Commands

    • linenouteplus.addNote: Add note at current position (Annotate Line)
    • linenouteplus.openNote: Edit note at current position (Open Note)
    • linenouteplus.revealLine: Reveal line in notated file (Show Note Marker)
    • linenouteplus.removeNote: Remove note at current position (Delete Note)

    Configuration

    • linenoteplus.cleanUpOrphanedNotesInterval: Interval at which to clean up unused notes in the background in ms. Only applies if cleanUpOrphanedNotes is set to on-interval or on-save-and-on-interval. Default: 60000 (60s). For performance, a larger value is recommended.
    • linenoteplus.cleanUpOrphanedNotes: Defines the cleanup behavior for orphaned notes. It can be set to on-save, on-interval, on-save-and-on-interval, or never. Default: on-save-and-on-internal. Note that when using on-save or on-save-and-on-interval, if you delete a note marker and save the file then your note file will also be deleted.
    • linenoteplus.includePaths: Specifies file pattern globs to scan for note markers. Directories that don't match these patterns will be ignored.
    • linenoteplus.gutterIconPath: File path of the icon to be displayed in gutter.
    • linenoteplus.lineColor: Sets the background color for inline note markers (Name, HEX, or RGB).
    • linenoteplus.rulerColor: Sets the ruler color for notated lines (Name, HEX, or RGB).
    • linenoteplus.showGutterIcon: Whether to display the gutter icon in the gutter for a noted line. Default: true.

    Demos

    Adding a note

    add-note

    Custom note title

    custom-name

    Notes move with code changes

    moves-with-code

    Notes can be moved across files

    move-notes-across-files

    Reveal notated line command

    reveal-notated-file

    Refactor does not affect notes

    refactor-does-not-affect-notes

    Acknowledgements

    Line Note Plus is a fork of Line Note by tkrkt. This library's design was also informed by Marginalia by indiejames.

    Known Bugs

    • Gutter icon does not display.
  • NaN years ago - link
    by @ghost

    Rixfeed Dev Log

    I've created a repositor of useful ts-node powered command line utilities.

    Link: https://github.com/prmichaelsen/devx

    Currently supports only:

    • ls-recursive

    But the commands can be run globally on unix-like shells (with autocompletion) like devx ls-recursive.

    From the README.md:

    What is this package?

    This is a repository of command line utilities written in typescript for use with ts-node.

    How do I run it?

    The preferred way to run scripts with the ts-node version specified in the package.json. To do so, use the provided devx bash script. devx bash script.

    For example: ./devx ls-scripts.ts src

    Use devx command globally

    Note: Only supports unix-like shells like MacOS and Linux distributions. Does not work on Windows.

    You only need to update your .bashrc, .bash_profile, or .zshrc.

    To do so, run ./init and follow the instructions provided.

    This will also add bash completion for your scripts.

  • NaN years ago - link
    by @ghost

    Conclusion

    There's a lot more required to actually get our search service to use these values and sort the results in the order provided.

    I won't go over all of it, but I do want to tie everything together.

    From the onset, our goal was to take what's in the url bar:

    And get it into our search feature so we can filter and sort on the values.

    First, I will show you the code that generates the sort function our search feature will use:

    It's nice we wrote all those re-usable helper functions! That made the logic for these components much simpler.

    And here is where we put it (mostly, finally) all together:

    Now we can pass our filters and transformResults to our search feature and it will only return pages that match the ids we specified and in the same order as we specified them.

    That's a lot of work just to enable creating ordered lists just via url params, isn't it!

    I think it's worth it though. I enjoyed the process and I have a neat little tool I can leverage as I experiment building the website and its pages. A better solution may present itself, but for now, this is an idiomatic and intuitive way to create saved lists without requiring any data being saved to a server. This is excellent for my usecase: ad-hoc arrangements of data accessible by URL.

    It's possible I'll never use this feature again. However, if it's useful, it may become central to how the application and pages work and the concept may be extended to enable writing even more powerful queries--just with URL query params. 😉

    This method is certainly with its limitations. Browsers are only required to support 2048 characters in a URL, so your lists cap out at a certain length. Additionally, even modest page chains generate a large URL that is not entirely savory to look at. Eventually, I will need to allow users to create custom filters that are saved to the database. But for simpler use cases, I think it does the trick.

    Thank you for tuning in and stay copacetic.

    - Pat

  • NaN years ago - link
    by @ghost

    Writing the helper functions

    I extracted my code from my naive function into helper functions and ran the tests.

    All tests failed! Immediately I knew there was work to be done. But because tests output the differences between your expected output and the actual output, resolving this is easy.

    After fixing the bugs, our functions are defined as follows:

    Now all test cases for the helper functions are passing. But the main replaceMultiValueFilters still fails its tests. What's happening? Fortunately we have eliminated potential problem areas with reasonably high confidence.

    Upon taking a closer look at the code, I noticed a very subtle problem:

    Can you spot it? The code is designed to take our input filters and replace each filter one at a time in a loop. However, I was using filters.replace instead of filter.replace. This means each time I called replace, I was calling it on the original filter instead of our "under construction" filter.

    This is why my tests of two field paths or more were failing.

    I didn't catch this myself! In fact, my tests did. When I refactored this logic into _replaceValues and wrote tests for it, I discovered it was working just fine. This left one remaining spot to check in my code, and potential hours worth of debugging over a small small typo were saved.

    After changing this line:

    The function worked perfectly and passed all our test cases.

  • NaN years ago - link
    by @ghost

    Writing the code

    We'll start with my naive implementation.

    This function finds each fieldPath:[value1,value2, ...] pattern in the filters query param string and replaces it with (fieldPath:value1 OR fieldPath:value2 OR ...).

    It achieves this using regex to find matches. We then iterate over our matches, extract the fieldPath and the values, format them as required, and then replace the old value.

    However, my code isn't passing our test cases. What's wrong?

    We have a couple of options for deducing the issue:

    • Read and reason about the code
    • Launch the tests in debug mode
    • Use console.log to output variables at different points of interest in the function.

    However, there is another option. This is where TDD shines.

    I am reasonably confident that most of the internal logic of this component is correct. There is some small bug somewhere that I need to catch and fix. Instead of spending hours trying to find it, we will break the function up into smaller chunks with their own set of tests. This allows us to narrow down our search by confirming which parts of the code are doing what we want.

    Here is our revised function:

    Note we are now using the additional functions _getFieldPath, _getValues, and _replaceValues but we haven't defined them yet. That's because we are going to use TDD for these functions, too.

    I know what I expect these functions to be called with and what I expect them to output. And so, I write tests to validate that behavior. Here are some sample tests:

    Our regex pattern is pretty complicated as well, so we will define a test for that, too:

    These are important ins & outs for the behavior of our function. By ensuring we pass these tests, our function should work exactly as designed.

  • NaN years ago - link
    by @ghost

    Defining the jest spec

    A "spec" is just a test file. We call it "spec", short for "specification", because well written tests clearly define the behavior of a function.

    There is no need for comments or guessing. The function does exactly what the spec says it will do. This also means we can change the inner implementation of the function at any time as long as it still meets the spec.

    The test cases in the spec run against your code to ensure this.

    To define a test case, we need to define the input value and the output value we are validating the function against.

    Here are some simple tests that confirm the filters parameter is converted to the type required by the search feature. I'm essentially taking the example I gave before but writing it in code.

    With our tests defined, we can now see clearly how this function is intended to work.

  • NaN years ago - link
    by @ghost

    Mapping the filters query param to the search feature

    We need to write code to turn filters=id:[id1,id2,id3,id4] into the format the search feature understands.

    The current format looks like this:

    And the end format will look like this:

    This text above is a search filter string. When executed as part of a search, it retrieves any page that matches any condition where id equals one of those ids.

    I'll start by defining a function in typescript to accomplish this behavior. We'll fill in the function body later.

    This function was developed using Test Driven Development, or TDD.

    We will follow the same process to explain the code.

    We'll start with some jest specs.

  • NaN years ago - link
    by @ghost

    Breaking filters down

    Let's take another look at our filters query param. We'll use an example that's easier to read and reason about:

    filters is a query parameter that is sent to the search feature whenever a page is loaded.

    The search feature is powered by a lightning-fast sophisticated search and discovery API. Currently, complex queries over large data sets of 10K documents or more take as little as 3ms to run. It leverages advanced search algorithms and indexing techniques to swiftly search through large volumes of data in real time. The true power of the search feature comes from filtering.

    Our filter above has the following meaning to the search feature:

    Before the search feature can understand the filters param, I have to convert it to a "language" it understands.

    From here on, this article will get a little more technical.