Deprecated: Creation of dynamic property wpdb::$categories is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$post2cat is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Creation of dynamic property wpdb::$link2cat is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 668

Deprecated: Return type of WP_Theme::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 554

Deprecated: Return type of WP_Theme::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 595

Deprecated: Return type of WP_Theme::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 535

Deprecated: Return type of WP_Theme::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-theme.php on line 544

Deprecated: Return type of WP_REST_Request::offsetExists($offset) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 960

Deprecated: Return type of WP_REST_Request::offsetGet($offset) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 980

Deprecated: Return type of WP_REST_Request::offsetSet($offset, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 992

Deprecated: Return type of WP_REST_Request::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/rest-api/class-wp-rest-request.php on line 1003

Deprecated: Return type of WP_Block_List::current() should either be compatible with Iterator::current(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 151

Deprecated: Return type of WP_Block_List::next() should either be compatible with Iterator::next(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 175

Deprecated: Return type of WP_Block_List::key() should either be compatible with Iterator::key(): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 164

Deprecated: Return type of WP_Block_List::valid() should either be compatible with Iterator::valid(): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 186

Deprecated: Return type of WP_Block_List::rewind() should either be compatible with Iterator::rewind(): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 138

Deprecated: Return type of WP_Block_List::offsetExists($index) should either be compatible with ArrayAccess::offsetExists(mixed $offset): bool, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 75

Deprecated: Return type of WP_Block_List::offsetGet($index) should either be compatible with ArrayAccess::offsetGet(mixed $offset): mixed, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 89

Deprecated: Return type of WP_Block_List::offsetSet($index, $value) should either be compatible with ArrayAccess::offsetSet(mixed $offset, mixed $value): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 110

Deprecated: Return type of WP_Block_List::offsetUnset($index) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 127

Deprecated: Return type of WP_Block_List::count() should either be compatible with Countable::count(): int, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in /var/www/twodee/blog/wp-includes/class-wp-block-list.php on line 199

Deprecated: Creation of dynamic property Automattic\Jetpack\Connection\Manager::$error_handler is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-connection/src/class-manager.php on line 91

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Instagram_Gallery::$is_wpcom is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-instagram-gallery.php on line 23

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Mailchimp::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php on line 17

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Tweetstorm_Gather::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-tweetstorm-gather.php on line 21

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Tweetstorm_Gather::$is_wpcom is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-tweetstorm-gather.php on line 22

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Gutenberg_Available_Extensions::$wpcom_is_site_specific_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php on line 20

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Memberships::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php on line 23

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Memberships::$wpcom_is_site_specific_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php on line 24

Deprecated: Creation of dynamic property WPCOM_REST_API_V2_Endpoint_Subscribers::$wpcom_is_wpcom_only_endpoint is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php on line 15

Deprecated: Creation of dynamic property Automattic\Jetpack\Sync\Queue::$random_int is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-sync/src/class-queue.php on line 38

Deprecated: Creation of dynamic property Automattic\Jetpack\Sync\Queue::$random_int is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/vendor/automattic/jetpack-sync/src/class-queue.php on line 38

Deprecated: Creation of dynamic property WPCOM_Widget_Goodreads::$shelves is deprecated in /var/www/twodee/blog/wp-content/plugins/jetpack/modules/widgets/goodreads.php on line 33

Deprecated: DateTime::__construct(): Passing null to parameter #1 ($datetime) of type string is deprecated in /var/www/twodee/blog/wp-includes/script-loader.php on line 348

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_classic_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 347

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 349

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$toolbar_block_side is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 350

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$panels_block is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 351

Deprecated: Creation of dynamic property Advanced_Editor_Tools::$used_block_buttons is deprecated in /var/www/twodee/blog/wp-content/plugins/tinymce-advanced/tinymce-advanced.php on line 354

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: Creation of dynamic property WP_Block_Type::$plan_check is deprecated in /var/www/twodee/blog/wp-includes/class-wp-block-type.php on line 333

Deprecated: ltrim(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/twodee/blog/wp-includes/wp-db.php on line 3030

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$object_id is deprecated in /var/www/twodee/blog/wp-includes/class-wp-term.php on line 198

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Warning: Cannot modify header information - headers already sent by (output started at /var/www/twodee/blog/wp-includes/class-wp-block-list.php:14) in /var/www/twodee/blog/wp-includes/feed-rss2.php on line 8
keystrokes – teaching machines https://twodee.org/blog Tue, 04 Jun 2013 00:34:36 +0000 en-US hourly 1 https://wordpress.org/?v=5.7.1 Keystrokes File Format https://twodee.org/blog/7919 https://twodee.org/blog/7919#respond Mon, 03 Jun 2013 21:13:09 +0000
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
http://www.twodee.org/blog/?p=7919 [...]]]> A Keystrokes text movie is composed of a number of frames. Each frame is currently stored in a separate file, and all metadata describing the frame is stored in the file name. The only thing inside the file is the text of the frame (or a diff describing how to construct it from the previous frame’s text). A filename has this format:

source-serialid-cursorline-cursorcolumn-timestamp

Source is the name of the original file whose editing got recorded. Serial id is the number of the frame in the frame sequence. This number gives no information about the time the frame was recorded. Cursorline and cursorcolumn record the position of the cursor at the time the frame was recorded. Timestamp records the time the frame was recorded. The value is produced by C’s strftime(“%s”), whose documentation has this to say about %s:

The number of seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).

If storing the metadata like this ends up being a bad idea, we’ll fix it. Caveat emptor.

]]>
https://twodee.org/blog/7919/feed 0
Keystrokes Patcher https://twodee.org/blog/7914 https://twodee.org/blog/7914#respond Mon, 03 Jun 2013 20:50:30 +0000
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
http://www.twodee.org/blog/?p=7914 [...]]]> For our Keystrokes project, we grab “frames” for our text movie as snapshots of the file being edited. We don’t really want to pass the complete file around for every snapshot, so instead we store diffs between frames that allow us to reconstruct any particular frame beyond the first.

To produce frame 2, we apply diff 2 to frame 1. To produce frame 3, we apply diff 3 to (diff 2 to frame 1). To produce frame N, we apply diff N to (diff N – 1 to (… to frame 1)).

Since we take snapshots at every cursor change, the diffs are likely to be quite small, often a line or two. Grabbing a text movie from the web should be much faster compared to grabbing the complete set of snapshots.

The reconstruction process involves parsing the diff file and applying it just like the Unix patch utility does. What follows is my attempt at understanding the diff protocol and reconstructing patch. The Patcher class takes a complete frame and a patch (both stored as String lists to make indexing into the files easier) and applies the patch to produce the next complete frame.

package org.twodee.undiff;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.twodee.utilities.Utilities;

/**
 Patches a source text modified by changes, deletes, and appends.
 */
public class Patcher {
  private static final Pattern TRANSACTION_PATTERN = Pattern.compile("(\\d+)(?:,(\\d+))?([acd])(\\d+)(?:,(\\d+))?");

  private ArrayList<String> pre;
  private ArrayList<String> patch;
  private int iPatchLine;
  private int iPreLine;
  private ArrayList<String> post;

  /**
   Applies a patch to a source text.
   @param pre The source text, given as a list of lines.
   @param patch The patch text as produced by diff, given as a list of lines.
   @return The destination text, given as a list of lines.
   */
  public static ArrayList<String> patch(ArrayList<String> pre, ArrayList<String> patch) {
    Patcher patcher = new Patcher(pre, patch);
    patcher.apply();
    return patcher.post;
  }

  /*
   Not meant for public use.
   */
  private Patcher(ArrayList<String> pre, ArrayList<String> patch) {
    this.pre = pre;
    this.patch = patch;
  }

  private void apply() {
    // We start at the beginning of the patch and the pre. Post gets built up
    // as we advance through the patch, but it starts off empty.
    iPatchLine = 0;
    iPreLine = 0;
    post = new ArrayList<String>();

    // Read and apply the patch, one transaction at a time. Since not every
    // line may be altered by the transactions, before we apply a transaction,
    // we make sure all the lines previous to the lines the transaction affects
    // get copied over from pre to post.
    while (hasTransaction()) {
      Transaction transaction = readTransaction();
      appendPreLinesToPost(transaction.getPreStart());
      transaction.execute();
      iPreLine = transaction.getPreEnd() + 1;
    }

    // We also want to copy any lines after the last transaction left off up
    // to the end of the file.
    appendPreLinesToPost(pre.size());
  }

  /*
   Determines whether the patch contains another transaction to process. If
   there are any unvisited lines in the patch, we have more transactions.
   */
  private boolean hasTransaction() {
    return iPatchLine < patch.size();
  }

  /*
   Appends lines from pre to post.
   */
  private void appendPreLinesToPost(int to) {
    for (; iPreLine < to; ++iPreLine) {
      post.add(pre.get(iPreLine));
    }
  }

  /*
   Gets the next transaction that is to be executed. It does not execute the
   transaction. It does not advance iPatchLine.
   */
  private Transaction readTransaction() {
    Matcher matcher = TRANSACTION_PATTERN.matcher(patch.get(iPatchLine));

    if (!matcher.find()) {
      throw new RuntimeException("Bad transaction type");
    }

    Transaction transaction;
    String command = matcher.group(3);
    if (command.equals("a")) {
      transaction = new AppendTransaction();
    } else if (command.equals("c")) {
      transaction = new ChangeTransaction();
    } else {
      transaction = new DeleteTransaction();
    }

    int preStart = Integer.parseInt(matcher.group(1)) - 1;
    int preEnd = matcher.group(2) == null ? preStart : Integer.parseInt(matcher.group(2)) - 1;
    int postStart = Integer.parseInt(matcher.group(4)) - 1;
    int postEnd = matcher.group(5) == null ? postStart : Integer.parseInt(matcher.group(5)) - 1;
    transaction.setBounds(preStart, preEnd, postStart, postEnd);

    return transaction;
  }

  /*
   Represents a transaction, which turns ranges of lines in pre to ranges of
   lines in post.
   */
  private abstract class Transaction {
    public int preStart;
    public int preEnd;
    public int postStart;
    public int postEnd;

    public void setBounds(int preStart, int preEnd, int postStart, int postEnd) {
      this.preStart = preStart;
      this.preEnd = preEnd;
      this.postStart = postStart;
      this.postEnd = postEnd;
    }

    public int getPreStart() {
      return preStart;
    }

    public int getPreEnd() {
      return preEnd;
    }

    /*
     Executes this transaction and puts the patch line cursor at the start of
     the next transaction. After this method, we are ready to read the next
     transaction from the patch.
     */
    public abstract void execute();
  }

  /*
   Changes the specified pre lines into the specified post lines. A change
   transaction has the following representation in the patch:

     9c7,8
     < first line replace
     ---
     > first line to insert
     > second line to insert
   */
  private class ChangeTransaction extends Transaction {
    public void execute() {
      // Move past the transaction header, the pre lines on the chopping block,
      // and the --- separator.
      iPatchLine += (preEnd - preStart + 1) + 2;

      // Read each line to append from the patch, removing the leading "> ",
      // and insert the line into post.
      for (int i = postStart; i <= postEnd; ++i) {
        post.add(patch.get(iPatchLine).substring(2));
        ++iPatchLine;
      }
    }
  }

  /*
   Appends the enumerated lines into post. An append transaction has the
   following representation in the patch:

     9a10,11                                                                                                                            
     > first line to append
     > second line to append
   */
  private class AppendTransaction extends Transaction {
    public void execute() {
      // Move past the transaction header line.
      ++iPatchLine;

      // The transaction is responsible for dealing with pre lines in
      // [preStart, preEnd]. On append, only one pre line is in this range,
      // which we simply copy over.
      appendPreLinesToPost(preStart + 1);

      // Read each line to append from the patch, removing the leading "> ",
      // and insert the line into post.
      for (int i = postStart; i <= postEnd; ++i) {
        post.add(patch.get(iPatchLine).substring(2));
        ++iPatchLine;
      }
    }
  }

  /*
   Advances past all the deleted pre lines in this transaction in the patch.
   We don't really need to do anything more, since the lines in this
   transaction are not to appear in post.

   A delete transaction that removes two lines has this representation in the
   patch:

     1,2d0
     < first line to be removed
     < second line to be removed

   We move past the transaction line and the two pre lines, so that the next
   thing we read will be the transaction line.
   */
  private class DeleteTransaction extends Transaction {
    public void execute() {
      iPatchLine += (preEnd - preStart + 1) + 1;
    }
  }
}

My primary goal was to keep the methods short. It didn’t really make sense to create a stateful object, since Patcher has no meaningful lifespan. Thus, I wanted a static method. The code was too long for a single static method. Breaking it up meant passing a bunch of parameters around to the helper methods, and that didn’t sound fun. The solution was to make all instance-related tasks private. That way I could safely store the “global” data in instance variables that I didn’t have to pass around. (This is safe because I’m the only that can alter the Patcher instance I create.) I’m not sure I like the design, but it does have minimal conditional statements and the methods are pretty short. They’re not really individually testable.

]]>
https://twodee.org/blog/7914/feed 0
Capturing snapshots of a text file in Vim https://twodee.org/blog/3684 https://twodee.org/blog/3684#comments Fri, 01 Jun 2012 21:02:00 +0000
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
http://www.twodee.org/blog/?p=3684 [...]]]> To make a movie of textual development, I need a way to capture edits to a text file. Capturing needs to be done automatically and transparently; the developer shouldn’t have to trigger them. Otherwise, he’d forget.

