Logo

Who is talking?

Archive

My eBook build process and some PDF, EPUB and MOBI tips

over 4 years ago | Pat Shaughnessy: Pat Shaughnessy

Ruby Under a Microscope is an illustrated guide to Ruby internals. No C programming required!

Agile vs. Lean

over 4 years ago | Sven Kräuter: makingthingshappen blog.

One of the first things I tell potential clients that hire me for an agile transformation is that part of my goals is to make myself superfluous. Although more or less common sense for people with an agile background this provokes more often than never puzzled faces. “Isn’t he supposed to lead the product development process by managing the product team with agile methodologies?” Transforming intangible perceptions into actionable items In fact I’m supposed to enable the product development team to start managing itself in an agile manner. Reads itself like a minor difference in the formulation, but has a major impact on the proceeding. <!-- more -->Of course I start leading & managing the team. Introduce the necessary events, evolve daily stand-ups to short & precise meetings, get everybody on the same page and facilitate the retrospectives. Apart from the latter, a fully developed agile team is able to answer the three magic daily questions and organize the events on its own. When it comes to retrospectives, it’s a little bit different. You need a neutral facilitator here a little longer. For my last client this meant that after the time intensive initial phase of coaching I stopped attending on a daily basis after we both felt comfortable with it. I continued to facilitate the retrospectives for some more weeks, and after we tried and saw that there are still action items and the resulting improvements as tangible outcomes I realized I brought that team to the agile path and futhermore to a state in which it could walk this way without further assistance. Short & direct feedback. <3. Tangible outcomes are amongst the core metrics I am judged by. In the beginning the effects of the new process are still very intangible. “We like that we now communicate more with each other, but we are affraid losing our efficiency!”. When moving from batch processing your specialized task to think a little cross functional this is a natural reaction to the change. Measured by the quantity of product features you deliver it in fact will look like losing efficiency. When judging by the quality of what you deliver the efficiency equation looks quite attractive. In fact after a short period of time the propelled quality becomes quite obvious - be it the lowered technical debts, the increased harmony of the team or the ability to react to customer wishes faster. As you may have realized I used the formulation “measure quantity” and “judge quality”. I did this on purpose since it stresses the very tangible nature of quantity and the more intangible way we perceive quality. In my retrospectives I’m quite strict about actionable items as a result. They make our progress tangible and I see them as a basic metric to measure the progress we make. In fact I put a little square on every action item sticky and we check this box if we accomplished the task in the next retrospective. This is just a small example of validated learning. Which is one of the aspects in the focus of lean entrepreneurship. It is about learning based on the data you collect from your product and finding the right metrics to measure the value and the growth of it. Which is why I see Agile & lean entrepreneurship as a synergy of greatest potential. Participating in the 2012 Agile Design Camp I bootstrapped some provocative slides to bring the audience into the mood for discussing the topic. The core hypothesis here is that agile focusses on the process success while lean entrepreneurship focusses on the product success: ‘Agile vs Lean’ on Slideshare Of course this is only true to some extent. When working in agile environments the chance of meeting practicioners that do not only think in terms of their special subject but also have the product in their vision is quite high. When iterating over your processes lean entrepreneurial thinking as a result can be an outcome quite naturally. This is a result of the fact that the right process framework takes away unnecessary pressure from your team. This enables the practicioeners to actually think about what they build as opposed to being busy with figuring out how to finish tasks in time. I would say this is similar to moving up on the Maslov pyramid - just in the domain of your product quality and not concerning personal life’s quality where Maslov’s famous geometric metaphor is originally pointed at. To quantify if our newly gained freedom actually results in higher value for the customer moving from judging prodcut quality to measuring product quality is essential. One way to achieve this goal is the path of lean entrepreneurship. Viewing from that angle I think it becomes quote obvious why I chose the provocative hypothesis that agile focusses on the process success while lean entrepreneurship focusses on the product success.

Big Data ETL and Big Data Analysis

almost 5 years ago | Prasoon Sharma: Enterprise Software Doesn't Have to Suck

