{"action":"created","comment":{"url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/comments/59253394","id":59253394,"diff_hunk":"@@ -0,0 +1,130 @@\n+require 'filewatch/boot_setup' unless defined?(FileWatch)\n+\n+module FileWatch\n+  class Fingerprinter\n+    attr_reader :data, :fnv, :fingerprint, :offset, :size\n+\n+    def initialize(path, offset)\n+      @path = path\n+      @offset = offset\n+      @size = FP_BYTE_SIZE\n+    end\n+\n+    def match_any?(keys)\n+      if @fnv.nil?\n+        # STDERR.puts \"Fingerprinter: fnv nil for path - #{path}\"\n+        return nil\n+      end\n+      if @data.nil?\n+        # STDERR.puts \"Fingerprinter: data nil for path - #{path}\"\n+        return nil\n+      end\n+      keys.each do |k|\n+        fp, off, len = *k\n+        # STDERR.puts \"Fingerprinter: any_match? - #{fp}:#{off}:#{len}\"\n+        if off != @offset\n+          # STDERR.puts \"Fingerprinter: any_match? - wrong offset, mine is: #{@offset}\"\n+          next\n+        end\n+        possible = @fnv.fnv1a64(len)\n+        if fp == possible\n+          @fingerprint, @size = fp, len\n+          return k\n+        end\n+      end\n+      # STDERR.puts \"Fingerprinter: no match - #{keys.inspect}\"\n+      nil\n+    end\n+\n+    def add_size(size)\n+      if @fnv\n+        fnv_fingerprint(size)\n+      end\n+      self\n+    end\n+\n+    def add_data(data)\n+      @data = data\n+      set_fnv\n+      self\n+    end\n+\n+    def read_path\n+      begin\n+        file = FileOpener.open(@path)\n+        set_fingerprint(file)\n+      ensure\n+        file.close\n+      end\n+      self\n+    end\n+\n+    def read_file(file)\n+      set_fingerprint(file)\n+      self\n+    end\n+\n+    def ==(other)\n+      size == other.size && offset == other.offset && fingerprint == other.fingerprint\n+    end\n+\n+    def data_size\n+      return 0 if @data.nil?\n+      @data.size\n+    end\n+\n+    def to_a\n+      [@fingerprint, @offset, @size]\n+    end\n+\n+    def to_io\n+      StringIO.new(@data)\n+    end\n+\n+    def clear\n+      @data = @fnv = nil\n+    end\n+\n+    def end_position\n+      @offset + @size\n+    end\n+\n+    def fingerprint_at(len)\n+      @fnv.fnv1a64(len)\n+    end\n+\n+    def starts_eql?(other)\n+      return false if offset != other.offset\n+      if size > other.size\n+        return fingerprint_at(other.size) == other.fingerprint\n+      end\n+      if other.size > size\n+        return other.fingerprint_at(size) == fingerprint\n+      end\n+      other.fingerprint == fingerprint\n+    end\n+\n+    private\n+\n+    def set_fingerprint(file)\n+      file.sysseek(@offset, IO::SEEK_SET)\n+      @data = file.sysread(FP_BYTE_SIZE)\n+      set_fnv\n+    end\n+\n+    def set_fnv\n+      @fnv = Fnv.new(@data)\n+      fnv_fingerprint(@size)\n+    end\n+\n+    def fnv_fingerprint(size)\n+      if size && size < FP_BYTE_SIZE && size < data_size","path":"lib/filewatch/fingerprinter.rb","position":121,"original_position":121,"commit_id":"9a27bc6935aa55790bf3a585b2c4656c4809c2e8","original_commit_id":"9a27bc6935aa55790bf3a585b2c4656c4809c2e8","user":{"login":"ph","id":640,"avatar_url":"https://avatars.githubusercontent.com/u/640?v=3","gravatar_id":"","url":"https://api.github.com/users/ph","html_url":"https://github.com/ph","followers_url":"https://api.github.com/users/ph/followers","following_url":"https://api.github.com/users/ph/following{/other_user}","gists_url":"https://api.github.com/users/ph/gists{/gist_id}","starred_url":"https://api.github.com/users/ph/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ph/subscriptions","organizations_url":"https://api.github.com/users/ph/orgs","repos_url":"https://api.github.com/users/ph/repos","events_url":"https://api.github.com/users/ph/events{/privacy}","received_events_url":"https://api.github.com/users/ph/received_events","type":"User","site_admin":false},"body":"You are right, this is not easy logic, lest add documentation to it.","created_at":"2016-04-11T18:13:01Z","updated_at":"2016-04-11T18:13:01Z","html_url":"https://github.com/jordansissel/ruby-filewatch/pull/79#discussion_r59253394","pull_request_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79","_links":{"self":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/comments/59253394"},"html":{"href":"https://github.com/jordansissel/ruby-filewatch/pull/79#discussion_r59253394"},"pull_request":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79"}}},"pull_request":{"url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79","id":62790466,"html_url":"https://github.com/jordansissel/ruby-filewatch/pull/79","diff_url":"https://github.com/jordansissel/ruby-filewatch/pull/79.diff","patch_url":"https://github.com/jordansissel/ruby-filewatch/pull/79.patch","issue_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues/79","number":79,"state":"open","locked":false,"title":"Add versioned sincedb upgrade; use fingerprints instead of inode and/or path","user":{"login":"guyboertje","id":84912,"avatar_url":"https://avatars.githubusercontent.com/u/84912?v=3","gravatar_id":"","url":"https://api.github.com/users/guyboertje","html_url":"https://github.com/guyboertje","followers_url":"https://api.github.com/users/guyboertje/followers","following_url":"https://api.github.com/users/guyboertje/following{/other_user}","gists_url":"https://api.github.com/users/guyboertje/gists{/gist_id}","starred_url":"https://api.github.com/users/guyboertje/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guyboertje/subscriptions","organizations_url":"https://api.github.com/users/guyboertje/orgs","repos_url":"https://api.github.com/users/guyboertje/repos","events_url":"https://api.github.com/users/guyboertje/events{/privacy}","received_events_url":"https://api.github.com/users/guyboertje/received_events","type":"User","site_admin":false},"body":"","created_at":"2016-03-14T17:57:11Z","updated_at":"2016-04-11T18:13:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"5e5b9798043785c3aedd2420fb016595f217ed67","assignee":{"login":"jordansissel","id":131818,"avatar_url":"https://avatars.githubusercontent.com/u/131818?v=3","gravatar_id":"","url":"https://api.github.com/users/jordansissel","html_url":"https://github.com/jordansissel","followers_url":"https://api.github.com/users/jordansissel/followers","following_url":"https://api.github.com/users/jordansissel/following{/other_user}","gists_url":"https://api.github.com/users/jordansissel/gists{/gist_id}","starred_url":"https://api.github.com/users/jordansissel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jordansissel/subscriptions","organizations_url":"https://api.github.com/users/jordansissel/orgs","repos_url":"https://api.github.com/users/jordansissel/repos","events_url":"https://api.github.com/users/jordansissel/events{/privacy}","received_events_url":"https://api.github.com/users/jordansissel/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79/commits","review_comments_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79/comments","review_comment_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/comments{/number}","comments_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues/79/comments","statuses_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/statuses/9a27bc6935aa55790bf3a585b2c4656c4809c2e8","head":{"label":"guyboertje:fix-sincedb","ref":"fix-sincedb","sha":"9a27bc6935aa55790bf3a585b2c4656c4809c2e8","user":{"login":"guyboertje","id":84912,"avatar_url":"https://avatars.githubusercontent.com/u/84912?v=3","gravatar_id":"","url":"https://api.github.com/users/guyboertje","html_url":"https://github.com/guyboertje","followers_url":"https://api.github.com/users/guyboertje/followers","following_url":"https://api.github.com/users/guyboertje/following{/other_user}","gists_url":"https://api.github.com/users/guyboertje/gists{/gist_id}","starred_url":"https://api.github.com/users/guyboertje/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guyboertje/subscriptions","organizations_url":"https://api.github.com/users/guyboertje/orgs","repos_url":"https://api.github.com/users/guyboertje/repos","events_url":"https://api.github.com/users/guyboertje/events{/privacy}","received_events_url":"https://api.github.com/users/guyboertje/received_events","type":"User","site_admin":false},"repo":{"id":46736131,"name":"ruby-filewatch","full_name":"guyboertje/ruby-filewatch","owner":{"login":"guyboertje","id":84912,"avatar_url":"https://avatars.githubusercontent.com/u/84912?v=3","gravatar_id":"","url":"https://api.github.com/users/guyboertje","html_url":"https://github.com/guyboertje","followers_url":"https://api.github.com/users/guyboertje/followers","following_url":"https://api.github.com/users/guyboertje/following{/other_user}","gists_url":"https://api.github.com/users/guyboertje/gists{/gist_id}","starred_url":"https://api.github.com/users/guyboertje/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/guyboertje/subscriptions","organizations_url":"https://api.github.com/users/guyboertje/orgs","repos_url":"https://api.github.com/users/guyboertje/repos","events_url":"https://api.github.com/users/guyboertje/events{/privacy}","received_events_url":"https://api.github.com/users/guyboertje/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/guyboertje/ruby-filewatch","description":"ruby api for file watching and tailing.","fork":true,"url":"https://api.github.com/repos/guyboertje/ruby-filewatch","forks_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/forks","keys_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/teams","hooks_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/hooks","issue_events_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/issues/events{/number}","events_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/events","assignees_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/assignees{/user}","branches_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/branches{/branch}","tags_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/tags","blobs_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/git/refs{/sha}","trees_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/statuses/{sha}","languages_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/languages","stargazers_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/stargazers","contributors_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/contributors","subscribers_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/subscribers","subscription_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/subscription","commits_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/commits{/sha}","git_commits_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/git/commits{/sha}","comments_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/comments{/number}","issue_comment_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/issues/comments{/number}","contents_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/contents/{+path}","compare_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/merges","archive_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/downloads","issues_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/issues{/number}","pulls_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/pulls{/number}","milestones_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/milestones{/number}","notifications_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/labels{/name}","releases_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/releases{/id}","deployments_url":"https://api.github.com/repos/guyboertje/ruby-filewatch/deployments","created_at":"2015-11-23T17:18:10Z","updated_at":"2016-01-27T20:03:12Z","pushed_at":"2016-04-04T17:46:54Z","git_url":"git://github.com/guyboertje/ruby-filewatch.git","ssh_url":"git@github.com:guyboertje/ruby-filewatch.git","clone_url":"https://github.com/guyboertje/ruby-filewatch.git","svn_url":"https://github.com/guyboertje/ruby-filewatch","homepage":"","size":483,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"jordansissel:master","ref":"master","sha":"703862a76f90789bb1d8f8b94bc4fe62feea4e35","user":{"login":"jordansissel","id":131818,"avatar_url":"https://avatars.githubusercontent.com/u/131818?v=3","gravatar_id":"","url":"https://api.github.com/users/jordansissel","html_url":"https://github.com/jordansissel","followers_url":"https://api.github.com/users/jordansissel/followers","following_url":"https://api.github.com/users/jordansissel/following{/other_user}","gists_url":"https://api.github.com/users/jordansissel/gists{/gist_id}","starred_url":"https://api.github.com/users/jordansissel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jordansissel/subscriptions","organizations_url":"https://api.github.com/users/jordansissel/orgs","repos_url":"https://api.github.com/users/jordansissel/repos","events_url":"https://api.github.com/users/jordansissel/events{/privacy}","received_events_url":"https://api.github.com/users/jordansissel/received_events","type":"User","site_admin":false},"repo":{"id":1442359,"name":"ruby-filewatch","full_name":"jordansissel/ruby-filewatch","owner":{"login":"jordansissel","id":131818,"avatar_url":"https://avatars.githubusercontent.com/u/131818?v=3","gravatar_id":"","url":"https://api.github.com/users/jordansissel","html_url":"https://github.com/jordansissel","followers_url":"https://api.github.com/users/jordansissel/followers","following_url":"https://api.github.com/users/jordansissel/following{/other_user}","gists_url":"https://api.github.com/users/jordansissel/gists{/gist_id}","starred_url":"https://api.github.com/users/jordansissel/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jordansissel/subscriptions","organizations_url":"https://api.github.com/users/jordansissel/orgs","repos_url":"https://api.github.com/users/jordansissel/repos","events_url":"https://api.github.com/users/jordansissel/events{/privacy}","received_events_url":"https://api.github.com/users/jordansissel/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jordansissel/ruby-filewatch","description":"ruby api for file watching and tailing.","fork":false,"url":"https://api.github.com/repos/jordansissel/ruby-filewatch","forks_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/forks","keys_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/teams","hooks_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/hooks","issue_events_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues/events{/number}","events_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/events","assignees_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/assignees{/user}","branches_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/branches{/branch}","tags_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/tags","blobs_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/git/refs{/sha}","trees_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/statuses/{sha}","languages_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/languages","stargazers_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/stargazers","contributors_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/contributors","subscribers_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/subscribers","subscription_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/subscription","commits_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/commits{/sha}","git_commits_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/git/commits{/sha}","comments_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/comments{/number}","issue_comment_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues/comments{/number}","contents_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/contents/{+path}","compare_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/merges","archive_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/downloads","issues_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues{/number}","pulls_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls{/number}","milestones_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/milestones{/number}","notifications_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/labels{/name}","releases_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/releases{/id}","deployments_url":"https://api.github.com/repos/jordansissel/ruby-filewatch/deployments","created_at":"2011-03-05T05:57:20Z","updated_at":"2016-01-15T21:40:31Z","pushed_at":"2016-04-04T17:46:54Z","git_url":"git://github.com/jordansissel/ruby-filewatch.git","ssh_url":"git@github.com:jordansissel/ruby-filewatch.git","clone_url":"https://github.com/jordansissel/ruby-filewatch.git","svn_url":"https://github.com/jordansissel/ruby-filewatch","homepage":"","size":383,"stargazers_count":68,"watchers_count":68,"language":"Ruby","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":52,"mirror_url":null,"open_issues_count":20,"forks":52,"open_issues":20,"watchers":68,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79"},"html":{"href":"https://github.com/jordansissel/ruby-filewatch/pull/79"},"issue":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues/79"},"comments":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/issues/79/comments"},"review_comments":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79/comments"},"review_comment":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/pulls/79/commits"},"statuses":{"href":"https://api.github.com/repos/jordansissel/ruby-filewatch/statuses/9a27bc6935aa55790bf3a585b2c4656c4809c2e8"}}}}