My initial thoughts were to intercept every keystroke and record the changes elsewhere on disk. I didn’t really like this idea, given the extreme number of snapshots it would produce, so I went searching for something better. It turns out that the Vim editor recognizes a couple of events, CursorHold and CursorHoldI, that are triggered when the cursor stops moving. Moving cursors are a little different than text changes, but the location of the cursor is probably something I also want to track in the text movie. With Vim’s autocommands, I can register an event handler for these two events.

The following function, when called on a file named foo, starts listening for these CursorHold events. When the first is fired, the current text is written to foo00…0. The next to foo00…1. The next to foo00…2. They’ll be processed into a text movie later.

function! StartKeystrokes()
  " CursorHold* events are fired when the user doesn't move the cursor
  " for updatetime milliseconds.
  set updatetime=500

  " We're going to keep a counter for the number of events that are
  " fired. I'm sure we'll find some way to use it.
  let b:nupdates=0

  " Snapshots will be recorded to a directory. Let's put it in junk
  " so that it will automatically get wiped. Let's wipe any previous
  " session.
  let b:dir=$HOME . "/.junk/keystrokes/" . bufname("%")
  execute ":!rm -rf " . b:dir . " && mkdir -p " . b:dir

  " Attach to this buffer some event handlers. When the user stops
  " moving the cursor in either normal or insert mode, let's record
  " a snapshot out to disk.
  autocmd CursorHold,CursorHoldI <buffer>
  \ let b:nupdates=b:nupdates + 1|
  \ execute printf('write! %s/%s%010d', b:dir, bufname("%"), b:nupdates)