I was at Strata New York 2012 last month. Great conference! Thanks O'Reilly media for assembling the industry leaders and running it well.I understand it was too crowded for some of my out-of-town friends. Stepping out to the streets of mid-town Manhattan for a breath of fresh air and calmness wasn't an option either. Maybe O'Reilly can get a bigger space next year?My primary interest in Big Data analysis was structured data analysis i.e. crunching, munging (ETL) and analysis of large dataset in columns and rows.My team deals with 1-2 Terabytes (~ 1 billion rows) of structured data (e.g sales transaction data) regularly for marketing/retail/healthcare analytics. Like others, we're spending a lot of time in Big Data ETL processes and less on Big Data Analysis. Someone at Strata New York captured this well,80% of a Big Data development effort goes into data integration efforts and only 20% of our effort/time is spent on analysis, i.e. interesting things we want to work onI want to flip this equation. I want to be able to spend 20% of our time/effort on Big Data ETL/integration efforts and 80% on Big Data analysis.At Strata, I wanted to check if vendors and open source communities had simplified the Hadoop stack for my use. There have been many improvements in the past year and the products on my list is quite long. We've more players in Big Data space and the solution space is muddy. It is great to have more vendors, experts, communities focusing on Big Data but the product space is crowded, fragmented and CONFUSING (just listing all Apache products discussed at Strata needs 1 full page.)I created a list of products to try out. I wish these products were easy to evaluate (legal paperwork, infrastructure footprint, and ease of setup and execute my use cases).As far as ease of use and powerful data science workbench is concerned, I want to use something like R or even Excel for these steps (Big Data ETL and Big Data analysis), but they are both memory constrained. So, I need other options.Did someone say, Hadoop? Yup, on it. I tried it a few years ago and we're exploring it now. Hadoop/MapReduce is THE infrastructure to power Big Data ETL and Big Data analysis.I also believe that MapReduce and Databases are complementary technologies and the experts agree! See MapReduce and Parallel DBMSs: friends or foes?Here's how I've framed my problem and thinking about the solution space.Big Data ETL processTake big structured dataset (multiple CSV files with total 100M-1B rows) and create DDL/clean/transform/split/sample/separate errors in minutes.Solution options:Unix scripts (shell, awk, perl). Do all of the above in one pass (i.e. read each row only once) quickly. Start with Unix parallel processes, scale to multiple machines (mapreduce-style) only if neededBig Data ETL tools like Kafka?Open source ETL tools (e.g. Talend)Can commercial ETL tools do this in a few minutes/hours?Others?Given any structured data from client (csv), our Big Data ETL workbench takes the data and processes it super fast (detect data types, clean, transform eg. change date formats to our internal standards, separate error rows, create sample, split into multiple clean files)Raw data files have different schema that we auto-detect in processing (only string vs numeric types to begin with).Big Data AnalysisThen we load this data for analysis:RDBMS for well-defined arithmetic/set-based analysisnoSQL database (Lucene/Solr with Blacklight front-end for discovery). Blacklight project: Open source discovery app built on Lucene/Solr. Thinking of it as a discovery app for Big Data analysis. Facets on top of structured data. Slide-dice large structured dataset. We can add visualizations later (e.g. summaries etc.) Checkout this Stata session on Lucene-powered Big Data analysis which confirmed this design hypothesisThe clean split files can be used in any stats tool as well for statistical analysis e.g. SAS for larger data sets, R for smaller ones (often the clean split files are small enough for R)New Big Data tools like ImpalaWe're building proof-of-concepts for Big Data ETL (Unix scripts) and Blacklight discovery app on top of Lucene/Solr. I will share it when its ready. Stay tuned.

Don’t write off Microsoft just yet!

almost 5 years ago | Aishwarya Singhal: Aishwarya Singhal

I just bought a new laptop with the cool new Windows 8 installed. I must admit that I was a bit skeptical of how the new OS would be, but its totally taken me by surprise, and in a good … Continue reading →

Don't write off Microsoft just yet!

almost 5 years ago | Aishwarya Singhal: Aishwarya Singhal

