Want to read Slashdot from your mobile device? Point it at m.slashdot.org and keep reading!

 



Forgot your password?
typodupeerror
×

Comment Re:BitCoin has complete record of transactions. (Score 4, Informative) 115

You're close. There's no difficulty decoding the blockchain. The transactions are a public ledger. Have a look: https://blockchain.info/tree/1...

It's not anonymous - it's pseudonymous. Your address is your pseudonym. It can be linked to you in many ways:

When you buy something the seller knows who you are (they have your mailing address, your IP address, etc), and they know your Bitcoin address (the transaction is public information). Anyone watching your address will also see the transaction. If the address you sent coins to is a known address the investigator can then go to that seller and request your identity (via subpoena, violence, bribery, etc).

When you transmit the transaction it's first received by a few network nodes. If the investigator is running one of those nodes they see your IP. They won't know for certain it's you (perhaps you were just relaying a transaction), but it's still a short list to check. If it's the NSA or anyone else who can monitor your internet connection directly, they can easily discover that the transaction originated from you because no one sent it to you first.

People use mixing services to help obscure the origin of their coins. It makes it harder, but it's still possible to perform statistical analysis. For a simple example: https://blockchain.info/taint/... . The investigator can find some addresses which correlate with yours. Even if they don't find YOU they might find someone you do business with, then coerce them into giving up your identity.

It's a lot like cash. You can pass it around freely, but every dollar bill has a serial number. You can spend it with relative anonymity, but it will be scanned whenever it passes through a bank. If someone is looking for certain serial numbers then they can easily find the bank your merchant uses; then stake out the merchant; then find you.

Comment Re:Geeqie (Score 2) 243

+1. The reason: it has a fuzzy-matching dedupe feature. It'll crawl all your images, then show them grouped by similarity and let you choose which ones to delete. It seems to do a pretty good job with recompressed or slightly cropped images.

Open it up, right click a directory, Find Duplicates Recursive.

fdupes is also good to weed out the bit-for-bit identical files first.

Comment Re:Errors in Paper (Score 4, Informative) 203

The correct date is approximately 2140 AD. The reward per block started at 50 BTC and is cut in half every 210,000 blocks, which nominally takes about 4 years. After ~130 years you have done 33 halvings, so the reward is 50 / (2^33) = 0.58 Satoshi, where 100 million Satoshi = 1 bitcoin. Since the smallest unit in the bitcoin transaction system is 1 Satoshi, the reward becomes too small to measure, and thus mining for new coins stops.

This is closer but still incorrect. All accounting in Bitcoin is performed with integer arithmetic. The reward per block started at 5,000,000,000 satoshis and is right shifted by one bit every 210,000 blocks. The reward does not become too small to measure - it becomes precisely zero.

Comment Re:JSON (Score 1) 112

It doesn't require all those extras brackets and braces and quotes.

My point is all those extra brackets, braces, and quotes (and field labels) don't cost you much. They compress efficiently.

JSON is like any hammer. Sometimes you gotta know when it's time to put it down and pick up the screwdriver instead.

No argument there - JSON isn't my only tool. :) I just disagree that it "fails hard when you want to send 1,000s of records".

Comment Re:JSON (Score 1) 112

Sending 1,000 copies of that is going to take a lot more packets than a fixed binary format where you can pack the entire thing down to 9 bytes e.g. 8 bytes for the Id, and both bools into a bitset on the last byte.

That's why you compress the stream. HTTP supports Content-Encoding: gzip, or you can wrap it around your file format on disk. Here's what happens with your example:

user@host:~$ ruby <<EOF | gzip | wc -c
prng = Random.new
1000.times do |i|
    puts <<EOR
{
            CustomerId: "#{prng.bytes(8).unpack('H*').first}",
            AllowExtendedConfiguation: "#{prng.rand(2).zero? ? 'true' : 'false'}",
            IsMaximumLengthRequired: "#{prng.rand(2).zero? ? 'true' : 'false'}"
},
EOR
end
EOF
12550

12550 bytes... 12.5 bytes per record, instead of your hand-optimized 9 bytes per record. I'm only paying a 28% premium with 100% random data. When it contains text strings (and we're talking about Wave here - it's mostly text) it's quite common for gzipped JSON to be smaller than an optimized but uncompressed binary format.

This frequently happens even with raw numbers. You won't have 4 billion customers for a while, so let's make the first four bytes of the CustomerId all zeroes:

CustomerId: "00000000#{prng.bytes(4).unpack('H*').first}",

I now have 7.5 bytes per record. I'm already doing better than your binary format, unless you plan to do variable length encoding on the customer ID. That'd be even more code you have to write and debug.

There are certainly cases where shaving off the last few bytes might be worthwhile, but for the general internet, and for the kind of uses that Wave is meant for... no. The simpler code (not inventing a new serialization format) and debugging advantages of human-readable streams outweigh the marginal bandwidth savings of a binary protocol.

Comment Re:Trendy no more? (Score 4, Informative) 65

I've used both a fair bit. They are similar in many ways so it's mostly a matter of preference.

I've found Ruby makes it easy to explore objects and see what can be done with them. The consistent OO model makes it easy to perform concise data manipulation. Here's a quick example:


irb(main):001:0> arr = ["1", "2", "3", "4"]
=> ["1", "2", "3", "4"]
irb(main):002:0> arr.methods - Object.methods
=> [:to_a, :to_ary, :[], :[]=, :at, :fetch, :first, :last, :concat, :>>, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :bsearch, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :lazy]
irb(main):003:0> arr.pop
=> "4"
irb(main):004:0> arr.join
=> "123"
irb(main):005:0> arr.map { |i| i.to_i }
=> [1, 2, 3]
irb(main):006:0> arr.map(&:to_i).reduce(&:+)
=> 6

Here's the same thing in Python:


In [1]: arr = ["1", "2", "3", "4"]

In [2]: dir(arr)
Out[2]:
[(stuff removed, fucking lameness filter) 'append', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

In [3]: arr.pop()
Out[3]: '4'

OK, it's pretty similar so far, but then we want to join the array. OO came late to Python, so while some things are implemented as methods on the array, a lot of things are functions which operate on an array. As such, they don't appear on the list above. Bizarrely, it's a method on string acting as a function on an array:


In [4]: "".join(arr)
Out[4]: '123'

Perhaps that's intuitive to someone, but to me, they took join which is a natural thing to do to an array and put it somewhere else so I had to look it up in the docs.

The list comprehension handles the simple mapping okay:


In [5]: [int(i) for i in arr]
Out[5]: [1, 2, 3]

But the map-reduce example gets messy:


In [6]: reduce(lambda x, y: x+y, map(int, arr), 0)
Out[6]: 6

Speaking of lambdas, Ruby makes this convenient:


irb(main):001:0> def retry_loop(tries)
irb(main):002:1> yield
irb(main):003:1> rescue
irb(main):004:1> retry if (tries -= 1) > 0
irb(main):005:1> end
=> nil
irb(main):006:0> retry_loop(3) { puts "failing"; raise }
failing
failing
failing
=> nil
irb(main):007:0> retry_loop(3) { puts "succeeding" }
succeeding
=> nil

Doing this in Python is miserable: http://code.activestate.com/recipes/578163-retry-loop/

Another difference is namespacing. Ruby imports libraries as classes or extensions to classes. Python imports them selectively into the global namespace. Python's finer grained control helps mitigate the collisions this causes, but it means that every Python script has to start with a long list of imports. Ruby can include a lot by default because all the additions are neatly contained in a class.

Python's docs are verbose and comprehensive, like a full manual. Ruby's docs tend to be concise and somewhat incomplete, like a reference guide. Take a read through these and see how long it takes you to figure out how to simply start a thread in each language:
http://docs.python.org/3/library/threading.html
http://www.ruby-doc.org/core-2.1.0/Thread.html

Both styles have their place, but I like that I can get the reference guide by just googling a feature. Python doesn't really have the short form. On the other hand, the full manual for Ruby will set you back $28: http://pragprog.com/book/ruby4/programming-ruby-1-9-2-0

Python has a thing: "There should be one -- and preferably only one -- obvious way to do it". This is a good philosophy to keep the language clean, but sometimes it means they don't provide some functionality since it's supposed to be obvious how to do it yourself. And thus, it's self-defeating: http://tomayko.com/writings/cleanest-python-find-in-list-function . In Ruby, it's simple:


irb(main):007:0> arr.grep(/[12]/)
=> ["1", "2"]
irb(main):008:0> arr.grep(/[12]/).first
=> "1"

And having simple things BE simple makes it really easy to go exploring. Hey look, here are all the methods on an array which return a boolean, or which cast it to another class:


irb(main):014:0> arr.methods.grep(/\?/)
=> [:frozen?, :eql?, :empty?, :include?, :all?, :any?, :one?, :none?, :member?, :nil?, :tainted?, :untrusted?, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :respond_to?, :equal?]
irb(main):015:0> arr.methods.grep(/to_/)
=> [:to_s, :to_a, :to_ary, :psych_to_yaml, :to_yaml, :to_yaml_properties, :to_enum]

I could go on, but perhaps this gives you some idea. I'm focusing a lot on where I think Ruby has things right (since you asked), but they're both well designed languages with many similarities. Ruby is a carefully self-consistent language which encourages concise but semantic style. Python is an evolved and quite complete language which encourages verbose but readable style.

I personally find Ruby cleaner, easier to navigate, and more intuitive, and the docs are easier to read. For me that makes it faster, more fun, and less frustrating. YMMV.

Comment Re:The thousand words I saw (Score 4, Informative) 65

TFA describes it in a way that makes sense even if it's technically inaccurate:

The water drops are so tiny they don't have any moisture in them; you can test it on paper or your glasses -- your piece of paper will remain dry and your glasses won't steam up.

More accurately: The water drops are so tiny they won't moisten things they contact.

... let's call a recess and re-convene when that statement makes sense, shall we?

You may now resume bashing the gizmo for being inadequate instead of the submitter for being incomprehensible or the editors for being incompetent.

Slashdot Top Deals

Solutions are obvious if one only has the optical power to observe them over the horizon. -- K.A. Arsdall

Working...