endfunction
]]>
https://twodee.org/blog/3684/feed 1
Making a jQuery slider do something https://twodee.org/blog/3676 https://twodee.org/blog/3676#respond Fri, 01 Jun 2012 20:46:44 +0000
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
http://www.twodee.org/blog/?p=3676 [...]]]> Getting a slider to display was the first step. The end goal is to make the slider scrub through a series of snapshots of a text file. In between, let’s just figure out how to map the tick to a timestep.

jQuery sliders are discrete; they can only be scrubbed to integral positions. Since the text movies they are scrubbing through may be 100, 103.5, 15.7, etc., second longs, I must range map the slider’s tick position (in [0, n], where n is the maximum number of ticks) to the appropriate timestep (in [0, nseconds], where nseconds is the number of seconds in the movie). I do that by finding the proportion of the current tick position to the maximal tick position, and applying that proportion to the number of seconds.

I make the maximal number of ticks a large number to provide a good number of reachable timesteps. If n was only 10, for example, the slider would only let the user access 10 different timesteps. For a 3 hour text movie, that’s not very helpful.

Here’s the script I ended up with:

When embedded in the page, the script produces:

]]>
https://twodee.org/blog/3676/feed 0
Loading a remote file in JavaScript https://twodee.org/blog/3647 https://twodee.org/blog/3647#respond Fri, 01 Jun 2012 15:31:05 +0000
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
http://www.twodee.org/blog/?p=3647 [...]]]> Next up on my list of things I don’t know how to do is load a file in JavaScript. For now, let’s assume the file is hosted on the same server as the script. I understand that reading local files requires HTML5 and reading files from other servers can be troublesome.