I just bought a new laptop with the cool new Windows 8 installed. I must admit that I was a bit skeptical of how the new OS would be, but its totally taken me by surprise, and in a good way!  First, I absolutely adore the new Metro layout. Its like a cool dashboard where I have all my tools and information handy for me to get started. From facebook to gmail to google search, everything is a shortcut on there. And its not just a shortcut! The mails tile shows new ones and facebook one shows the highlights - everything that makes you decide if you want to click that icon or not. Similarly, there are news feeds, weather updates and other handy info. Its really much more useful than the mostly empty windows desktop that exists on previous versions. And its much brighter and colorful too! Secondly, IE 10 is a total pleasure to use. Its super fast, and feels much lighter. I also hear that it finally adheres to global standards too (yay, developers rejoice) ! Thirdly, each new window/ app is a full screen by default. No task bar, no title bar, nothing. It makes the full use of the screen - can it get better ?! Oh well, some things require 2 clicks (including a right click) that should really just need one. Like closing windows. Yeah. You either drag a window to the bottom to ask it to go to hell (or where ever), or you right click, find yourself a cross button and close the damn thing. I wish there was a close button that would appear when I hover around one of the corners, closing a window should be a one click thing. And I could not install Google Chrome on Win 8 - its just kept on hanging up on me. I think the performance of the OS and system in general is pretty good, and the fact that the same system will run on mobile and desktop/ laptop computers is pretty encouraging. May be we should consider how we'll develop apps for windows along with Android and iOS ? ha ha! I hear Windows 8 is all HTML and JS anyways!

Look, Ma! No batteries! A Clojure Web App Without Noir

almost 5 years ago | Daniel Higginbotham: Flying Machine Studios

