College students are increasingly demanding protection from words and ideas they don’t like. Here’s why that’s disastrous for education.

Kiana Khansmith

if i look back, i am lost

祝日 / Permanent Vacation

tannertan36
occasionally subtle
Peter Solarz

Love Begins
Misplaced Lens Cap
tumblr dot com
he wasn't even looking at me and he found me

oozey mess
YOU ARE THE REASON

blake kathryn
we're not kids anymore.

@theartofmadeline
Today's Document
Jules of Nature
RMH

pixel skylines
Sweet Seals For You, Always

seen from Germany
seen from Greece
seen from United States

seen from Malaysia
seen from United Kingdom

seen from Portugal

seen from United Kingdom

seen from Türkiye

seen from United States
seen from Netherlands

seen from Malaysia
seen from Germany
seen from Portugal
seen from United States

seen from Singapore

seen from Romania

seen from Malaysia
seen from United States

seen from China
seen from France
@ryankelley
College students are increasingly demanding protection from words and ideas they don’t like. Here’s why that’s disastrous for education.
Stephen Moore and Arthur Laffer's over-the-top enthusiasm for Trump's sketchy economic agenda is not likely to convince anyone not already sporting a "Make America Great Again" hat.
I really had high hopes for Trump's economic policy. Early on, I felt we needed some protectionist measures and some gutting of our governments profligate spending--particularly by the DoD. Some good things are happening according to indicators of employment and wages. But honestly, my working-class family is now paying more taxes than before, and I suspect this market growth is largely short-sighted gorging, PR-fueled and wishful thinking. Of course rah-rah nationalism is going to draw some positive speculation and investment, but it's not real growth.
Eventually the chickens will come home to roost. Our R&D funding is decelerating and becoming more centralized. We're trapping more money at the top, increasing inequality, continually squeezing dwindling natural resources without incentivizing environmentally-sustainable technology development. Trickle-down economics has its merits. It's wise to make rich people and business owners comfortable so they store money in your banks and invest more capital your nation. Unfortunately, we haven't done that. We've made them richer at the expense of the working class while they've continued to move their funds overseas into more liberalized nations. We gave their corporations control over markets like airlines, telecommunications, health insurance, bankings--eliminating competition and creating ineffeciencies.
What we should be doing is cutting taxes for the working-class. They actually take their savings and reinvest large portions of it into the local economy--via openning new businesses, purchasing more goods and services etc...One thing the working class does is work--so it makes sense that putting extra money in their pocket will result in extra money being reinvested into the economy.
The working class is the most productive segment of the economy per dollar. Unfortunately, they're already loyal tax payers, so the bureaucrats and crony businesses don't need to focus on them when campaigning. Instead, they offer sops of bread to the poor masses in order to get their policy across. This is why inner cities have stayed poor despite being dominated by leftists over the last 40 years, and why the welfare state is so inefficient. The aim is to pacify their desperation with some small gift in the short term, like a needle exchange or more money into a bad public school. In return, the leftist demagogue gets their vote and passes more policy funneling money into the businesses they're affiliated with. Wall Street loved Hillary, not Trump.
Thus, we've actually squeezed the working class more in recent years. While some tax cuts and some positive PR has led to economic growth and higher wages, it hasn't done so in a sustainable fashion. Furthermore, middle-class homeowners are now enjoying less tax cuts under Trump, the Drug War is now being waged against veterans wrought with chronic pain and health insurance has increasing per capita. Illegal immigration persists, and there's now policy on the ballot proposing that felons and illegal aliens will vote. Meaning, net resource takers will be given more power vis a viz tax-paying citizens. The middle class will effectively pay more for the same amount of public goods they received before under this policy. While this policy comes from the left, I suspect it is here because the left has been inflamed in hysteria over Trump's rhetoric. After all, every action has a reaction. The left is only becoming more radical and desperate with every loss. The cyclical nature of politics and economy leads me to believe the next president will be a democrat.
My ballot was red in Florida, but honestly, I regretted watching Rick Scott shut down sewage treatment plants, pollute the everglades and Tampa Bay, and drill offshore...He traded some short-term growth for long-term economic health--also sacrificed the beauty of the area. This is the typical conservative policy prescription. Keep doing what you're doing until it stops working. Well, it's going to stop working--we're overpopulated, our natural resource stores are quickly dwindling and the earth is telling us we're in trouble with a more extreme climate. Worse, it's economically irrational to trade tourism—e.g. clean beaches--and real estate—e.g. clean water and fertile land--for his friends at the oil companies. Tourism and real estate, most likely, are sectors that have far more growth potential and offer long-term stability in a state like Florida. Jeopardizing these sectors along with commercial fisheries to drill off shore is unlikely to be a net gain.
Unfortunately, I just didn't see any more promising options on the left side of the ballot. Frankly, I'm not surprised. That side has become the anti-science side. They're waging a war against the entire field of economics. They feel bought, and in every policy prescription are attempting to take away our individual freedoms. They want our right to self-defense, they want our free speech, they want our free markets and they want control over our critical goods--safety, telecommunications, water, arable land...Simply put, while the right may be misguided, the left has become dangerous to the citizen's future. I work in STEM, and I worked very hard to get there. I got a degree in economics (hard!) and I have spent the last 6 years working tirelessly as a software engineer (hard!). In response to the high wage I"ve earned while their voters chose easy, liberal arts degrees that have a poor return in the work force, they're forcing policy that funnels STEM jobs away from me and towards less-qualified people because of their race or gender. 51% of the US population is female--the law of supply and demand means my wage will fall if we're hiring less-qualified women just because they're women. And can I speak out? No. They're the party against free speech--they despise so-called "Hate Speech". In essence, they despise any non-polite speech, and therefore, free speech. Their rhetoric increasingly aligns with authoritarian police states that have total control over the populace.
Because they suffered a loss, the left is becoming more tyrannical. Essentially, anyone they can draw votes from they want voting. Most recently, they started pushing policy to allow felons and non-citizens to vote in elections. I saw this on my ballot in Florida. Already, they want illegal aliens sharing public goods despite so many impoverished and homeless US citizens not having enough access to them.
Both sides have become out of touch with our nations' needs. We might've had a few sops of bread under Trump, but ultimately, the inflammatory rhetoric from his regime will undoubtedly lead to a harsh reaction in the opposite direction.
Download data from a variety of data repositories
I love Python. For fun, I just banged out a script to download data from a variety of repositories beginning with RetroSheet.org. It uses some cool libraries in Python like tqdm for adding a status bar for the data transfer and argparse for adding flags to your scripts.
import argparse, httplib2, os, re, requests, sys, time; from datetime import datetime from tqdm import tqdm parser = argparse.ArgumentParser() parser.add_argument("-s", "--season", help="numeric season", type=int) parser.add_argument("-p", "--path", help="download path") args = parser.parse_args() if args.path: DOWNLOAD_PATH = os.path.expanduser(args.path) else: DOWNLOAD_PATH = os.path.expanduser('~/Downloads') this_year = datetime.now().year dl_year = str((args.season or this_year)) dl_year_short = dl_year[-2:] ## CHECK YEAR AND ABORT IF INVALID if not dl_year.isdigit(): sys.exit(f"Invalid year {args.season}, please use digits") elif int(dl_year) < 1900 or int(dl_year) > int(this_year): sys.exit(f"Invalid year {args.season}, must be between 1900 and this year ({this_year})") ## CHECK DOWNLOAD PATH AND ABORT IF INVALID if not os.path.isdir(DOWNLOAD_PATH): sys.exit(f"Invalid path {DOWNLOAD_PATH}") def get_download_path(file_basename): return ( DOWNLOAD_PATH + "/" + (time.strftime("%Y%m%d")+"_"+file_basename) ).replace("//", "/") def check_url_exists(dl_url): r = httplib2.Http().request(dl_url, 'HEAD') return int(r[0]['status']) < 400 def download_data(url_dict, data_name): dl_path = get_download_path(data_name) pretty_name = re.sub(r"/[\-\_]/", " ", data_name) dl_url = ( url_dict['base'] + url_dict['data'][data_name] ) if not check_url_exists(dl_url): print(f"#{dl_url} does not exist, perhaps you should specify different parameters") quit() print(f"Beginning file download of {pretty_name} data from {url_dict['base']}, saving to {dl_path}...") r = requests.get(dl_url, stream=True) with open(dl_path, "wb") as handle: for data in tqdm(r.iter_content()): handle.write(data) return dl_path site_info = { 'base' : "http://www.retrosheet.org", 'data': { 'events': f"/events/{dl_year}eve.zip", 'events_decade' : f"/events/{dl_year}seve.zip", 'events_postseason' : f"/events/{dl_year}post.zip" }, 'pages' : {} } download_data(site_info, 'events')
Download projections in seperate files by position. `python steamer_multi.py '~/Downloads'`
To illustrate the benefits fundamentals of automated browsing with Selenium webdriver, I wrote a script to automatically download Steamer CSV files from Fangraphs.com.
For you Python developers, please excuse my ugly semicolon use. I've been writing a lot of Java lately and have gotten a bit OCD about my seperators and line endings.
Below is V1 and V2 of the script. V1 only downloads a single CSV file (for pitchers in this case). V2 of the script downloads both hitter and pitcher Steamer projections amd attempts to name them using a timestamp filenaming convention. You can run it with python steamer.py '~/Downloads'
import time; import os; import sys; from selenium import webdriver; from selenium.webdriver.firefox.firefox_profile import FirefoxProfile; if len(sys.argv) > 1: download_path = os.path.expanduser(sys.argv[1]); else: download_path = os.path.expanduser('~/Desktop'); if not os.path.isdir((download_path)): sys.exit('Invalid path %s.'%(download_path)); print('File will be saved to %s'%(download_path)); download_file_path = (download_path+'/Fangraphs Leaderboard.csv'); ts_file_name = (time.strftime("%Y%m%d")+"_steamer_projections.csv"); ## custom file name profile = FirefoxProfile(); profile.set_preference("browser.helperApps.neverAsk.saveToDisk", 'text/csv'); profile.set_preference("browser.download.manager.showWhenStarting", False); profile.set_preference("browser.download.dir", download_path); profile.set_preference("browser.download.folderList", 2); ## download to last location set driver = webdriver.Firefox(firefox_profile=profile); uri = "https://www.fangraphs.com/projections.aspx?pos=all&stats=bat&type=steamer&team=0&lg=all&players=0"; driver.get(uri); driver.find_element_by_link_text('Export Data').click(); ## leave browser open for 5 seconds then close time.sleep(5); driver.quit(); print('Success, file saved to %s'%(download_path)); if os.path.isfile(download_file_path): os.rename(download_file_path, ts_file_name ); print('Renamed file %s to %s'%(download_path,ts_file_name)); else: sys.exit('Error, unable to locate file at %s'%(download_path));
Here's V2:
import time; import os; import sys; from selenium import webdriver; from selenium.webdriver.firefox.firefox_profile import FirefoxProfile; import glob; # import pdb; ## debugger def get_filename(folder_before, folder_after): change = set(folder_after) - set(folder_before) if len(change) > 0: return next(iter(change)); def gen_uri(player_type='bat'): return "https://www.fangraphs.com/projections.aspx?pos=all&stats="+player_type+"&type=steamer&team=0&lg=all&players=0"; if len(sys.argv) > 1: download_path = os.path.expanduser(sys.argv[1]); else: download_path = os.path.expanduser('~/Desktop'); if not os.path.isdir((download_path)): sys.exit('Invalid path %s.'%(download_path)); print('File will be saved to %s'%(download_path)); profile = FirefoxProfile(); profile.set_preference("browser.helperApps.neverAsk.saveToDisk", 'text/csv');
A script I wrote to easily merge pdf files into one doc use CombinePDF library.
I wrote a ruby script that merges all pdf files in a specific directory together into one. Usage:
## merge_pdf /path/of/pdfs /path/to/save/to $ merge_pdf.rb /Users/me/projects/pdfs_to_combine /Users/me/projects/merged_output_folder
I made a second version of this script that will convert files if a non-pdf file type is specified. Check it out here
$ merge_pdf.rb /Users/me/projects/pdfs_to_combine /Users/me/projects/merged_output_folder .odt
The final version I made (v3), uses flags for passed parameters to be more explicit. Here's v3
$ ruby merge_pdf_v3.rb --source_directory ~/Downloads --save_directory ~/Desktop --source_file_extension odt
A Script to Remove DS_Store from your Project
.DS_Store is a hidden file placed in Mac OS/X directories that stores metadata about the display options and arrangement of its files. It's utilized by finder.app and is only applicable to viewing the file system via the GUI. If you're working on a coding project, with a group, the chances are you'll be using the command line to access this folder and you will be merging different versions of the project regularly. This makes .DS_Store metadata not useful and even an annoyance, as it will be tracked by Git by default; it will make drag-and-drop overwriting and file transfers slightly more annoying, and obviously it offers other people some data about your personal environment. That last point is probably irrelevant in the case of coding projects, but in other cases this is perhaps undesirable.
So, if you want to get rid of .DS_Store, and remove it from git tracking, you're in luck. I recently created a shell script to removed .DS_Store, and it can easily be modified to remove other files--hidden or otherwise--in an automated fashion.
#!/bin/sh if [ -f "`find . -name .DS_Store`" ] ; then if [ ! -f "`git rev-parse --is-inside-work-tree`" ] ; then echo "no git repository found" while true; do read -p "Do you wish to initialize git repository in this folder $(echo $(pwd))?" yn case $yn in [Yy]* ) git init; break;; [Nn]* ) exit;; * ) echo "Please answer yes or no.";; esac done fi if[ ! -f "`find . -name .gitignore`" ] ; then touch $(pwd)/.gitignore && echo "created .gitignore" fi echo "removing .DS_Store" find . -name .DS_Store -print0 | xargs -0 git rm git config --global core.excludesfile "$(pwd)/.gitignore" echo .DS_Store >> ~/.gitignore && echo ".DS_Store added to .gitignore" else echo ".DS_Store not found." fi
The first line is the shebang identifying the shell to use for the script; the third line (after the break) is a logical statement using the Unix find command to search the current directory for the hidden file .DS_Store. If that file is found, then it executes the code wrapped inside of the first if....fi.
As a side note, you can list all hidden files in the current directory using the ls command ls -ld .?* which will include user privelage info, or succinctly ls -A | egrep '^\.'.
The second if block checks to see if the current working directory is already a git repository. If not, it asks for user input using a while loop. The while loop will break and exit the script if the user enters no. If the user enters yes, then the case statement will run git init, which initializes the git repo in the current working directory.
Side note, you can check your current work directory with pwd. If you're asking yourself--well that is my current directory but what directory will this script use? That's a good question. By default, when you run this script, it will run all commands using the user's current working directory as a reference. Still, I made use of pwd in my scripts to explicitly illustrate that I am running the commands in the current working directory. If we wanted to change this, we could provide explicit absolute paths to each of the commands, or we could use cd to change the current working directory.
The third if block of logic conditionally creates a .gitignore file if it doesn't already exist in the working directory. Subsequently, we once again run the find command, this time to check the current directory for the .DS_Store file. If it is there, the second piece after the pipe is executed, removing it with the rm command.
The next line of code identifies the .gitignore file for git to use. That's the git config --global core.excludesfile "$(pwd)/.gitignore" portion. Then the final line inserts ".DS_Store" into .gitignore, ensuring git will not track it in the future.
I created a gist that you can view on Github.
What is Bitcoin and How Does it Work?
The following post is an introduction to Bitcoin. What is Bitcoin? How does it work? Is it a bubble? These are all great questions, and as a software developer and long-time Bitcoin enthusiast I'm happy to try to answer them.
Before you begin reading, I want to make it clear that I am neither an expert on Bitcoin, nor a financial advisor. I created this post to introduce you to something I love, something that is new and confusing to most people. I'm passing along information I have learned over the years. Please, consult actual experts and do your own research before diving into this world. After you've read my post, considering moving on to Bitcoin.org and bitcoin founder Satoshi Nakamoto's original research paper revealing his design.
In a Few Words
Bitcoin is a currency based on a transparent, distributed, decentralized ledger tracking all transactions chronologically. Similar to how Google Docs distributes documents, Bitcoin allows all parties to operate with the same information at the same time when making a transaction. This solves the asymmetric information problem that traditional fiat currencies present. For instance, the money stored in your bank account is really an IOU from the bank, and you're at their mercy when attempting to use those funds. You even have to pay them additional fees when making transactions.
What is Bitcoin and What Does It Do?
Bitcoin (BTC) is a cryptocurrency and a medium of exchange. Like traditional fiat currencies, it is a tool for transferring and storing value. Its own worth relies on how effectively it does these jobs--or at least the perception of its effectiveness by a public full of laypeople.
Unlike the USD, JPY, EUR and other fiat currencies, BTC is not printed and regulated by a central authority. It is not distributed by a government banking system. Therefore, BTC is protected--to a degree--from political corruption, insider trading and some of the reckless banking activities that have destroyed currencies (and lives) throughout history[1,2,3]. And as a cryptocurrency, it is inherently more difficult to counterfeit.
BTC's architecture removes the requirement of a private company (a.k.a. a bank) to facilitate transactions, freeing it from the fees and obstacles that accompany a profit-seeking middleman. Transferring coins between wallets can be virtually free of transaction costs, no matter what countries the owners reside in and what type of good they're dealing with. This also makes it a useful medium for remittances and international business.
One of the largest markets for BTC is in China, where businesses evade the costly regulations and corruption tied to the Yuan.
The government-controlled depreciation of the Yuan against the dollar in an attempt to gain international trade advantages. It has unsurprisingly led to an uncontrolled and unpredictable downward spiral over the past half-decade. The gloomy future and already-waning usefulness of the Yuan has fueled the demand for BTC--an inherently deflationary, totally-decentralized currency that isn't tied to any competing foreign countries. In addition to its usefulness as a currency, the poor performance of Chinese stocks, other world currencies and a recent global economic crisis has made BTC more and more tempting vis a vis the alternatives.
One of the defining properties of Bitcoin is its privacy features. While the presence of a permanent public ledger of all transactions makes true anonymity impossible, BTC provides a far greater degree of privacy than fiat currencies. Face-to-face transactions with cash money are difficult to track by outside entities, but long-distance transactions or payments over the internet require forfeiting access to your personal information, as well as information about the goods and other parties involved.
Bitcoin has emerged as the currency of choice for internet-based blackmarkets and clandestine business because it makes long-distance transactions more difficult to trace. Obviously, the ability to transfer funds without face-to-face interaction is a crucial part of the privacy equation. In addition, it offers the ability to create a wallet without personal information--unlike opening a bank account. One is also able to receive bitcoin using one-time-generated addresses, adding a layer of obfuscation that is expensive to piece together.
Supplementing the properties of bitcoin that make transactions difficult to trace, there are also techniques like cryptocurrency tumbling that add much thicker layers of obfuscation by removing one's ties to the purchase of the bitcoins being used in the deal. If BTC is purchased with cash and without an exchange (a company faciliating the trade of Bitcoin), then that also makes it more difficult to trace--as long as the individual that sells you the BTC doesn't know enough about you to rat on you later!
What is a Wallet?
A wallet is essentially Bitcoin's version of a bank account. A bank account doesn't physically store cash, and a BTC wallet doesn't physically contain BTC. Bitcoin wallets store private keys used to access your public Bitcoin addresses. Accessing these addresses on the block chain accounts for how much BTC that wallet is associated with. The private keys stored in the wallet are also used to sign transactions to verify that they are coming from your wallet and not someone elses'.
Wallets are also used to make transactions between BTC users. When a user wants to receive BTC, they generate a public key/address. This address is used by the other user to securely send bitcoins to this other wallet. The sending user, uses their own wallet's private key to sign the transaction. The addresses are often generate on a per transaction basis.
There are three primary types of wallets--software, hardware and cloud.
Software wallets are installed on your desktop or mobile device and they store the critical keys for accessing your BTC offline. These wallets typically strike the best balance between security and convenience, and they offer measures to recover your BTC if your hard drive fails.
Online/cloud wallets are wallets hosted by other companies. You're putting the security of your private keys, and access to your coins, in their hands. This type of wallet is the least secure, but the most convenient. Since it is advantageous to be able to access your wallet over the internet, I personally store small amounts of coins in my cloud wallets and larger amounts offline. This way, I can make quick transactions at BTC exchanges using my online wallet from any location I have internet access. But, I also don't have to risk losing large sums of money, as I keep the keys to the majority of my dough stored safely in my own computer.
Finally, there are hardware and even paper wallets that store the sensitive private keys offline and off of a computer's hard drive. Some argue these are most secure, but they are also definitely impractical for transactions.
Can You Lose a Wallet?
Yes. Firstly, if you forget your wallet password and you don't have a backup measure to access it, you're screwed. Secondly, if you haven't backed up your wallet and your hard drive crashes, you're screwed. If you store your coins in the cloud, they're not only more susceptible to being hacked, but they too are susceptible to the same types of data loss. Read about the Mt. Gox scandal for more information on how to lose coins if you're not careful.
What is the Block Chain?
The block chain is a shared public ledger that supports the entire Bitcoin network. Every transaction ever made using Bitcoin is recorded chronologically in this open-source, public, transparent ledger. The chronological aspect is what makes it a chain, while each transaction is stored in a block along with a mathetmatical proof of work used for verification. Every bitcoin wallet interfaces with this living blockchain to determine the spendable balance of a user's wallet.
New transactions are verified to ensure BTC is being sent from the correct individual. In other words, they are verified to ensure the sender has (a) the correct key and (b) to prevent double spending. Double spending is a crucial problem faced by digital currencies. Previous to Satoshi's block chain, double spending was addressed by a centralized, trusted authority to verify transactions. The issue here, is this centralization adds a central point of failure to the equation. The distributed architecture of the blockchain removes this central point of failure. Using a scheme called proof of work, the block chain has a measure to defend the system from not only double spending, but also denial of service attacks and a variety of other scams.
The integrity and the chronological order of the block chain are enforced with cryptography. The blockchain is available to anyone who wants to access it, however it is extremely difficult and impractical to hack.
Every time BTC is transferred between wallets, a transaction is recorded in the ledger. Wallets use a secret piece of data called a private key to sign transactions, providing mathematical proof that they have come from the owner of the wallet. This signature also prevents the transaction from being altered by anybody once it has been issued. All transactions are broadcast between users and usually begin to be confirmed by the network in the following minutes through a process called mining.
The blockchain has a few core characteristics that make it a revolutionary technology and one with a huge amount of potential for development. The information embedded in the network:
cannot be controlled by a single entity;
has no single point of failure;
is transparent;
cannot be corrupted;
Essentially, the block chain is a shared, continuously reconciled database of information. The database isn't stored in any single location, meaning it is truly public and the data is easily verifiable by all participants. From a security perspective, there's no centralized store for a hacker to target and corrupt.
Let's juxtabose a block-chain-based financial system and the current banking system. When a transfer is made in the current banking system, only one side has the most up-to-date information. Basically, two owners can’t be working with the same record at the same time. That’s how banks maintain money balances and transfers; they briefly lock access or decrease the balance while they make a transfer, then update the other side, then re-open access or update once more.
Using a distributed block chain, both parties have access to the same information at the same time, and the same version is always visible to both of them.
Besides financial institutions, the distribted architecture of the blockchain is beneficial to a variety of other industries. In the legal field for instance, being able to work with the same document at the same time removes issues like losing track of the latest version, over-complicated filing and recall etc...Really, the block chain is a platform that is generally useful in scaling records management tasks.
The transparency of information is a key element of bitcoin. The US has a relatively low level of corruption when compared to many developing countries, yet we still have plenty to worry about when trusting a bank with our money. In developing countries this is a much more severe problem--trusting the other side in a transaction. The provided transparency makes it much more difficult for one party to dupe the other in the cloak of darkness.
What is mining?
Mining is not simply a means to generate and acquire new bitcoins, though that is a product of the process. Mining is a distributed system that confirms queued transactions by including them in the public block chain. It enforces the block chain's chronological order, and because it is performed by users around the world it protects the neutrality of the network through decentralized computing. To confirm the integrity of the ledger, at any given time, multiple mining computers agree on the precise state of the system.
For a transaction to be confirmed, fulfilled and recorded it must be packed in a block that fits a set of strict cryptographic rules, all verified by the network. These rules prevent previous blocks from being modified – doing so would invalidate subsequent blocks in the chain.
Mining also creates the equivalent of a competitive lottery that prevents any individual from easily adding new blocks consecutively in the block chain. This way, no individuals can control what is included in the block chain or replace parts of the block chain to roll back their own spends.
When a digital transaction is carried out, it is grouped together in a cryptographically protected block with other transactions that have occurred within the past 10 minutes. This grouping is then sent out to the BTC network along with a mathematical proof of work (POW). Miners then compete to validate the transactions by generating this POW, performing billions of calculations per second to do so. The first miner to solve the puzzle and validate the block, receives a BTC reward.
As more people start to mine, the difficulty of finding valid blocks is increased by the network, ensuring the average time to find a block remains equal to 10 minutes. As a result, mining is a very competitive business where no individual miner can control what is included in the block chain. At this point, mining is so demanding that the capital and operating cost limits profitability to only large farms of GPUs.
Is BTC a Bubble?
Maybe. But, it still has a great deal of value and shouldn't be discounted as a scam in my opinion. It's possible that the price has/will outrun its actual value. We should be wary of a market correction (a fall in price) at some point in time. But when will that be? Given the potential for adoption that remains, it could grow tens of thousands of dollars per coin, perhaps hundreds before it reaches its real value. It could also lose virtually all value in a couple of months if an alternative is adopted, or a large entity attacks it.
Because it is new and cutting-edge technology, and because it receives a great deal of press, people are investing in bitcoin without educated expectations. This has led to a rapid climb in demand and perhaps a bubble effect. The rapidly rising demand leads to a rapidly rising price, arguably outrunning its real market value as a commodity. And this climbing price reinforces itself: buyers perceive that the price climb signals large future gains. They buy for fear of missing out on a profit. This behavior is in-part explained by the hot hand fallacy, and a major reason the bubbles exist in the first place.
Bitcoin's decentralized, unregulated design also makes it susceptible to price manipulation by groups with relatively small amounts of capital.
The total market capitalization of BTC at this writing is $33 billion--relatively meager compared to leading stocks and tiny compared to the M1 money supply of major world currencies. Apple Inc. stock for instance, could reach 1 trillion in total market cap this year, while the USD M1 money supply is about $3.5 trillion. The point is, these players can cause fluctuations in price by controlling a substantial chunk of the total bitcoin market capital with an investment of that many wallstreet traders consider to be routine. This control and the speed of exchange creates opportunities for arbitrage and a variety of scams.
When an an individual holds x millions of dollars in Bitcoin, they have the opportunity to control the price in an unregulated market and therefore the ability to commit some fraud. When a scammer follows a climb in price with published "analysis", laypeople are more susceptible to buying into the scam; their belief in future payoffs are confirmed by the scammer's analysis, not knowing that the scammer has the ability to manipulate the value for his own ends. They pump up the value of the stock with misinformation, and the prices reinforces itself because of the sudden climb anyway, allowing them to earn a great deal of value when they dump their stock of coins. And it doesn't necessarily have to be a climb in price either, it can be a fall in price if the scammer is interested in shorting. For more information, see How does a pump and dump scam work?.
A group of investors can also influence the price through circular trading methods. By trading amongst themselves, they can increase or decrease the price of the stock as they accept a larger/smaller price in each transaction.
Because BTC's value is increasingly fueled by speculation, wishful thinking and frenzied greed rather than educated understanding and intrinsic value, individuals can use their funds to influence the market via social media and PR. There's a large margin-trading market in bitcoin now, meaning there are investors rooting AGAINST the price and perhaps for competing cryptocurrencies they have a large stake in. A self-proclaimed "realist" publicizing so-called predictions in a reputable source can cause huge price changes in a market filled with speculation, uncertainty, and gullible laypeople. At this point, a simple Wallstreet Journal headline can cause 10-20% drops in price in a matter of hours.
Conclusion
I'll leave you with this: Bitcoin is a revolutionary way to make cash-like transactions cheaply, quickly and privately (if so desired). I believe it is here to stay, and there will be an exponential amount of development and adoption around the world in the next couple of years. But be careful. The exchange of the currency is unregulated, and it's a radical new technology still in it's infancy. We're already sailing in uncharted territory.
SQL Injection in Ruby
When one is building applications that will be hosted on closed network, perhaps at a small office, it may seem tempting to skimp on time allotted to ensuring application security. But this is certainly a mistake. "It's unlikely" or "it's not worth the time" or "this isn't Google" should never be the sentiment. The truth is, no matter how small the organization, security is always crucial when building a web application--or really anything for that matter. One often exploited aspect of web applications is SQL injections via client inputs. In Rails, if developers aren't careful with their user input and escaping query strings, they can make it very simple for attackers to steal, destroy and otherwise manipulate sensitive data.
SQL Injection attacks are particularly dangerous because they provide access to your application's database.
Good rules of thumb are:
1.) Use prepared statements and parameterize queries. In Rails, use hash or array syntax when constructing your where clauses. Hash key-value pairs will escape arguments while the array form will safely parameterize the query.
Prepared statements prevent attackers from changing the funtionality of the query, even when SQL commands are inserted. If an attacker enters a parameter as "x OR 1=1" while querying the email column in the user's table, the parameterized query would look for a an email which literally matched "x OR 1=1" instead of activating the OR clause.
2.) Escape all user supplied input and attempt to avoid direct user input when performing queries. In many cases, malicious users can easily insert UPDATE and DESTROY statements into queries with interpolated arguments.
Here are some examples of how SQL injection works:
params = {} ## Using string interpolation in where clauses is always dangerous ## BAD (Strings unescaped) params[:firstname] = "'cat' OR lastname='Kelley'" User.find(:first, conditions: "firstname = #{params[:firstname]}") #=> AR Relation matching conditions ## GOOD (Escaped/Parameterized via Hash or Array) User.find(:first, conditions: {firstname: params[:firstname]}) #=> nil ## OR User.find_by_firstname(params[:firstname]) #=> nil ## OR User.where(firstname: params[:firstname]).first #=> nil ## BAD Where Clause params[:email] = "'' OR is_admin=1" User.where("email = #{params[:email]}").first #=> AR Relation with admin user ## GOOD User.where(email: params[:email]).first #=> nil ## OR User.find_by_email(params[:email]) ## More to Avoid ## Bad and Weird params[:column_name] = "ip_address from customers where email like '%rkelley%'--" Customer.pluck("DISTINCT #{params[:column_name]}") ## Never Pass an Input Directly to :destroy_all, :delete_all, :update_all params[:account_active] = "'' OR 1=1--'" Customer.destroy_all("uid = ? AND account_active=#{params[:id]}", params[:uid]) params[:email] = "' OR 1=1;" Customer.where("email LIKE '%#{params[:email]}%'").update_all(inactive: true)
Martin, Buckingham, Moore and Davis Also Claim Major Awards
The 2017 A-10 All-Conference Team and Player of the Year awards were announced today for men's basketball. Unsuprisingly, Richmond's TJ Cline won the player of the year award. He has received a lot of hype all year, and his team is outstanding (though I think Shawndre' Jones is the best player on Richmond.) If I were voting, I would've went with Jack Gibbs for Player of the Year, and my first team would've looked much different.
My Player of the Year: Jack Gibbs
Jaylen Adams and TJ Cline are outstanding players, no doubt, but Jack Gibbs has been truly special during his time at Davidson. After posting a 35% USG last year and leading the entire conference, he once again led the conference with a 30.8% mark this year. What's incredible is, aside from Peyton Alldridge, Davidson's team is incredibly weak. The duo combined for 9.6 of Davidson's 16.3 wins shares (58%), and were used more than 56% of the time. Gibbs is the focus of every opposing coach's defensive gameplan before every game, they know he's going to shoot the ball and they still can't stop him. Not only was Gibbs gameplanned for, he played through amultitude of injuries--even more of a reason he should win POY. He was third among all guards in player efficiency rating, and he ranked in the top-10 among all players in Win Shares (7th), Assist Percentage (7th) and Effective Field Goal Percentage (10th). Of course, he also led the conference for the second season in a row in points per game with 22.0.
Despite going 16-14 and getting a 9-seed in the A-10 Tournament, Davidson is ranked 85th by KenPom, 4th among conference teams. Up until this point, their luck measurement is 309th in the country. Let's see if Gibbs can change their luck.
My 1st Team
JeQuan Lewis
1st in BPM among A10 point guards and 4th among all players
3rd in WS/40 among guards and 8th overall.
6th in total Win Shares.
8th in TS%
6th in Steal Percentage and 10th in DRTG
Lewis most well-rounded guard in the A10. He's the quarterback of VCU's offense and an excellent athlete who plays the position like Rajon Rondo. He can beat top defenders with his feet and has the incredible agility and body control to finish with a variety of moves. He's also a lethal long-range shooter that can splash shots off the dribble at the point and wings.
Jack Gibbs
1st in USG% and PPG among all players for the second consecutive season.
The lowest turnover percentage among starting guards
7th in total Win Shares
3rd among guards and 8th in PER among all players
6th in career PER
Davidson leans on Gibbs, even while he's been injured. He was at 35% USG last year and is at 31% this year, and he is still able to lead the conference in points per game and do so efficiently. The departues of A10 POY Tyler Kalinoski and Brian Sullivan left the team gutted going into 2017. It was essentially Gibbs and Aldridge thsi year, and the team still managed to earn an 85 ranking from KenPom's algorithm at this writing and 16 wins heading into the tournament.
Gibbs is the most dynamic scorer in the conference, and he has the same type of three-point range and efficiency as Adams but also the the ability to cut to the basket and finish on par with Lewis or Jones. He has an uncanny court IQ, and has earned comparisons to Steph Curry at the same age.
Peyton Aldridge
1st in total Win Shares among forwards, 2nd overall.
3rd in PER.
5th overall in WS/40
2nd in ORTG among forwards, 3rd overall, 10th in BPM overall
25.8% USG% is just outside of the top-10
Aldridge is arguably the best all-around forward in the conference. He's the positions leader in total win shares, he ranks top-10 in both offensive and defensive win shares, is within the top-5 in PER and ORTG. His defense took a large step forward this year, and his DRTG was 100.4 while he combined for nearly 3 steals-plus-blocks per game.
Aldridge can shoot, he can score and rebound in the post, and he plays excellent defense. Davidson is gutted aside from he and Gibbs and their offense goes to them almost 60% of the time. Despite this, both players produce at a elite level consistently.
Tyler Cavanaugh
3rd in USG% among all players and 0.8% behind TJ cline among bigs.
8th in total Win Shares
9th in PER and 6th in Offensive BPM
7th in Offensive Rebounding Percentage, 6th in Defensive Rebounding Percentage
10th in career PER in A10
The 2015-16 NIT Most Valuable Player, Cavanaugh is GW Basketball. Unlike Cline, Pollard or even Alldridge, he doesn't have a top point guard to feed open opportunities to score, and he lacks a quality or even an experienced big to take some of the pressure off of him in the post and in terms of collecintg boards. His USG% is 3rd in the conference among all players, and there is no other player on GW's offense that teams need to gameplan for. Despite that, he scored an unbelievable 18.6 points per game and collected 8.3 rebounds on 43% shooting. Defensively, he's exposed by the lack of the team's effective perimeter defenders. When Watanabe is injured or off the floor particularly, teams are able to slash into the post cleanly past Jaren Sina's weak defense. Because he's an integral part of the team's offense, his defense is also handcuffed by GW's no-fouls approach.
Teams try to shut Cavanaugh down every game, yet he's still 8th among all players in Win Shares at nearly 30% USG%. He's a beast. His ability to dominate the post physically paired with his lethal long-range shooting ability and court IQ should earn him a spot in the NBA.
Hassan Martin
1st in the conference in Block Percentage and Blocks Per Game for 4th consecutive season, 9th in the A10 all-time; 4th-most career blocks in conference history
1st in WS/40, PER and 3rd in BPM
1st in Effective Field Goal Percentage
3rd among bigs in ORTG
14th in career PER
A force in the post. Martin leads the conference in just about every measure of individual player value and would've been my second choice for POY. He's an absolute beast, and he is 4th all-time in blocks in the conference with only Stephane Lasme, Marcus Camby and CJ Aiken in front of him. Rhode Island under-achieved for much of the season given their talent level, particularly during conference play, and I believe that hurt Martin in voters' eyes. No doubt about it though, he's a first-team player and a dominant force on both offense and defense. He scored a career-high 14 points per game and did so efficiently, posting the A10's best eFG.
My 2nd Team
Jaylen Adams - St. Bonaventure Shawndre' Jones - Richmond Scoochie Smith - Dayton TJ Cline - Richmond Justin Tillman - VCU
My 3rd Team
Marquise Moore - George Mason Matt Mobley - Saint Bonaventure Yuta Watanabe - George Washington Charles Cooke - Dayton Mo Alie-Cox - VCU
Just Missed: BJ Johnson, Jordan Price, Joseph Chartouny, Pookie Powell, Kendall Pollard, E.C. Matthews
I have my dream job, but if I was in another line of work this one would be intriguing: transmission tower engineer. These guys free climb towers twice as tall as The Empire State Building. And unlike climbing coarse and porous rock ledges, their boots slip and slide against steel and alloy covered with condensation. If the weather turns? Try braving a thunder storm on a half-mile-long lightning rod...Yeah, they have balls.
God bless these tower engineers. They maintain our crucial telecommunications infrastructure, American Heroes of American America USA HASHTAG TEXAS.
It’s likely that subconscious tendencies are impacting your efficiency at work. Implicit biases are “attitudes or stereotypes that affect…
Do you understand the key differences between hashing and encrypting? Do you know when to use each, and why? Read on to find out.
Succinct summary of how symmetric encryption and hashing differs from assymetric/public-key encryption. The article gives a nice example of how and why symmetric encryption is ideal for securely storing and verifying a user's password.
One of the more difficult concepts to wrap one's head around is that good hashing algorithms are one-way streets and can't be feasibly reversed to get the password from the hashed password. However, some of the most popular algorithms have been effectively cracked and rainbow tables are available online for reversing passwords unsecured by salts/nonces (secret piece of string data used in addition to the alogorithm to make the hashing stronger). Try CrackStation to crack a hashed string.
MAC Address Spoofing - A Work-a-Round for Connecting Your Network Appliances at Hotels
Purpose
This is a walkthrough informing readers how to connect their network appliances (e.g. Apple TV, Chromecast, Roku) to a hotel network that requires the user to interact with a splash page. These devices typically lack the necessary web browser to complete the splash page and connect to the internet.
Background
I relocated for new employment a couple of years ago. Since I had to move suddenly, I chose to live in an extended stay hotel for my first three months. The hotel I was staying at provided its guests free Wifi access. However, it required users to accept terms and conditions on a splash page via browser interface before they could use the network. While this is common behavior for hotel network setups, it unfortunately makes it difficult for guests to utilize the local area network for work, entertainment etc...Simple network appliances often lack the web browser necessary to complete forms like the ones on these splash pages--even if the form is comprised only of a checkbox and submit button. So, when I wanted to use my Chromecast to watch some Netflix, I had to create a work-a-around.
Like many networks, my hotel's network attempts to improve security by using MAC address filtering. Luckily, Mac OS X (>= 10.4) makes it very easy to spoof your network card's MAC address.
Here's how to add a devices like Chromecast, AppleTV, Roku to a wireless network that requires a browser to authenticate and accept terms and conditions.
Before You Start
You'll need two things besides the device you want to connect to the network, (1) your laptop and (2) some Unix shell flavor.
If you don't have any idea what a MAC address is, see my Gist on MAC Address Spoofing. Really, there are just two important points you should know about MAC addresses before proceeding:
1.) MAC addresses are 48-bit, factory-assigned, hexadecimal uids used for organizing a physical network.
2.) MAC addresses will typically be reset once your computer/device reboots.
Steps
1.) Open up Terminal.app and run the following command to list your machine's active network interface:
# Should output something like 'en0' or 'en1' depending on wireless/wired connection $ ifconfig | pcregrep -M -o '^[^\t:]+:([^\n]|\n\t)*status: active' | egrep -o -m 1 '^[^\t:]+'
2.) Show the MAC address for the interface name you retrieved in step 1, en0 in this example:
$ ifconfig en0 | grep ether
3.) Store that value in a variable so you can easily set your MAC address back to its original value without rebooting your computer.
$ mymac=$(ifconfig en0 | grep ether)
4.) Turn your chromecast/other device on and configure it to connect to the network. Find the devices MAC address and copy it down.
5.) Disconnect your computer from the network and turn off your wireless controller:
# First disassociate from your wireless network $ sudo airport -z # Then turn the network interface controller (NIC) off $ sudo ifconfig en0 down
6.) Turn your NIC back on, and set your the your network card's MAC address to the Chromecast's (xx:xx:xx:xx:xx:xx in this example):
# Turn on the NIC $ sudo ifconfig en0 up # Change MAC address of your computer to Chromecast's $ sudo ifconfig en0 xx:xx:xx:xx:xx:xx
Note: If you get a 'bad value' message or your MAC address isn't being set to the new value you generated, you may have to specifiy another name for the interface.
# Try using 'ether' for OS X 10.9 and 10.10 $ sudo ifconfig en0 ether xx:xx:xx:xx:xx:xx # Try using 'Wi-Fi for OS X prior to 10.8' $ sudo ifconfig en0 Wi-Fi xx:xx:xx:xx:xx:xx
7.) Turn off your Chromecast. Then, open your laptop's browser, accept the splash page terms and conditions and log onto the network while using the Chromecast's MAC address.
8.) Repeat step 5, disassociating from the network on your laptop and turning the NIC off.
9.) Turn your Chromecast on, and it should automatically connect to the wireless network.
10.) On your laptop, change your MAC address back to it's default:
sudo ifconfig en0 ether ${mymac}
Also...
Use arp -a -n to list all of the machines on your LAN. This should out their MAC and their IP/Host. You can probably guess why this is useful...
Guess what? If Hillary wins, or if Trump wins -- it's not as big a deal as the people say it is.
The culture enveloped within the liberal industrial complex deems any opposition to be evil. So really, the rebellion wasn't about insiders vs. outsiders -- it was about a rejection of decades of liberal fascism expressed through identity politics, balkanized grievances, racial politics, attacks on traditional institutions and anti-exceptionalism.The Trump phenomenon was a thumb in the eye of liberal complacency. It was the first time in my memory that a Republican gave the same treatment back to the Democrats. That caused this new fretting over polarization. There was no polarization when only one side (the Dems) was the bully.No one spoke of polarization when the left demonized a decent man like Mitt Romney. But when you have a candidate like Trump hit back, now you have polarization. This should have been a gift for Republicans -- but it wasn't. Where Trump and his mouthpieces went wrong was turning this into an attack not on leftism, but on the establishment -- which lumped real Republicans, ideological conservatives, hard working grass roots activists, and even noted military heroes into the same box as Hillary, Obama, Hollywood and the Harvard faculty.
There are lots of people whose jobs depend on Trump winning on Tuesday. There are a lot of people whose jobs depend on Hillary winning. This is why you have to take any opinion not tethered to facts with a grain of poop. The exceptions to this amorality: the people who were honest to a fault, and were willing to lose a paycheck. Think Jonah Goldberg. Kevin Williamson. Ben Shapiro. Think of everyone of who didn't sacrifice principles for more appearances on TV.
And remember, liberals: Trump is a centrist. Cruz was way more to the right. And he got rejected!
FOR nine long days, with the election imminent, a cloud of suspicion hung over Hillary Clinton.
I guess we know which party the bureaucrats and fascists support.
With the election immiment, and so many reputable polls and forecasts predicting a comfortable Hillary Clinton win, Comey's FRUITLESS investigation is very suspicious.
The stock market — and US personal wealth holdings — continue to set new records. The United States is now at or near “full employment,” at least according t...
As Donald Trump prepares to enter office, I hear a lot of animosity towards white men in the US on social media. The sentiment is that white men somehow are all privelaged and overly greedy. Really, the data portrays something different in modern America however. It isn't just women and minorities who experience pain and fear of the future on a daily basis in this country.
Male work rates in the US are at depression-era levels, and fall in prime-age male employment since 2000 is far greater than in struggling economies like Greece.
Each year, 7 million US men spend the majority of their daylight time playing videogames, watching TV and surfing the internet instead of accumulating skills that would make them more employable in the future.
This is just another indicator that our economy, artificially propped up by low interest rates as is, does not have a bright future. As key inputs become increasingly scarce (oil, fresh water), as roaring Asian economies become relatively stronger and better educated (China, Indonesia, Vietnam, Singapore), the strain will only increase.
How to Prevent Submitting Duplicate Forms PT. II
Yesterday I published a post and gist on how to prevent users from submitting duplicate form data in your Rails app. I created a simple method that prevents client browsers from caching the form, and I run it via an after_filter in the controller. In this post, I’ll show you an extra layer of protection, that can be used in conjunction with the aforementioned approach. Now that we prevent the user from entering duplicate data in a form by addressing the GET request, let’s fill the remaining holes by preventing duplicate data from being saved to the database on POST request.
ActiveRecord offers a variety of useful tools to Rails developers out-of-the-box, practically everything you need from your ORM. One of my favorite methods is first_or_initialize (first_or_initialize_by in Rails 4.0.2+). This method returns the first record in a relation if it exists. If the relation returns an empty array, then it instantiates a new instance of that class with any optional attributes it is passed. Example:
class PuppiesController < ApplicationController before_filter :load_puppy, only: [ :new, :create, :show, :update, :edit, :delete ] def new ## If user already has a record in the puppies table ## created this year ## then redirect them to edit that Puppy. if [email protected]_record? flash[ :notice ] = "You may only create one puppy per year. You may edit your existing puppy." redirect_to edit_puppy_path( @puppy ) and return end end def create ## prevent malicious user from setting the user_id @puppy.user_id = current_user.id if @puppy.errors.empty? && @puppy.save redirect_to @puppy else ## Tell user they need to fix their mistakes render :edit end end private def load_puppy @puppy = Puppy. includes( :user ). by_user_from_this_year( current_user.id ). first_or_initialize( params[ :puppy ] ) end end
Once again, I do think we should use the first_or_initialize approach in conjunction with our preventing forms from being cached by the browser. And of course, this is only one layer of protection, it’s always wise to have other layers at the model and database level. Gotta protect that data.
Using :first_or_initialize will allow us to update a user’s existing record if she indeed has one, instead of creating a duplicate. However, from a UX perspective, you need to make it clear to your users what is happening when they press Back, and then they edit a form and re-submit it. If the form is cached and they press back, they may assume that they’re creating a totally new record, instead of updating the existing record they just created on the first submission. This can get messy. So, I like to use both approach-1 and approach-2 together; approach-1 to prevent the browser from caching form data (fixes 99.9% of cases) and approach-2 to prevent users from saving duplicate records via the POST request with first_or_initialize (the other 0.1%). Forcing the browser to hit the server when the user presses back also gives us the opportunity to warn the user that they have an existing record, and that they’re being redirected to an edit page. (And we like the server side, because we can use Ruby there!)
All together simply:
class ApplicationController < ActionController::Base prepend_before_filter :authenticate_user! private ## Tell client not to cache the response def client_will_not_cache_response response.headers[ "Cache-Control” ] = “no-cache, no-store” response.headers[ “Pragma” ] = “no-cache” response.headers[ “Expires” ] = “Fri, 01 Jan 1990 00:00:00 GMT” end end class PuppiesController < ApplicationController before_filter :load_puppy, only: [ :new, :create, :show, :update, :edit, :delete ] after_filter :browser_will_not_cache_response, only: :new def new ## If user already has a record in the puppies table ## created this year ## then redirect them to edit that Puppy. if [email protected]_record? flash[ :notice ] = "You may only create one puppy per year. You may edit your existing puppy." redirect_to edit_puppy_path( @puppy ) and return end end def create ## prevent malicious user from setting the user_id @puppy.user_id = current_user.id if @puppy.errors.empty? && @puppy.save redirect_to @puppy else ## Tell user they need to fix their mistakes render :edit end end private def load_puppy @puppy = Puppy. includes( :user ). by_user_from_this_year( current_user.id ). first_or_initialize( params[ :puppy ] ) end end
Some final notes about this code...I added the :load_puppy method to DRY up some common code, refactoring it into a single method called prior to our controller actions. The authenticate_user! method you see in the Application controller is a Devise method for authorizing users--it's there for reference since so many of us use Devise. I also moved the :redirect_if_existing before_filter method--you may remember it from my previous post--into the :new action definition for the sake of clarity. It was only being used in that one method all.
That’s it.