jQuery has several ways to retrieve file contents: load, ajax, and get. The latter two let you specify the file type, which I found to be important. If I tried to load a JavaScript file, jQuery would automatically execute it. For my purposes, I wanted the file as plain text, which the get function lets me specify.

Here’s a test script I ended up with:

When I execute it, the file is properly embedded:

jQuery’s fun.

]]>
https://twodee.org/blog/3647/feed 0
Adding a slider into WordPress https://twodee.org/blog/3637 https://twodee.org/blog/3637#respond Fri, 01 Jun 2012 06:00:13 +0000
Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383

Deprecated: Creation of dynamic property WP_Term::$cat_ID is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 378

Deprecated: Creation of dynamic property WP_Term::$category_count is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 379

Deprecated: Creation of dynamic property WP_Term::$category_description is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 380

Deprecated: Creation of dynamic property WP_Term::$cat_name is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 381

Deprecated: Creation of dynamic property WP_Term::$category_nicename is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 382

Deprecated: Creation of dynamic property WP_Term::$category_parent is deprecated in /var/www/twodee/blog/wp-includes/category.php on line 383
http://www.twodee.org/blog/?p=3637 [...]]]> How can I get a slider in HTML? Actually, how can I get a slider in WordPress, which is slightly harder? jQuery UI provides a slider, but the jQuery that ships with WordPress was not appearing for me. I tried using the jQuery provided by Google’s CDN instead:

<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/themes/base/jquery.ui.all.css">
<?php
wp_deregister_script('jquery');
wp_register_script('jquery', "https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js", false);
wp_enqueue_script('jquery');
wp_register_script('jqueryui', "https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.13/jquery-ui.min.js", false);
wp_enqueue_script('jqueryui');
?>

There are probably later versions I could be grabbing.

Then I embedded a Javascript file into my post which created a slider div:

jQuery(function() {
  jQuery("#slider").slider({
      value: 100,
      min: 0,
      max: 500,
      step: 50,
      slide: function(event, ui) {
        // insert event-handling code here
      }
    });
});

// Add a div which will hold the slider.
document.write('<div id="slider"></div>');

This file produces the following slider:

And I’m satisfied.

]]>
https://twodee.org/blog/3637/feed 0