UPDATE http://gratefulplace.com now uses a completely different codebase. You can find it on github. You can read about the new codebase at Building a Forum with Clojure, Datomic, Angular, and Ansible . Awhile back I released OMG! SMACKDOWN!!!, which still holds the title for dumbest Clojure app in existence. To make up for that ludicrostrosity, I’ve created Grateful Place. This time I around I didn’t use Noir, instead going closer to the metal with Compojure and Enlive. The experience was a lot easier than I anticipated, perhaps easier than using Noir. This post will cover some of the more interesting bits of code: Templating heaven with Enlive and Middleman Using macros to enforce full stack consistency Roll-your-own validations Pagination is more fun with macros Using fierce mustaches to run tasks Fun utilities You can find all source code on github. Also, I’m going to be at the Clojure Conj and would love do meet folks. If you’d like to chat, please do tweet me (@nonrecursive) or find me at the conj! App Overview Grateful Place is a social app with only a few models: Users, Comments, Posts, and Likes. Nothing too fancy. If you’re interested in why I made it, here’s a post I wrote about gratitude. Templating heaven with Enlive and Middleman Enlive is the bee’s knees I can say without reservation that Enlive is the best templating library I’ve ever used. I absolutely love it! If you try out one thing from this post, try out the workflow I describe here. Enlive is completely different from Hiccup, ERB, HAML and the like and it’s worth giving it a shot. If you’re not familiar with Enlive, it’s a selector-based templating library. In the same way that CSS allows you to separate structure and presentation, Enlive lets you separate structure and view logic. This is huge! Unless you’re the kind of person who still likes to use font and bold tags in your HTML, you should give Enlive a try. Middleman/Enlive Workflow Using Enlive allowed me to do all my design work using the Ruby library Middleman. This allowed me to build stand-alone web pages so that I could see how they looked without worrying about any view logic. For example, here’s the example home page I put together: clojure/gratefulplace-dissected/v1/assets/generator/source/index.html.haml 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42--- title: Grateful Place --- #posts .post .content %p Here is some content. %footer .date Jan 03, 2012 .author by %a{:href => ""} Joe Schmoe .favorite %a{:href => "#"} &#9733; .status Like this %a.comments{:href => ""} 35 Comments .post .content %p Here is some content, too. %footer .date Jan 03, 2012 .author by %a{:href => ""} Joe Schmoe .favorite %a{:href => "#"} &#9733; .status Like this %a.comments{:href => ""} 35 Comments .pagination %a.previous{:href => "#"} Previous %span.page-link.current 1 %a.page-link{:href => "#"} 2 %a.page-link{:href => "#"} 3 %a.next{:href => "#"} Next You might have noticed a few weird things. First, this is written using HAML. Yep, HAML. I prefer HAML over HTML because it’s more concise and the consistent structure allows me to visually scan it more easily. And since my HTML templates and view logic are completely separate, I can write my designs in HAML, preview them with Middleman, and then generate an HTML file for Enlive to work with. Here’s my process in full: Build on every change by cd’ing to assets/generator/ and running fswatch . ./g. This runs a bash script which generates the HTML, CSS, and Javascript files and moves them to the proper directories. Start up Middleman by cd’ing to assets/generator/ and running middleman View site at http://localhost:4567 and make changes to my heart’s content When I’m happy with the changes, create or recompile a Clojure file which makes use of the HTML file with Enlive. It’s necessary to recompile the files so that Enlive uses the updated HTML. That doesn’t happen automatically. Another thing you might have noticed is that in the HAML file I’m showing two example posts. With Enlive, you actually have to add some logic to remove one of the post divs: clojure/gratefulplace-dissected/v1/src/gratefulplace/views/posts.clj39 40 41 42(defpage all "index.html" [posts current-auth record-count page max-pages] ;; don't show the second post as it's just an example [[:.post (h/nth-of-type 2)]] nil Some code to reduce boilerplate Finally, here’s some code I put together to reduce boilerplate: clojure/gratefulplace-dissected/v1/src/gratefulplace/views/common.clj 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47(defonce template-dir "gratefulplace/templates/") (h/defsnippet nav (str template-dir "index.html") [:nav] [logged-in] [:.auth] (if logged-in (h/do-> (h/content "Log Out") (h/set-attr :href "/logout")) (h/do-> (h/content "Log In") (h/set-attr :href "/login")))) (h/deftemplate layout (str template-dir "index.html") [html] [:html] (h/substitute html) [:nav] (h/substitute (nav (current-authentication))) [:nav :ul.secondary :#logged-in :a] (if-let [username (:username (current-authentication))] (h/do-> (h/content username) (h/set-attr :href (str "/users/" username)))) [:nav :ul.secondary :#logged-in :span] (when (current-authentication) (h/content "Logged in as"))) ;; Need to come up with better name ;; Bundles together some defsnippet commonalities for user with the ;; layout template ;; ;; TODO destructuring doesn't work in argnames (defmacro defpage [name file [& argnames] & body] `(do (h/defsnippet ~(symbol (str name "*")) (str template-dir ~file) [:html] [~@argnames] ~@body) (defn ~name [{:keys [~@argnames]}] (layout (~(symbol (str name "*")) ~@argnames))))) The ultimate purpose of this code is the defpage macro. This helps me in a few ways. It lets me easily write view code for each page without having to worry about the surrounding layout. For example, before writing the above code I had to include the navigation transformations in every page, which quickly got annoying. The defpage macro also bundles up the template-dir variable, saving me some keystrokes and some duplication. Finally, it establishes a consistent way of interacting with the controller, a topic I’ll explore more in the next section. Before that, here’s an example of defpage in action: clojure/gratefulplace-dissected/v1/src/gratefulplace/views/posts.clj77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94(defpage show "posts/show.html" [post comments current-auth] [:.post :.author :a] (linked-username post) [:.post :.date] (h/content (created-on post)) [:.post :.content] (md-content post) [:.post :.edit] (keep-when (can-modify-record? post)) [:.post :.edit :a] (set-path post post-edit-path) [:.post :.moderate] (keep-when (moderator? (:username current-auth))) [:.post :.moderate :a] (h/do-> (set-path post post-path) (h/content (if (:hidden post) "unhide" "hide"))) [:#post_id] (h/set-attr :value (:id post)) [:.favorite] (favorite current-auth post) Thanks to defpage, my view code contains only logic specific to that view. I love it! Using macros to enforce full-stack consistency Creating a route→controller interface When I was putting the app together, each of my compojure routes was a unique and beautiful snowflake: (GET "/users/new" [] (users/show-new)) (POST "/users" {params :params} (users/create! params)) (GET "/users/:username" [username] (users/show username)) As you can see, each route captures variables in a completely different way. At first I thought this made sense; I was passing exactly the data that was needed to each controller. However, this quickly became a pain in the ass. For example, if I wanted to make a request param available to a view, I had to modify functions all up and down the stack: in the routes, in the controller function, and in the view function. I ended up making all routes send the full request object to their functions: clojure/gratefulplace-dissected/v1/src/gratefulplace/middleware/routes.clj14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30(defmacro route [method path & handlers] `(~method ~path req# (->> req# ~@handlers))) (defroutes routes (compojure.route/files "/" {:root "public"}) ;; posts (route GET "/" posts/all) (route GET "/posts" posts/all) (route GET "/posts/new" posts/show-new) (route POST "/posts" posts/create! (friend/authorize #{:user})) (route GET "/posts/:id" posts/show) (route GET "/posts/:id/edit" posts/edit) (route POST "/posts/:id" posts/update) The route macro is very handy. It saves me from typing and (for the most part) from burning precious brain cells on thinking, and it enforces the “send the full request” constraint by not allowing me to deviate. Of course, I can still deviate, and this is useful if you’re using a library: clojure/gratefulplace-dissected/v1/src/gratefulplace/middleware/routes.clj56 57 58(friend/logout (ANY "/logout" [] (ring.util.response/redirect "/"))) If I want to get to the params, I just use a let; no big deal: clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/posts.clj38 39 40(defn show [req] (let [id (get-in req [:params :id]) Creating a controller→view interface In the same way that it was useful to create a route→controller interface, it became useful to create a controller→view interface. That was accomplished with this macro: clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/common.clj55 56 57 58 59 60 61 62 63 64 65(defmacro view "provides defaults for the map provided to view functions and allows you to provide additional key value pairs. Assumes that a variable named req exists" [view-fn & keys] `(let [x# {:current-auth (friend/current-authentication) :errors {} :params (:params ~'req) :req ~'req}] (~view-fn (into x# (map vec (partition 2 ~(vec keys))))))) This also helped with one weird problem I ran into with cemerick’s friend library where (friend/current-authentication) returns nil from within an anonymous function (and there are many anonymous functions in my view code). I could circumvent this problem by assigning doing something like (let [current-auth (friend/current-authentication)]). But it seemed to make more sense to just always pass that data along when calling view functions, as you can see in the macro above. The defpage macro also helped in establishing this interface in that it allowed me to destructure the arguments sent by the controller. For example, if a controller had (view posts/show {:post post}) I could create the corresponding view with (defpage show [post current-authentication]) And I wouldn’t even have to worry about the order of the arguments. It really reduced some “incidental complexity” (and I’m almost certainly using that term incorrectly). Roll-your-own validations It wasn’t too difficult to write my own way of doing validations, and I’m satisfied with it for now. Here’s a description of the data structure, with an example following: Validation: a combination of a key and “validation check groups” Validation check group: first element is an error message and the rest are “validation checks”. If any validation check returns false then the error message is added to a list of error messages for the given key. Validation check: a boolean function to apply to one of a record’s values. The value corresponds to the validation key Here’s an example: (validate {:username "joebob", :password "hey"} {:password ["Your password must be at least 4 characters long" #(>= (count %) 4)]}) This validation would fail because the value "hey" for the :password is not at least four characters long. Here’s the main validation code: clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/common.clj16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48(defmacro if-valid [to-validate validations errors-name & then-else] `(let [to-validate# ~to-validate validations# ~validations ~errors-name (validate to-validate# validations#)] (if (empty? ~errors-name) ~(first then-else) ~(second then-else)))) (defn error-messages-for "return a vector of error messages or nil if no errors validation-check-groups is a seq of alternating messages and validation checks" [value validation-check-groups] (filter identity (map #(when (not ((last %) value)) (first %)) (partition 2 validation-check-groups)))) (defn validate "returns a map of errors" [to-validate validations] (let [validations (vec validations)] (loop [errors {} v validations] (if-let [validation (first v)] (let [[fieldname validation-check-groups] validation value (get to-validate fieldname) error-messages (error-messages-for value validation-check-groups)] (if (empty? error-messages) (recur errors (rest v)) (recur (assoc errors fieldname error-messages) (rest v)))) errors)))) if-valid wasn’t strictly necessary but I made it and ended up liking it. It’s a small improvement, but a handy one. Pagination is more fun with macros It was a bit difficult for me to pull the pagination code together. I tried many approaches, and I’m not 100% satisfied with what I have, but it’s better than nothing! The basic approach was to add a couple Korma clauses to a base set of clauses. Here are the base clauses, along with a macro that allows me to add more clauses willy-nilly: clojure/gratefulplace-dissected/v1/src/gratefulplace/models/post.clj23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39(def base (-> (select* e/post) (with e/user (fields :username)) (with e/comment (aggregate (count :*) :count) (where {:hidden false})) (with e/favorite (aggregate (count :*) :count)) (order :created_on :DESC))) (defmacro all [& clauses] `(-> base ~@clauses select)) Here’s the pagination macro: clojure/gratefulplace-dissected/v1/src/gratefulplace/models/helpers.clj4 5 6 7 8 9;; TODO make better! (defmacro paginate ([page num-per-page query] `(~@query (limit ~num-per-page) (offset (dec ~page))))) And here’s the whole thing in action: clojure/gratefulplace-dissected/v1/src/gratefulplace/controllers/posts.clj19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36(defn all [req] (let [current-auth (friend/current-authentication) per-page 20 page (str->int (or (get-in req [:params :page] 1))) conditions (with-visibility current-auth {:moderator true :logged-in (or {:hidden false} {:user_id [= (:id current-auth)]}) :not-logged-in {:hidden false}}) record-count (post/record-count (where conditions))] (view view/all :posts (paginate page per-page (post/all (where conditions))) :record-count record-count :page page :max-pages (ceil (/ record-count per-page))))) I definitely think there’s room for improvement here and would love suggestions. Using fierce mustaches to run tasks So it turns out that you can use leiningen to run tasks, kind of like Rake. As far as I know, it’s not as powerful in that you can’t specify dependencies, but it’s still better than nothing! Here’s a file I wrote to allow me to rebuild and re-seed by db: clojure/gratefulplace-dissected/v1/src/tasks/db.clj 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22(ns tasks.db (:refer-clojure :exclude [alter drop complement bigint boolean char double float time]) (:require [gratefulplace.models.user :as user]) (:use (lobos core connectivity))) (defn rebuild [] (rollback :all) (migrate)) (defn seed [] (println (user/create! {:username "higginbotham" :email "daniel@flyingmachinestudios.com" :display_name "higginbotham" :password "password"}))) (defn -main [task-name] (condp = task-name "rebuild" (rebuild) "seed" (seed))) I ran lein run -m tasks.db rebuild and lein run -m tasks.db seed. Fun utilities Here’s some stuff that was fun to write: clojure/gratefulplace-dissected/v1/src/gratefulplace/utils.clj 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24(ns gratefulplace.utils) (defn str->int ([str] (Integer. str)) ([m & keys] (reduce (fn [m k] (if-let [val (k m)] (assoc m k (str->int val)) m)) m keys))) (defn deserialize [m & ks] (reduce #(assoc % %2 (read-string (%2 %))) m ks)) (defmacro self-unless-fn [self fn otherwise] `(let [self# ~self] (if (~fn self#) ~otherwise self#))) The End And that’s it! I hope you’ve found this useful. I’d love any feedback, so please do leave a comment or tweet me or email me. And like I mentioned above – it’d be great to meet some folks at the Conj next week!

Loving Without Fear

almost 5 years ago | Daniel Higginbotham: Flying Machine Studios

I was sitting at the Cambridge Public Library, and for the first time in months - years? - I felt at peace. In my journal I had just written what's become a kind of mantra for me: "Love without fear." At the time I was going through a very difficult breakup. My relationship of 6 years had been slowly and painfully dissolving, in part because of my own inability to end it decisively. Part of my difficulty what was that I had a lot of guilt over wanting to end the relationship because the person I was with had a long-term illness and I was supporting her both financially and as a kind of house helper or ersatz nurse. I had watched her suffer terribly. I'm not sure how to convey what that was like. How do you share the experience of watching someone you love get a spinal tap? Of wheeling them out of the hospital and to the hotel next door, trying to do it quickly but smoothly because every bump causes excruciating pain? Or how about cleaning the vomit out of a mixing bowl because antibiotics are causing her nausea? Or giving the antibiotics shots yourself, night after night? Or knowing that there was no end in sight? How could I leave someone to face that on her own? After six years, I was in a state of chronic exhaustion and stress. Often I would start my day by sitting at my desk for a couple hours and just staring, not really able to do anything. I knew that something had to change, but I felt too guilty to leave. And, to be completely honest, I was scared about what it might say about me if I left her. Would it mean that I was a callous, heartless person? More, I was scared to live without her. We'd been together for 6 years, and the life I knew was familiar and provided comfort in a way. In the state I was in, I did not feel confident that I could make a large life change. Michael Singer said it well: You will get to a point in your growth where you understand that if you protect yourself, you will never be free. It’s that simple. Because you’re scared, you have locked yourself within your house and pulled down all the shades. Now it’s dark and you want to feel the sunlight, but you can’t. It’s impossible. If you close and protect yourself, you are locking this scared, insecure person within your heart. You will never be free that way. -- The Untethered Soul, by Michael Singer But those words, "love without fear", helped give me strength. Beneath the fear, beneath the raw ache of being a perpetual witness to suffering, I could still feel the beating heart of love. I felt it there, ready, waiting for me without judgment. I felt the desire to open up again, to build honest and meaningful relationships with others. I felt like I had nothing to fear from embracing every moment of life whole-heartedly. The months that followed that day at the library were messy and painful in many ways. But despite many mistakes, I knew that basically I was on the right path, that my heart was opening up more and more and I was learning to love myself and be myself without giving in to my fears of what other people might think or what vague disaster might befall me. Now, more than two and a half years later, I can say without reservation that I took the right path. My life has not been problem-free and I don't ever expect it to be. In embracing love, though, I've learned that freedom and joy can be found in every moment, even when problems do arise. My life has improved as well. Actually, that's a major understatement. My life is freaking awesome right now. About a month ago, I got engaged to the girl I love. A few days ago, I moved out of a drafty, gross old apartment into a beautiful new house that's close enough to my brother and mom to allow me to visit them much more often. And my latest project, something I put together with the idea of lifting up other people, is almost ready to ship. And through it all, I keep telling myself: Love without fear. Love without fear. Love without fear.

Line Charts with d3 js

almost 5 years ago | Aishwarya Singhal: Aishwarya Singhal

Want to do a line chart with d3? There are no ready APIs right? At least none that I could find. What I did find was http://benjchristensen.com/2012/05/02/line-graphs-using-d3-js/ (very useful!) and I hacked up a line chart taking cue from there. … Continue reading →

Line Charts with d3 js

almost 5 years ago | Aishwarya Singhal: Aishwarya Singhal

Want to do a line chart with d3? There are no ready APIs right? At least none that I could find. What I did find was http://benjchristensen.com/2012/05/02/line-graphs-using-d3-js/ (very useful!) and I hacked up a line chart taking cue from there. Here's an example: And the code? <!DOCTYPE html> <html lang="en"> <head> <title>Line Charts</title> <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script> <script src="http://d3js.org/d3.v2.js"></script> <script type="text/javascript"> function getDate(d) { var dt = new Date(d.date); dt.setHours(0); dt.setMinutes(0); dt.setSeconds(0); dt.setMilliseconds(0); return dt; } function showData(obj, d) { var coord = d3.mouse(obj); var infobox = d3.select(".infobox"); // now we just position the infobox roughly where our mouse is infobox.style("left", (coord[0] + 100) + "px" ); infobox.style("top", (coord[1] - 175) + "px"); $(".infobox").html(d); $(".infobox").show(); } function hideData() { $(".infobox").hide(); } var drawChart = function(data) { // define dimensions of graph var m = [20, 40, 20, 100]; // margins var w = 700 - m[1] - m[3]; // width var h = 360 - m[0] - m[2]; // height data.sort(function(a, b) { var d1 = getDate(a); var d2 = getDate(b); if (d1 == d2) return 0; if (d1 > d2) return 1; return -1; }); // get max and min dates - this assumes data is sorted var minDate = getDate(data[0]), maxDate = getDate(data[data.length-1]); var x = d3.time.scale().domain([minDate, maxDate]).range([0, w]); // X scale will fit all values from data[] within pixels 0-w //var x = d3.scale.linear().domain([0, data.length]).range([0, w]); // Y scale will fit values from 0-10 within pixels h-0 (Note the inverted domain for the y-scale: bigger is up!) var y = d3.scale.linear().domain([0, d3.max(data, function(d) { return d.trendingValue; } )]).range([h, 0]); // create a line function that can convert data[] into x and y points var line = d3.svg.line() // assign the X function to plot our line as we wish .x(function(d, i) { // return the X coordinate where we want to plot this datapoint return x(getDate(d)); //x(i); }) .y(function(d) { // return the Y coordinate where we want to plot this datapoint return y(d.trendingValue); }); function xx(e) { return x(getDate(e)); }; function yy(e) { return y(e.trendingValue); }; $("#chart").append("<p><small><em>Please move the mouse over data points to see details.</em></small></p>"); // Add an SVG element with the desired dimensions and margin. var graph = d3.select("#chart").append("svg:svg") .attr("width", w + m[1] + m[3]) .attr("height", h + m[0] + m[2]) .append("svg:g") .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); // create yAxis var xAxis = d3.svg.axis().scale(x).ticks(d3.time.months, 1).tickSize(-h).tickSubdivide(true); // Add the x-axis. graph.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0," + h + ")") .call(xAxis); // create left yAxis var yAxisLeft = d3.svg.axis().scale(y).ticks(10).orient("left"); //.tickFormat(formalLabel); // Add the y-axis to the left graph.append("svg:g") .attr("class", "y axis") .attr("transform", "translate(-25,0)") .call(yAxisLeft); // Add the line by appending an svg:path element with the data line we created above // do this AFTER the axes above so that the line is above the tick-lines graph .selectAll("circle") .data(data) .enter().append("circle") .attr("fill", "steelblue") .attr("r", 5) .attr("cx", xx) .attr("cy", yy) .on("mouseover", function(d) { showData(this, d.trendingValue);}) .on("mouseout", function(){ hideData();}); graph.append("svg:path").attr("d", line(data)); graph.append("svg:text") .attr("x", -200) .attr("y", -90) .attr("dy", ".1em") .attr("transform", "rotate(-90)") .text("Trending Value"); $("#chart").append("<div class='infobox' style='display:none;'>Test</div>"); } var draw = function() { var data = [ {'date': "2012-10-01", 'trendingValue': 1000}, {'date': "2012-09-01", 'trendingValue': 900}, {'date': "2012-08-01", 'trendingValue': 1100}, {'date': "2012-07-01", 'trendingValue': 950}, {'date': "2012-06-01", 'trendingValue': 1050}]; drawChart(data); } </script> <style> #chart path { stroke: steelblue; stroke-width: 2; fill: none; } .axis { shape-rendering: crispEdges; } .x.axis line { stroke: lightgrey; } .x.axis .minor { stroke-opacity: .5; } .x.axis path { display: none; } .y.axis line, .y.axis path { fill: none; stroke: #000; } .infobox { border:2px solid steelblue; border-radius:4px; box-shadow:#333333 0px 0px 10px; margin:200px auto; padding:5px 10px; background:rgba(255, 255, 255, 0.8); position:absolute; top:0px; left:0px; z-index:10500; font-weight:bold; } </style> </head> <body onload="draw();"> <div id="chart"> </div> </body> </html>