fix submodule, restore blog source

master
Chakib (spike) Benziane 11 years ago
parent 91ae427551
commit 018af4861d

2
.gitmodules vendored

@ -12,7 +12,7 @@
url = https://github.com/FortAwesome/Font-Awesome.git
[submodule "lib/lesshat"]
path = lib/lesshat
url = https://github.com/CSSHat/LESSHat.git
url = https://github.com/csshat/lesshat.git
[submodule "projects/bootstrap-magic-button"]
path = projects/bootstrap-magic-button
url = https://github.com/sp4ke/bootstrap-magic-button.git

@ -1 +0,0 @@
sp4ke.com

@ -1,2 +0,0 @@
source 'https://rubygems.org'
gem 'github-pages'

@ -1,62 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
RedCloth (4.2.9)
blankslate (2.1.2.4)
classifier (1.3.3)
fast-stemmer (>= 1.0.0)
colorator (0.1)
commander (4.1.5)
highline (~> 1.6.11)
fast-stemmer (1.0.2)
ffi (1.9.3)
github-pages (12)
RedCloth (= 4.2.9)
jekyll (= 1.4.2)
kramdown (= 1.2.0)
liquid (= 2.5.4)
maruku (= 0.7.0)
rdiscount (= 2.1.7)
redcarpet (= 2.3.0)
highline (1.6.20)
jekyll (1.4.2)
classifier (~> 1.3)
colorator (~> 0.1)
commander (~> 4.1.3)
liquid (~> 2.5.2)
listen (~> 1.3)
maruku (~> 0.7.0)
pygments.rb (~> 0.5.0)
redcarpet (~> 2.3.0)
safe_yaml (~> 0.9.7)
toml (~> 0.1.0)
kramdown (1.2.0)
liquid (2.5.4)
listen (1.3.1)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
rb-kqueue (>= 0.2)
maruku (0.7.0)
parslet (1.5.0)
blankslate (~> 2.0)
posix-spawn (0.3.8)
pygments.rb (0.5.4)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
rb-fsevent (0.9.3)
rb-inotify (0.9.3)
ffi (>= 0.5.0)
rb-kqueue (0.2.0)
ffi (>= 0.5.0)
rdiscount (2.1.7)
redcarpet (2.3.0)
safe_yaml (0.9.7)
toml (0.1.0)
parslet (~> 1.5.0)
yajl-ruby (1.1.0)
PLATFORMS
ruby
DEPENDENCIES
github-pages

@ -1,35 +0,0 @@
#
# BUILD Bootstrap theme
#
#
##TODO:
# Add compressing and jshint
OUTPUT = css/bootstrap.css
OUTPUT_MIN = css/bootstrap.min.css
LESS = less/compile.less
HR=\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#\#
CHECK=\033[32m✔\033[39m
build:
@echo "\n${HR}"
@echo "Building bootstrap theme ..."
@recess --compile ${LESS} > ${OUTPUT}
@lessc --compress ${LESS} > ${OUTPUT_MIN}
@echo "Compiling LESS with Recess... ${CHECK} Done"
## Responsive
# #lessc swatchmaker-responsive.less > ${OUTPUT_PATH}/bootstrap-responsive.css
# #lessc --compress swatchmaker-responsive.less > ${OUTPUT_PATH}/bootstrap-responsive.min.css
#
bootstrap:
@make -C ./lib/bootstrap build
clean:
@rm -rf ${OUTPUT} ${OUTPUT_MIN}
.PHONY: build bootstrap

@ -1,195 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Development as a Service on its baby steps - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Development as a Service on Its Baby Steps Let me start by presenting a new web service pythonanywhere.com. It&#8217;s a full python development &hellip;">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blog/Development-as-a-Service/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner"><article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h1 class="title" itemprop="name">Development as a Service on Its Baby Steps</h1>
<div class="entry-content" itemprop="articleBody"><p>Let me start by presenting a new web service <a href="http://www.pythonanywhere.com/">pythonanywhere.com</a>.</p>
<p>It&#8217;s a full python development stack, ready to be used in your browser. After a quick subscription for a free account,
you have access from your dashboard to [python, ipython, bash] consoles in different python flavours.</p>
<p>You can also browse your files, make cron scripts and create python web apps on the fly.</p>
<p>The most interesting features are the consoles pause/resume feature, which can be shared
with other people. This could be very helpful to collaborate on code or teach python.
Behind the scene, it&#8217;s an encrypted ajax window over your home folder running on a remote server hosted on EC2.</p>
<p>DaaS may be on it&#8217;s first baby steps. Though, it could rapidly become a standard way to code for developers especially in startups.
Before diving in the pros and cons, let&#8217;s analyse the different development stacks possibilities.</p>
<!-- more -->
<p>First, there&#8217;s the good old fashion way. Setup a server on a cloud service
(I guess there&#8217;s still people doing it with bare metal servers ). You have plenty of choice there, (EC2, AppEngine, Azure, Rackspace&#8230;),
it depends on your IT needs, spiritual beliefs (many don&#8217;t care) and your pockets.</p>
<p>Then pick the development stack of your preferred language/framework: Python(Django, Web2py, Pylons, Flask&#8230;), Ruby(Ruby On Rails) for the rock stars, Java/.Net, PHP &#8230;</p>
<p>Here, you have to maintain every piece involved in the process, packages versions, build tools, deployment, scaling. That&#8217;s a lot of time and resources needed to finally get your developers pushing and your apps running.</p>
<p>The next big step was the <a href="http://www.heroku.com">Heroku</a> and <a href="http://www.dotcloud.com"> Dotcloud </a> like services, aka Deployment/Scaling as a Service.
They release from the burden of deploying and give enough abstraction to exclusively focus your effort on the application logic.
The process is often the same, basically setup your project with a simple conf file, then deploy to the server with one command.
They practically all handle version control systems like git,
so your project is deployed every time you push your code.
I believe Github helped a lot making these services exist as deployment is often tightly bound to code revisions, and Github offers an excellent API and a huge community.</p>
<p>We have been adding more and more abstraction to the development process in order to make it easier, faster, stronger &#8230;
However, there is still one constant, &#8220;localhost development&#8221;. The coding itself is done on your machine/laptop.You still can use your favourite OS, IDE, tools.</p>
<p>Well, DaaS is going to cross that last barrier.
There are already several web services for online development like <a href="http://jsfiddle.net">jsfiddle.net</a> for web design or <a href="http://koding.com">koding.com</a>.
They offer something that could change the way we see development, the abstraction of your OS, ide and development environment.
If you think about it, that&#8217;s a lot of time saved. No multi-platform mess, no more scripts to ensure the same development stack. Using the enormous processing power
of cloud platforms, there is virtually no compile time. You can even forget about your machine, all you need is a keyboard and a screen.</p>
<p>It seems only benefit but the thing is, if DaaS is really going to be the next step,I think we are missing something very important.
Before a developer learns to code, he has
to understand the building blocks of programming, what&#8217;s a computer, what&#8217;s an Operating System, how does it do its work. All the abstractions we built are built
using this knowledge. How could a programmer understand code optimization ? Security flows?
How could he understand the interaction of his code with its environment if he&#8217;s not gonna use it?
Maybe we&#8217;re not concreted with that yet, but the next generations of programmers are.</p>
<p>What do you think ?</p>
</div>
</article>
<section id="comment">
<h1 class="title">Comments</h1>
<div id="disqus_thread" aria-live="polite"><noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</section>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
// var disqus_developer = 1;
var disqus_identifier = 'http://sp4ke.github.com/blog/Development-as-a-Service/';
var disqus_url = 'http://sp4ke.github.com/blog/Development-as-a-Service/';
var disqus_script = 'embed.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,319 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[]]></title>
<link href="http://sp4ke.github.com/blog/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[My most valuable lesson in life learnt the hard way]]></title>
<link href="http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/"/>
<updated>2013-04-18T11:51:00+02:00</updated>
<id>http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way</id>
<content type="html"><![CDATA[<p>Hollywood movies are often introduced with a main character living his life until a big event happens,
something that is enough life changing to justify a compelling story. And we, as an audience,
tend to identify to that hero or some event in the story that helps us forget the boredom of real life.
I believe this is one of the secret ingredients that make the movies industry so successful.
People need to forget about their daily life because they believe it&#8217;s boring.
In the timespan of <a href="http://www.slashfilm.com/by-the-numbers-the-length-of-feature-films/2/">159 minutes</a> they are thrilled in something more exciting, adventurous, romantic &#8230;
everything that does not seem to exist in &#8220;real life&#8221;.</p>
<!-- more -->
<p>I love movies and cinema, and I really enjoy seeing a good one. However, something have always kept me a bit skeptical about the whole phenomenon.
In my sight, real life is more exciting, there&#8217;s an infinite amount of possibilities
and outcomes to what you do. Everything seem possible when you stop picturing your
actions and ideas <a href="http://www.youtube.com/watch?v=lVeSLFgcKkw">in the way society expects you to do</a>. This feeling has started filling me since I was a teenager.
It forged my personality and made me what I have been until now. People nowadays call it being an &#8220;entrepreneur&#8221; or &#8220;hacker&#8221;.
I don&#8217;t think any word could describe the way I feel about my life and my role in the current society.</p>
<p>I left my country 6 years ago and came to France in order to study computer science.
I had been to medical school before, trying to follow my dad&#8217;s footsteps.
My path through my studies has been the same thing as it has always been my whole life:
trying new things, never settle down at the same place, always thinking of the next project
and moving forward. As an immigrant student I have done many little jobs, worked for big IT
companies ( although I was not always allowed to ), joined a prestigious computer school club
where I learned so much about sysadmin in system engineering and met many people.
Still, I was always feeling something missing. Deep inside, there was a voice who has been there since the beginning.
It kept telling me what
I needed to do. I was working as a system engineer on a short term contract when a friend
(at the time) offered me to start our own startup where I would be responsible for all the
technical aspect. When I think about it now, the idea was not that attractive,
there was no business plan and we were just a team of three guys without any previous experience in
the startup business. It was one of the most important choices I had to do.
Either decline a comfortable job offer which would&#8217;ve let me acquire a legal worker
status and finish my studies working with cool technologies, and maybe even travelling.
Or jumping right into the startup adventure, with no guaranty of success, no market
research whatsoever, and no immigration status possible especially in France which
is about ten years far from a Startup Act .</p>
<p>Flash forward, I am co-founder and CTO at jib.li. Many things happened since and
long story made short, we made a pivot and had new people in the team.
I will share this story with my friend and co-founder Ryadh in an other article,
a story which I think every foreign entrepreneur to France should know about.
For the time being, Jib.li has been launched 6 months ago, had some worldwide press and
media coverage, and is currently one of the first crowd-shipping/shopping platforms.</p>
<p>Then comes last week. Something big happened. Actually it was a succession of
events that, taken alone could be considered probable, but thinking they would happen all
at the same time in the lapse of a few days made them what we define as &#8220;life changing&#8221; events.
They are totally unrelated, each having a huge impact in some aspect of my personal and
professional life. But still, they are all connected together with the same variable
that makes them what I feel like being born in a new life.</p>
<p>Each one of these events could be considered a failed, depressing twist filled with despair.
In fact, they made me feel that way and I could barely sleep at night, always feeling a pain
in my stomach like I have been punched in the nuts. I am not enough comfortable to talk about
the personal one and the next articles will explain the rest of the story. What really matters
here is the key denominator, something I can now consider, with confidence, as the most important factor in any
future project and my whole new life. I am talking about <em>Trust</em>. Of course, it seems obvious !
Well I taught it was too.</p>
<p>The history of humanity has been shaped by trust. You can&#8217;t build a pyramid if
you can&#8217;t trust the architect. You can&#8217;t build an army when people don&#8217;t trust you. You can&#8217;t learn if you don&#8217;t
trust a teacher or a mentor, and you can&#8217;t found a family if you don&#8217;t trust a partner&#8230;
It is something that must be earned. Something you can&#8217;t afford with money and power. Something you can
fake with lies and charisma . I am now convinced the only way to find trust is to look for <em>Passion</em> inside people and that every human
being have to learn it the hard way. You must be betrayed in order to acknowledge it&#8217;s worth. I sincerely hope for
you it won&#8217;t be the same as me, but I can say for sure this was my life changing event.
Anything that will come after will be different and I am very thankful I was given this precious lesson in my youth.</p>
<p>I don&#8217;t know what words could describe the aftermath. I feel new, free, light.
I feel a strength rising inside me, like the power to shape the future. I still have so many
things to learn and experience, and the pains that come with it. <a href="http://www.bbc.co.uk/programmes/p00ynyl7">Entropy</a> makes
life beautiful, the uncertainty built in the entire universe makes our lives much more interesting than any Hollywood movie.</p>
<p>Good luck to all those who create, make and change things, and for anyone else, just listen to the voice speaking to you.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Redesigning jibli - lessons learned form Hack Design Part 1]]></title>
<link href="http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/"/>
<updated>2013-03-06T20:01:00+01:00</updated>
<id>http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1</id>
<content type="html"><![CDATA[<p>As many programmers, I have always thought web design is a
discipline best reserved for people doing art and design.
You know, the hipster with his MacBook, his pletora of Adobe suites,
and the huge time spent learning to use them.</p>
<p>I come from a background of system administration and networking, always
fascinated by the obscure backend&#8217;s thing happening behind what you
see on your screen. Furthermore, I started web development for the sole purpose
of building <a href="http://jib.li">Jib.li</a>, as a CoFounder and CTO on this
project, and as a team which had no money to hire a full time designer.</p>
<p>Needless to say I boarded the UI Design ship on the wrong foot.</p>
<p>In this first article I am going to share my experience on how I got passionate
about creating and designing a User Interface and what I learned from all the
resources shared on HN and <a href="http://hackdesign.org/courses/"> Hack Design </a> lessons which helped me redesign Jib.li.</p>
<!-- more -->
<h4>Before</h4>
<p><img class="hover center" src="http://sp4ke.github.com/blog/images/jibli_old.png" width="390"></p>
<h4>After</h4>
<p><img class="hover center" src="http://sp4ke.github.com/blog/images/jibli_new.png" width="400"></p>
<h2>Where to start ?</h2>
<p>We launched the public beta of jib.li on October 2012. A few weeks later we had had
plenty of feedback and proposals for new features.</p>
<p>For strategic reasons, we chose to start Jib.li with no registering process and just a &#8220;Connect with Facebook&#8221; instead.</p>
<p>We had no money to make a &#8220;how it works&#8221; video we could show
next to the home page form, like many startups do when they launch their
product. We only had a <a href="http://www.youtube.com/watch?v=KOYTefUmygA" title="Jib.li teaser video">teaser video</a> that we made before starting this project
where you see a bunch of people (our team at that time) pitching the idea.</p>
<p>The home page actually <a href="http://jib.li/homeold" title="Some styles are a little broken since we're migrating to the new design"> looked </a> like many location based services and the
typical workflow of a user was:</p>
<ol>
<li><p>Fill in the &#8220;From&#8221; and &#8220;To&#8221; location fields</p></li>
<li><p>Choose what action to take: Send, Deliver</p></li>
<li><p>A modal shows up to let him select a date depending on which action he chose</p></li>
<li><p>Redirecting the user to a listings results page</p></li>
<li><p>The user can then click on listings or create a new one if he&#8217;s not satisified</p></li>
</ol>
<p>We noticed that many people when they first reached the home page, where not able to figure out what to do next.
To assist new users we used bootstrap tooltips everywhere, even on the action buttons.</p>
<p>On the graphic design aspect, we were just using a slightly customized <a href="http://bootswatch.com/cerulean/"> bootstrap theme </a></p>
<h2>Getting inspiration</h2>
<p>So after we decided it was time to have a fresh and better look, I saw the opportunity
to start practicing what I have been learning on HN, Hack Design and <a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111"> About Face 3 </a> about
UI/UX Design. It was also a good opportunity to stop frontend programming with spaghetti jQuery dom
manipulation and start using AngularJS which devprived me of my sleep hours lately.
(frontend programming will be the subject of an other article)</p>
<p>I think the most difficult step when you start working on something, no matter what kind
of project, is actually to <strong>start</strong>. For me it was no exception. I was certainly looking
for visual inspiration because a User Interface for a web application is first of all something
we see before we touch and interact with.</p>
<p>To help me filter out the overwhelming quantity of images, photos and visuals available on the internet,
I made list of words that sum up what Jib.li was about and started combining those words in search queries
for images and photos.</p>
<p>I ended up with this one when looking for the words <em>bike</em> and <em>bag</em>, which seemed to summarize the ideas
of transportation, carrying and environment which jib.li is all about.</p>
<p><img class="center" src="http://sp4ke.github.com/blog/images/hero_bike.jpg" width="300"></p>
<p><em>This photo comes from this <a href="http://letsgorideabike.com/blog/2011/03/beautiful-bicycles-yuba-mundo-cargo-bike/#comment-823035149"> beautiful article </a> by Dottie and all credits go to her.</em></p>
<p>When I saw this one ideas started immediately flowing and I knew where to start.</p>
<h2>The color palette</h2>
<p>The first thing I did was to choose a color palette. To do so, I used the inspiration photo
to <a href="http://vimeo.com/7109253"> extract a simple color palette.</a></p>
<p><img class="right" src="http://sp4ke.github.com/blog/images/color_swatch.jpg"></p>
<p>I actually repeated the process until I get a set of colors which validate these conditions:</p>
<ul>
<li>Have at most 3 main colors</li>
<li>Have dark close to black color</li>
<li>Have a light close to white color</li>
</ul>
<p>This one has two main colors, a wide blue range and the yellow/gold one. Grays and white are
just desaturated and very light colors.</p>
<p>This should suffice to always have a color to pick from this palette instead of choosing
one from a color picker, and so basically when looking for black I just choose the darkest one and when looking for white I pick
the most close to white.</p>
<p>The wide range of blue colors made me choose the blue as the main color.</p>
<p>I was heavily inspired by this <a href="http://ianstormtaylor.com/design-tip-never-use-black/"> article </a> of Ian Storm Taylor, which also made me
start using HSL (Hue, Saturation, Brightness) everywhere I wanted to get new colors from the palette.</p>
<h2>Rapid prototyping vs flat PSD design</h2>
<p>One thing I learned in interactive design is that a User Interface can&#8217;t possibly be represented as a flat image only.
<a href="http://www.youtube.com/watch?v=PUv66718DII"> Bret Victor made an excellent talk </a> about the process of creation and the necessity to get immediate visual feedback.
My design process has been a mix of rapid prototyping and design exploration with <a href="https://developers.google.com/chrome-developer-tools/"> chrome developers tools </a> then representing ideas in
a PSD file as a reference for later.</p>
<p>Although I&#8217;m not going to talk much about frontend programming, this is the stack I prepared to quickly test ideas and move back and forth
from prototype to PSD.</p>
<p><a href="https://github.com/sp4ke/Angustrap.git"> The stack </a> consists of:</p>
<ul>
<li>Angular Seed project from AngularJS</li>
<li>Stylesheets using Less</li>
<li>Using git submodules to add frontend dependencies (Bootstrap, AngularUI, FontAwesome &#8230; )</li>
</ul>
<p>Whenever I wanted to test some <em>behavior</em> feature I first tested it with Chrome, played
with styles and interactions, then tried to represent it as a layer in PSD.</p>
<p>On the other hand, when trying to work on the <em>look</em> aspect of something, I prefered the PSD
approach first, which gives more freedom on the graphics.</p>
<p><img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_1.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_2.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_3.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_4.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_5.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_6.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_7.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_8.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_9.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_10.jpg" width="50">
<img class="hover" src="http://sp4ke.github.com/blog/images/jibli_design_11.jpg" width="50"></p>
<h2>End of Part 1</h2>
<p>I hope some programmers who are interested about web design and don&#8217;t know how
to start might find some insight from this article and the next ones.</p>
<p>Part 2 will be about getting from prototype to stylesheets using chrome devtools, the importance of shadows and
some tips I learned about textures and details.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Development as a Service on its baby steps]]></title>
<link href="http://sp4ke.github.com/blog/Development-as-a-Service/"/>
<updated>2012-04-29T20:26:09+02:00</updated>
<id>http://sp4ke.github.com/blog/Development-as-a-Service</id>
<content type="html"><![CDATA[<p>Let me start by presenting a new web service <a href="http://www.pythonanywhere.com/">pythonanywhere.com</a>.</p>
<p>It&#8217;s a full python development stack, ready to be used in your browser. After a quick subscription for a free account,
you have access from your dashboard to [python, ipython, bash] consoles in different python flavours.</p>
<p>You can also browse your files, make cron scripts and create python web apps on the fly.</p>
<p>The most interesting features are the consoles pause/resume feature, which can be shared
with other people. This could be very helpful to collaborate on code or teach python.
Behind the scene, it&#8217;s an encrypted ajax window over your home folder running on a remote server hosted on EC2.</p>
<p>DaaS may be on it&#8217;s first baby steps. Though, it could rapidly become a standard way to code for developers especially in startups.
Before diving in the pros and cons, let&#8217;s analyse the different development stacks possibilities.</p>
<!-- more -->
<p>First, there&#8217;s the good old fashion way. Setup a server on a cloud service
(I guess there&#8217;s still people doing it with bare metal servers ). You have plenty of choice there, (EC2, AppEngine, Azure, Rackspace&#8230;),
it depends on your IT needs, spiritual beliefs (many don&#8217;t care) and your pockets.</p>
<p>Then pick the development stack of your preferred language/framework: Python(Django, Web2py, Pylons, Flask&#8230;), Ruby(Ruby On Rails) for the rock stars, Java/.Net, PHP &#8230;</p>
<p>Here, you have to maintain every piece involved in the process, packages versions, build tools, deployment, scaling. That&#8217;s a lot of time and resources needed to finally get your developers pushing and your apps running.</p>
<p>The next big step was the <a href="http://www.heroku.com">Heroku</a> and <a href="http://www.dotcloud.com"> Dotcloud </a> like services, aka Deployment/Scaling as a Service.
They release from the burden of deploying and give enough abstraction to exclusively focus your effort on the application logic.
The process is often the same, basically setup your project with a simple conf file, then deploy to the server with one command.
They practically all handle version control systems like git,
so your project is deployed every time you push your code.
I believe Github helped a lot making these services exist as deployment is often tightly bound to code revisions, and Github offers an excellent API and a huge community.</p>
<p>We have been adding more and more abstraction to the development process in order to make it easier, faster, stronger &#8230;
However, there is still one constant, &#8220;localhost development&#8221;. The coding itself is done on your machine/laptop.You still can use your favourite OS, IDE, tools.</p>
<p>Well, DaaS is going to cross that last barrier.
There are already several web services for online development like <a href="http://jsfiddle.net">jsfiddle.net</a> for web design or <a href="http://koding.com">koding.com</a>.
They offer something that could change the way we see development, the abstraction of your OS, ide and development environment.
If you think about it, that&#8217;s a lot of time saved. No multi-platform mess, no more scripts to ensure the same development stack. Using the enormous processing power
of cloud platforms, there is virtually no compile time. You can even forget about your machine, all you need is a keyboard and a screen.</p>
<p>It seems only benefit but the thing is, if DaaS is really going to be the next step,I think we are missing something very important.
Before a developer learns to code, he has
to understand the building blocks of programming, what&#8217;s a computer, what&#8217;s an Operating System, how does it do its work. All the abstractions we built are built
using this knowledge. How could a programmer understand code optimization ? Security flows?
How could he understand the interaction of his code with its environment if he&#8217;s not gonna use it?
Maybe we&#8217;re not concreted with that yet, but the next generations of programmers are.</p>
<p>What do you think ?</p>
]]></content>
</entry>
</feed>

@ -1,200 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Blog Archives - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="2013 Apr 18 entrepreneurship, experience, life My most valuable lesson in life learnt the hard way Mar 6 UI Design, jib.li Redesigning jibli - &hellip;">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blog/blog/archives/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner"><div itemscope itemtype="http://schema.org/Blog">
<section class="archives"><h1 class="year">2013</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-04-18T11:51:00+02:00" itemprop="datePublished">Apr 18</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/entrepreneurship/'>entrepreneurship</a>, <a class='category' href='/blog/blog/categories/experience/'>experience</a>, <a class='category' href='/blog/blog/categories/life/'>life</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/">My most valuable lesson in life learnt the hard way</a></h1>
</article>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-03-06T20:01:00+01:00" itemprop="datePublished">Mar 6</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/ui-design/'>UI Design</a>, <a class='category' href='/blog/blog/categories/jib-li/'>jib.li</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/">Redesigning jibli - lessons learned form Hack Design Part 1</a></h1>
</article>
</section>
<section class="archives"><h1 class="year">2012</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2012-04-29T20:26:09+02:00" itemprop="datePublished">Apr 29</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/it/'>IT</a>, <a class='category' href='/blog/blog/categories/programming/'>programming</a>, <a class='category' href='/blog/blog/categories/python/'>python</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/Development-as-a-Service/">Development as a Service on its baby steps</a></h1>
</article>
</section>
</div></div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,99 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: entrepreneurship | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/entrepreneurship/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[My most valuable lesson in life learnt the hard way]]></title>
<link href="http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/"/>
<updated>2013-04-18T11:51:00+02:00</updated>
<id>http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way</id>
<content type="html"><![CDATA[<p>Hollywood movies are often introduced with a main character living his life until a big event happens,
something that is enough life changing to justify a compelling story. And we, as an audience,
tend to identify to that hero or some event in the story that helps us forget the boredom of real life.
I believe this is one of the secret ingredients that make the movies industry so successful.
People need to forget about their daily life because they believe it's boring.
In the timespan of <a href="http://www.slashfilm.com/by-the-numbers-the-length-of-feature-films/2/">159 minutes</a> they are thrilled in something more exciting, adventurous, romantic ...
everything that does not seem to exist in "real life".</p>
<!-- more -->
<p>I love movies and cinema, and I really enjoy seeing a good one. However, something have always kept me a bit skeptical about the whole phenomenon.
In my sight, real life is more exciting, there's an infinite amount of possibilities
and outcomes to what you do. Everything seem possible when you stop picturing your
actions and ideas <a href="http://www.youtube.com/watch?v=lVeSLFgcKkw">in the way society expects you to do</a>. This feeling has started filling me since I was a teenager.
It forged my personality and made me what I have been until now. People nowadays call it being an "entrepreneur" or "hacker".
I don't think any word could describe the way I feel about my life and my role in the current society.</p>
<p>I left my country 6 years ago and came to France in order to study computer science.
I had been to medical school before, trying to follow my dad's footsteps.
My path through my studies has been the same thing as it has always been my whole life:
trying new things, never settle down at the same place, always thinking of the next project
and moving forward. As an immigrant student I have done many little jobs, worked for big IT
companies ( although I was not always allowed to ), joined a prestigious computer school club
where I learned so much about sysadmin in system engineering and met many people.
Still, I was always feeling something missing. Deep inside, there was a voice who has been there since the beginning.
It kept telling me what
I needed to do. I was working as a system engineer on a short term contract when a friend
(at the time) offered me to start our own startup where I would be responsible for all the
technical aspect. When I think about it now, the idea was not that attractive,
there was no business plan and we were just a team of three guys without any previous experience in
the startup business. It was one of the most important choices I had to do.
Either decline a comfortable job offer which would've let me acquire a legal worker
status and finish my studies working with cool technologies, and maybe even travelling.
Or jumping right into the startup adventure, with no guaranty of success, no market
research whatsoever, and no immigration status possible especially in France which
is about ten years far from a Startup Act .</p>
<p>Flash forward, I am co-founder and CTO at jib.li. Many things happened since and
long story made short, we made a pivot and had new people in the team.
I will share this story with my friend and co-founder Ryadh in an other article,
a story which I think every foreign entrepreneur to France should know about.
For the time being, Jib.li has been launched 6 months ago, had some worldwide press and
media coverage, and is currently one of the first crowd-shipping/shopping platforms.</p>
<p>Then comes last week. Something big happened. Actually it was a succession of
events that, taken alone could be considered probable, but thinking they would happen all
at the same time in the lapse of a few days made them what we define as "life changing" events.
They are totally unrelated, each having a huge impact in some aspect of my personal and
professional life. But still, they are all connected together with the same variable
that makes them what I feel like being born in a new life.</p>
<p>Each one of these events could be considered a failed, depressing twist filled with despair.
In fact, they made me feel that way and I could barely sleep at night, always feeling a pain
in my stomach like I have been punched in the nuts. I am not enough comfortable to talk about
the personal one and the next articles will explain the rest of the story. What really matters
here is the key denominator, something I can now consider, with confidence, as the most important factor in any
future project and my whole new life. I am talking about <em>Trust</em>. Of course, it seems obvious !
Well I taught it was too.</p>
<p>The history of humanity has been shaped by trust. You can't build a pyramid if
you can't trust the architect. You can't build an army when people don't trust you. You can't learn if you don't
trust a teacher or a mentor, and you can't found a family if you don't trust a partner...
It is something that must be earned. Something you can't afford with money and power. Something you can
fake with lies and charisma . I am now convinced the only way to find trust is to look for <em>Passion</em> inside people and that every human
being have to learn it the hard way. You must be betrayed in order to acknowledge it's worth. I sincerely hope for
you it won't be the same as me, but I can say for sure this was my life changing event.
Anything that will come after will be different and I am very thankful I was given this precious lesson in my youth.</p>
<p>I don't know what words could describe the aftermath. I feel new, free, light.
I feel a strength rising inside me, like the power to shape the future. I still have so many
things to learn and experience, and the pains that come with it. <a href="http://www.bbc.co.uk/programmes/p00ynyl7">Entropy</a> makes
life beautiful, the uncertainty built in the entire universe makes our lives much more interesting than any Hollywood movie.</p>
<p>Good luck to all those who create, make and change things, and for anyone else, just listen to the voice speaking to you.</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: entrepreneurship - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: entrepreneurship">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/entrepreneurship/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2013</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-04-18T11:51:00+02:00" itemprop="datePublished">Apr 18</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/entrepreneurship/'>entrepreneurship</a>, <a class='category' href='/blog/blog/categories/experience/'>experience</a>, <a class='category' href='/blog/blog/categories/life/'>life</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/">My most valuable lesson in life learnt the hard way</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,99 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: experience | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/experience/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[My most valuable lesson in life learnt the hard way]]></title>
<link href="http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/"/>
<updated>2013-04-18T11:51:00+02:00</updated>
<id>http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way</id>
<content type="html"><![CDATA[<p>Hollywood movies are often introduced with a main character living his life until a big event happens,
something that is enough life changing to justify a compelling story. And we, as an audience,
tend to identify to that hero or some event in the story that helps us forget the boredom of real life.
I believe this is one of the secret ingredients that make the movies industry so successful.
People need to forget about their daily life because they believe it's boring.
In the timespan of <a href="http://www.slashfilm.com/by-the-numbers-the-length-of-feature-films/2/">159 minutes</a> they are thrilled in something more exciting, adventurous, romantic ...
everything that does not seem to exist in "real life".</p>
<!-- more -->
<p>I love movies and cinema, and I really enjoy seeing a good one. However, something have always kept me a bit skeptical about the whole phenomenon.
In my sight, real life is more exciting, there's an infinite amount of possibilities
and outcomes to what you do. Everything seem possible when you stop picturing your
actions and ideas <a href="http://www.youtube.com/watch?v=lVeSLFgcKkw">in the way society expects you to do</a>. This feeling has started filling me since I was a teenager.
It forged my personality and made me what I have been until now. People nowadays call it being an "entrepreneur" or "hacker".
I don't think any word could describe the way I feel about my life and my role in the current society.</p>
<p>I left my country 6 years ago and came to France in order to study computer science.
I had been to medical school before, trying to follow my dad's footsteps.
My path through my studies has been the same thing as it has always been my whole life:
trying new things, never settle down at the same place, always thinking of the next project
and moving forward. As an immigrant student I have done many little jobs, worked for big IT
companies ( although I was not always allowed to ), joined a prestigious computer school club
where I learned so much about sysadmin in system engineering and met many people.
Still, I was always feeling something missing. Deep inside, there was a voice who has been there since the beginning.
It kept telling me what
I needed to do. I was working as a system engineer on a short term contract when a friend
(at the time) offered me to start our own startup where I would be responsible for all the
technical aspect. When I think about it now, the idea was not that attractive,
there was no business plan and we were just a team of three guys without any previous experience in
the startup business. It was one of the most important choices I had to do.
Either decline a comfortable job offer which would've let me acquire a legal worker
status and finish my studies working with cool technologies, and maybe even travelling.
Or jumping right into the startup adventure, with no guaranty of success, no market
research whatsoever, and no immigration status possible especially in France which
is about ten years far from a Startup Act .</p>
<p>Flash forward, I am co-founder and CTO at jib.li. Many things happened since and
long story made short, we made a pivot and had new people in the team.
I will share this story with my friend and co-founder Ryadh in an other article,
a story which I think every foreign entrepreneur to France should know about.
For the time being, Jib.li has been launched 6 months ago, had some worldwide press and
media coverage, and is currently one of the first crowd-shipping/shopping platforms.</p>
<p>Then comes last week. Something big happened. Actually it was a succession of
events that, taken alone could be considered probable, but thinking they would happen all
at the same time in the lapse of a few days made them what we define as "life changing" events.
They are totally unrelated, each having a huge impact in some aspect of my personal and
professional life. But still, they are all connected together with the same variable
that makes them what I feel like being born in a new life.</p>
<p>Each one of these events could be considered a failed, depressing twist filled with despair.
In fact, they made me feel that way and I could barely sleep at night, always feeling a pain
in my stomach like I have been punched in the nuts. I am not enough comfortable to talk about
the personal one and the next articles will explain the rest of the story. What really matters
here is the key denominator, something I can now consider, with confidence, as the most important factor in any
future project and my whole new life. I am talking about <em>Trust</em>. Of course, it seems obvious !
Well I taught it was too.</p>
<p>The history of humanity has been shaped by trust. You can't build a pyramid if
you can't trust the architect. You can't build an army when people don't trust you. You can't learn if you don't
trust a teacher or a mentor, and you can't found a family if you don't trust a partner...
It is something that must be earned. Something you can't afford with money and power. Something you can
fake with lies and charisma . I am now convinced the only way to find trust is to look for <em>Passion</em> inside people and that every human
being have to learn it the hard way. You must be betrayed in order to acknowledge it's worth. I sincerely hope for
you it won't be the same as me, but I can say for sure this was my life changing event.
Anything that will come after will be different and I am very thankful I was given this precious lesson in my youth.</p>
<p>I don't know what words could describe the aftermath. I feel new, free, light.
I feel a strength rising inside me, like the power to shape the future. I still have so many
things to learn and experience, and the pains that come with it. <a href="http://www.bbc.co.uk/programmes/p00ynyl7">Entropy</a> makes
life beautiful, the uncertainty built in the entire universe makes our lives much more interesting than any Hollywood movie.</p>
<p>Good luck to all those who create, make and change things, and for anyone else, just listen to the voice speaking to you.</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: experience - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: experience">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/experience/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2013</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-04-18T11:51:00+02:00" itemprop="datePublished">Apr 18</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/entrepreneurship/'>entrepreneurship</a>, <a class='category' href='/blog/blog/categories/experience/'>experience</a>, <a class='category' href='/blog/blog/categories/life/'>life</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/">My most valuable lesson in life learnt the hard way</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: IT | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/it/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Development as a Service on its baby steps]]></title>
<link href="http://sp4ke.github.com/blog/Development-as-a-Service/"/>
<updated>2012-04-29T20:26:09+02:00</updated>
<id>http://sp4ke.github.com/blog/Development-as-a-Service</id>
<content type="html"><![CDATA[<p>Let me start by presenting a new web service <a href="http://www.pythonanywhere.com/">pythonanywhere.com</a>.</p>
<p>It's a full python development stack, ready to be used in your browser. After a quick subscription for a free account,
you have access from your dashboard to [python, ipython, bash] consoles in different python flavours.</p>
<p>You can also browse your files, make cron scripts and create python web apps on the fly.</p>
<p>The most interesting features are the consoles pause/resume feature, which can be shared
with other people. This could be very helpful to collaborate on code or teach python.
Behind the scene, it's an encrypted ajax window over your home folder running on a remote server hosted on EC2.</p>
<p>DaaS may be on it's first baby steps. Though, it could rapidly become a standard way to code for developers especially in startups.
Before diving in the pros and cons, let's analyse the different development stacks possibilities.</p>
<!-- more -->
<p>First, there's the good old fashion way. Setup a server on a cloud service
(I guess there's still people doing it with bare metal servers ). You have plenty of choice there, (EC2, AppEngine, Azure, Rackspace...),
it depends on your IT needs, spiritual beliefs (many don't care) and your pockets.</p>
<p>Then pick the development stack of your preferred language/framework: Python(Django, Web2py, Pylons, Flask...), Ruby(Ruby On Rails) for the rock stars, Java/.Net, PHP ...</p>
<p>Here, you have to maintain every piece involved in the process, packages versions, build tools, deployment, scaling. That's a lot of time and resources needed to finally get your developers pushing and your apps running.</p>
<p>The next big step was the <a href="http://www.heroku.com">Heroku</a> and <a href="http://www.dotcloud.com"> Dotcloud </a> like services, aka Deployment/Scaling as a Service.
They release from the burden of deploying and give enough abstraction to exclusively focus your effort on the application logic.
The process is often the same, basically setup your project with a simple conf file, then deploy to the server with one command.
They practically all handle version control systems like git,
so your project is deployed every time you push your code.
I believe Github helped a lot making these services exist as deployment is often tightly bound to code revisions, and Github offers an excellent API and a huge community.</p>
<p>We have been adding more and more abstraction to the development process in order to make it easier, faster, stronger ...
However, there is still one constant, "localhost development". The coding itself is done on your machine/laptop.You still can use your favourite OS, IDE, tools.</p>
<p>Well, DaaS is going to cross that last barrier.
There are already several web services for online development like <a href="http://jsfiddle.net">jsfiddle.net</a> for web design or <a href="http://koding.com">koding.com</a>.
They offer something that could change the way we see development, the abstraction of your OS, ide and development environment.
If you think about it, that's a lot of time saved. No multi-platform mess, no more scripts to ensure the same development stack. Using the enormous processing power
of cloud platforms, there is virtually no compile time. You can even forget about your machine, all you need is a keyboard and a screen.</p>
<p>It seems only benefit but the thing is, if DaaS is really going to be the next step,I think we are missing something very important.
Before a developer learns to code, he has
to understand the building blocks of programming, what's a computer, what's an Operating System, how does it do its work. All the abstractions we built are built
using this knowledge. How could a programmer understand code optimization ? Security flows?
How could he understand the interaction of his code with its environment if he's not gonna use it?
Maybe we're not concreted with that yet, but the next generations of programmers are.</p>
<p>What do you think ?</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: IT - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: IT">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/it/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2012</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2012-04-29T20:26:09+02:00" itemprop="datePublished">Apr 29</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/it/'>IT</a>, <a class='category' href='/blog/blog/categories/programming/'>programming</a>, <a class='category' href='/blog/blog/categories/python/'>python</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/Development-as-a-Service/">Development as a Service on its baby steps</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,179 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: jib.li | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/jib-li/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Redesigning jibli - lessons learned form Hack Design Part 1]]></title>
<link href="http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/"/>
<updated>2013-03-06T20:01:00+01:00</updated>
<id>http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1</id>
<content type="html"><![CDATA[<p>As many programmers, I have always thought web design is a
discipline best reserved for people doing art and design.
You know, the hipster with his MacBook, his pletora of Adobe suites,
and the huge time spent learning to use them.</p>
<p>I come from a background of system administration and networking, always
fascinated by the obscure backend's thing happening behind what you
see on your screen. Furthermore, I started web development for the sole purpose
of building <a href="http://jib.li">Jib.li</a>, as a CoFounder and CTO on this
project, and as a team which had no money to hire a full time designer.</p>
<p>Needless to say I boarded the UI Design ship on the wrong foot.</p>
<p>In this first article I am going to share my experience on how I got passionate
about creating and designing a User Interface and what I learned from all the
resources shared on HN and <a href="http://hackdesign.org/courses/"> Hack Design </a> lessons which helped me redesign Jib.li.</p>
<!-- more -->
<h4>Before</h4>
<p><img class="hover center" src="/images/jibli_old.png" width="390"></p>
<h4>After</h4>
<p><img class="hover center" src="/images/jibli_new.png" width="400"></p>
<h2>Where to start ?</h2>
<p>We launched the public beta of jib.li on October 2012. A few weeks later we had had
plenty of feedback and proposals for new features.</p>
<p>For strategic reasons, we chose to start Jib.li with no registering process and just a "Connect with Facebook" instead.</p>
<p>We had no money to make a "how it works" video we could show
next to the home page form, like many startups do when they launch their
product. We only had a <a href="http://www.youtube.com/watch?v=KOYTefUmygA" title="Jib.li teaser video">teaser video</a> that we made before starting this project
where you see a bunch of people (our team at that time) pitching the idea.</p>
<p>The home page actually <a href="http://jib.li/homeold" title="Some styles are a little broken since we're migrating to the new design"> looked </a> like many location based services and the
typical workflow of a user was:</p>
<ol>
<li><p>Fill in the "From" and "To" location fields</p></li>
<li><p>Choose what action to take: Send, Deliver</p></li>
<li><p>A modal shows up to let him select a date depending on which action he chose</p></li>
<li><p>Redirecting the user to a listings results page</p></li>
<li><p>The user can then click on listings or create a new one if he's not satisified</p></li>
</ol>
<p>We noticed that many people when they first reached the home page, where not able to figure out what to do next.
To assist new users we used bootstrap tooltips everywhere, even on the action buttons.</p>
<p>On the graphic design aspect, we were just using a slightly customized <a href="http://bootswatch.com/cerulean/"> bootstrap theme </a></p>
<h2>Getting inspiration</h2>
<p>So after we decided it was time to have a fresh and better look, I saw the opportunity
to start practicing what I have been learning on HN, Hack Design and <a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111"> About Face 3 </a> about
UI/UX Design. It was also a good opportunity to stop frontend programming with spaghetti jQuery dom
manipulation and start using AngularJS which devprived me of my sleep hours lately.
(frontend programming will be the subject of an other article)</p>
<p>I think the most difficult step when you start working on something, no matter what kind
of project, is actually to <strong>start</strong>. For me it was no exception. I was certainly looking
for visual inspiration because a User Interface for a web application is first of all something
we see before we touch and interact with.</p>
<p>To help me filter out the overwhelming quantity of images, photos and visuals available on the internet,
I made list of words that sum up what Jib.li was about and started combining those words in search queries
for images and photos.</p>
<p>I ended up with this one when looking for the words <em>bike</em> and <em>bag</em>, which seemed to summarize the ideas
of transportation, carrying and environment which jib.li is all about.</p>
<p><img class="center" src="/images/hero_bike.jpg" width="300"></p>
<p><em>This photo comes from this <a href="http://letsgorideabike.com/blog/2011/03/beautiful-bicycles-yuba-mundo-cargo-bike/#comment-823035149"> beautiful article </a> by Dottie and all credits go to her.</em></p>
<p>When I saw this one ideas started immediately flowing and I knew where to start.</p>
<h2>The color palette</h2>
<p>The first thing I did was to choose a color palette. To do so, I used the inspiration photo
to <a href="http://vimeo.com/7109253"> extract a simple color palette.</a></p>
<p><img class="right" src="/images/color_swatch.jpg"></p>
<p>I actually repeated the process until I get a set of colors which validate these conditions:</p>
<ul>
<li>Have at most 3 main colors</li>
<li>Have dark close to black color</li>
<li>Have a light close to white color</li>
</ul>
<p>This one has two main colors, a wide blue range and the yellow/gold one. Grays and white are
just desaturated and very light colors.</p>
<p>This should suffice to always have a color to pick from this palette instead of choosing
one from a color picker, and so basically when looking for black I just choose the darkest one and when looking for white I pick
the most close to white.</p>
<p>The wide range of blue colors made me choose the blue as the main color.</p>
<p>I was heavily inspired by this <a href="http://ianstormtaylor.com/design-tip-never-use-black/"> article </a> of Ian Storm Taylor, which also made me
start using HSL (Hue, Saturation, Brightness) everywhere I wanted to get new colors from the palette.</p>
<h2>Rapid prototyping vs flat PSD design</h2>
<p>One thing I learned in interactive design is that a User Interface can't possibly be represented as a flat image only.
<a href="http://www.youtube.com/watch?v=PUv66718DII"> Bret Victor made an excellent talk </a> about the process of creation and the necessity to get immediate visual feedback.
My design process has been a mix of rapid prototyping and design exploration with <a href="https://developers.google.com/chrome-developer-tools/"> chrome developers tools </a> then representing ideas in
a PSD file as a reference for later.</p>
<p>Although I'm not going to talk much about frontend programming, this is the stack I prepared to quickly test ideas and move back and forth
from prototype to PSD.</p>
<p><a href="https://github.com/sp4ke/Angustrap.git"> The stack </a> consists of:</p>
<ul>
<li>Angular Seed project from AngularJS</li>
<li>Stylesheets using Less</li>
<li>Using git submodules to add frontend dependencies (Bootstrap, AngularUI, FontAwesome ... )</li>
</ul>
<p>Whenever I wanted to test some <em>behavior</em> feature I first tested it with Chrome, played
with styles and interactions, then tried to represent it as a layer in PSD.</p>
<p>On the other hand, when trying to work on the <em>look</em> aspect of something, I prefered the PSD
approach first, which gives more freedom on the graphics.</p>
<p><img class="hover" src="/images/jibli_design_1.jpg" width="50">
<img class="hover" src="/images/jibli_design_2.jpg" width="50">
<img class="hover" src="/images/jibli_design_3.jpg" width="50">
<img class="hover" src="/images/jibli_design_4.jpg" width="50">
<img class="hover" src="/images/jibli_design_5.jpg" width="50">
<img class="hover" src="/images/jibli_design_6.jpg" width="50">
<img class="hover" src="/images/jibli_design_7.jpg" width="50">
<img class="hover" src="/images/jibli_design_8.jpg" width="50">
<img class="hover" src="/images/jibli_design_9.jpg" width="50">
<img class="hover" src="/images/jibli_design_10.jpg" width="50">
<img class="hover" src="/images/jibli_design_11.jpg" width="50"></p>
<h2>End of Part 1</h2>
<p>I hope some programmers who are interested about web design and don't know how
to start might find some insight from this article and the next ones.</p>
<p>Part 2 will be about getting from prototype to stylesheets using chrome devtools, the importance of shadows and
some tips I learned about textures and details.</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: jib.li - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: jib.li">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/jib-li/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2013</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-03-06T20:01:00+01:00" itemprop="datePublished">Mar 6</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/ui-design/'>UI Design</a>, <a class='category' href='/blog/blog/categories/jib-li/'>jib.li</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/">Redesigning jibli - lessons learned form Hack Design Part 1</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: life - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: life">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/life/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2013</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-04-18T11:51:00+02:00" itemprop="datePublished">Apr 18</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/entrepreneurship/'>entrepreneurship</a>, <a class='category' href='/blog/blog/categories/experience/'>experience</a>, <a class='category' href='/blog/blog/categories/life/'>life</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/">My most valuable lesson in life learnt the hard way</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: programming | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/programming/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Development as a Service on its baby steps]]></title>
<link href="http://sp4ke.github.com/blog/Development-as-a-Service/"/>
<updated>2012-04-29T20:26:09+02:00</updated>
<id>http://sp4ke.github.com/blog/Development-as-a-Service</id>
<content type="html"><![CDATA[<p>Let me start by presenting a new web service <a href="http://www.pythonanywhere.com/">pythonanywhere.com</a>.</p>
<p>It's a full python development stack, ready to be used in your browser. After a quick subscription for a free account,
you have access from your dashboard to [python, ipython, bash] consoles in different python flavours.</p>
<p>You can also browse your files, make cron scripts and create python web apps on the fly.</p>
<p>The most interesting features are the consoles pause/resume feature, which can be shared
with other people. This could be very helpful to collaborate on code or teach python.
Behind the scene, it's an encrypted ajax window over your home folder running on a remote server hosted on EC2.</p>
<p>DaaS may be on it's first baby steps. Though, it could rapidly become a standard way to code for developers especially in startups.
Before diving in the pros and cons, let's analyse the different development stacks possibilities.</p>
<!-- more -->
<p>First, there's the good old fashion way. Setup a server on a cloud service
(I guess there's still people doing it with bare metal servers ). You have plenty of choice there, (EC2, AppEngine, Azure, Rackspace...),
it depends on your IT needs, spiritual beliefs (many don't care) and your pockets.</p>
<p>Then pick the development stack of your preferred language/framework: Python(Django, Web2py, Pylons, Flask...), Ruby(Ruby On Rails) for the rock stars, Java/.Net, PHP ...</p>
<p>Here, you have to maintain every piece involved in the process, packages versions, build tools, deployment, scaling. That's a lot of time and resources needed to finally get your developers pushing and your apps running.</p>
<p>The next big step was the <a href="http://www.heroku.com">Heroku</a> and <a href="http://www.dotcloud.com"> Dotcloud </a> like services, aka Deployment/Scaling as a Service.
They release from the burden of deploying and give enough abstraction to exclusively focus your effort on the application logic.
The process is often the same, basically setup your project with a simple conf file, then deploy to the server with one command.
They practically all handle version control systems like git,
so your project is deployed every time you push your code.
I believe Github helped a lot making these services exist as deployment is often tightly bound to code revisions, and Github offers an excellent API and a huge community.</p>
<p>We have been adding more and more abstraction to the development process in order to make it easier, faster, stronger ...
However, there is still one constant, "localhost development". The coding itself is done on your machine/laptop.You still can use your favourite OS, IDE, tools.</p>
<p>Well, DaaS is going to cross that last barrier.
There are already several web services for online development like <a href="http://jsfiddle.net">jsfiddle.net</a> for web design or <a href="http://koding.com">koding.com</a>.
They offer something that could change the way we see development, the abstraction of your OS, ide and development environment.
If you think about it, that's a lot of time saved. No multi-platform mess, no more scripts to ensure the same development stack. Using the enormous processing power
of cloud platforms, there is virtually no compile time. You can even forget about your machine, all you need is a keyboard and a screen.</p>
<p>It seems only benefit but the thing is, if DaaS is really going to be the next step,I think we are missing something very important.
Before a developer learns to code, he has
to understand the building blocks of programming, what's a computer, what's an Operating System, how does it do its work. All the abstractions we built are built
using this knowledge. How could a programmer understand code optimization ? Security flows?
How could he understand the interaction of his code with its environment if he's not gonna use it?
Maybe we're not concreted with that yet, but the next generations of programmers are.</p>
<p>What do you think ?</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: programming - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: programming">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/programming/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2012</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2012-04-29T20:26:09+02:00" itemprop="datePublished">Apr 29</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/it/'>IT</a>, <a class='category' href='/blog/blog/categories/programming/'>programming</a>, <a class='category' href='/blog/blog/categories/python/'>python</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/Development-as-a-Service/">Development as a Service on its baby steps</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: python | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/python/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Development as a Service on its baby steps]]></title>
<link href="http://sp4ke.github.com/blog/Development-as-a-Service/"/>
<updated>2012-04-29T20:26:09+02:00</updated>
<id>http://sp4ke.github.com/blog/Development-as-a-Service</id>
<content type="html"><![CDATA[<p>Let me start by presenting a new web service <a href="http://www.pythonanywhere.com/">pythonanywhere.com</a>.</p>
<p>It's a full python development stack, ready to be used in your browser. After a quick subscription for a free account,
you have access from your dashboard to [python, ipython, bash] consoles in different python flavours.</p>
<p>You can also browse your files, make cron scripts and create python web apps on the fly.</p>
<p>The most interesting features are the consoles pause/resume feature, which can be shared
with other people. This could be very helpful to collaborate on code or teach python.
Behind the scene, it's an encrypted ajax window over your home folder running on a remote server hosted on EC2.</p>
<p>DaaS may be on it's first baby steps. Though, it could rapidly become a standard way to code for developers especially in startups.
Before diving in the pros and cons, let's analyse the different development stacks possibilities.</p>
<!-- more -->
<p>First, there's the good old fashion way. Setup a server on a cloud service
(I guess there's still people doing it with bare metal servers ). You have plenty of choice there, (EC2, AppEngine, Azure, Rackspace...),
it depends on your IT needs, spiritual beliefs (many don't care) and your pockets.</p>
<p>Then pick the development stack of your preferred language/framework: Python(Django, Web2py, Pylons, Flask...), Ruby(Ruby On Rails) for the rock stars, Java/.Net, PHP ...</p>
<p>Here, you have to maintain every piece involved in the process, packages versions, build tools, deployment, scaling. That's a lot of time and resources needed to finally get your developers pushing and your apps running.</p>
<p>The next big step was the <a href="http://www.heroku.com">Heroku</a> and <a href="http://www.dotcloud.com"> Dotcloud </a> like services, aka Deployment/Scaling as a Service.
They release from the burden of deploying and give enough abstraction to exclusively focus your effort on the application logic.
The process is often the same, basically setup your project with a simple conf file, then deploy to the server with one command.
They practically all handle version control systems like git,
so your project is deployed every time you push your code.
I believe Github helped a lot making these services exist as deployment is often tightly bound to code revisions, and Github offers an excellent API and a huge community.</p>
<p>We have been adding more and more abstraction to the development process in order to make it easier, faster, stronger ...
However, there is still one constant, "localhost development". The coding itself is done on your machine/laptop.You still can use your favourite OS, IDE, tools.</p>
<p>Well, DaaS is going to cross that last barrier.
There are already several web services for online development like <a href="http://jsfiddle.net">jsfiddle.net</a> for web design or <a href="http://koding.com">koding.com</a>.
They offer something that could change the way we see development, the abstraction of your OS, ide and development environment.
If you think about it, that's a lot of time saved. No multi-platform mess, no more scripts to ensure the same development stack. Using the enormous processing power
of cloud platforms, there is virtually no compile time. You can even forget about your machine, all you need is a keyboard and a screen.</p>
<p>It seems only benefit but the thing is, if DaaS is really going to be the next step,I think we are missing something very important.
Before a developer learns to code, he has
to understand the building blocks of programming, what's a computer, what's an Operating System, how does it do its work. All the abstractions we built are built
using this knowledge. How could a programmer understand code optimization ? Security flows?
How could he understand the interaction of his code with its environment if he's not gonna use it?
Maybe we're not concreted with that yet, but the next generations of programmers are.</p>
<p>What do you think ?</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: python - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: python">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/python/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2012</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2012-04-29T20:26:09+02:00" itemprop="datePublished">Apr 29</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/it/'>IT</a>, <a class='category' href='/blog/blog/categories/programming/'>programming</a>, <a class='category' href='/blog/blog/categories/python/'>python</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/Development-as-a-Service/">Development as a Service on its baby steps</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,179 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: UI Design | ]]></title>
<link href="http://sp4ke.github.com/blog/blog/categories/ui-design/atom.xml" rel="self"/>
<link href="http://sp4ke.github.com/blog/"/>
<updated>2013-12-19T13:54:11+01:00</updated>
<id>http://sp4ke.github.com/blog/</id>
<author>
<name><![CDATA[Chakib Benziane]]></name>
<email><![CDATA[chakib.benz@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Redesigning jibli - lessons learned form Hack Design Part 1]]></title>
<link href="http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/"/>
<updated>2013-03-06T20:01:00+01:00</updated>
<id>http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1</id>
<content type="html"><![CDATA[<p>As many programmers, I have always thought web design is a
discipline best reserved for people doing art and design.
You know, the hipster with his MacBook, his pletora of Adobe suites,
and the huge time spent learning to use them.</p>
<p>I come from a background of system administration and networking, always
fascinated by the obscure backend's thing happening behind what you
see on your screen. Furthermore, I started web development for the sole purpose
of building <a href="http://jib.li">Jib.li</a>, as a CoFounder and CTO on this
project, and as a team which had no money to hire a full time designer.</p>
<p>Needless to say I boarded the UI Design ship on the wrong foot.</p>
<p>In this first article I am going to share my experience on how I got passionate
about creating and designing a User Interface and what I learned from all the
resources shared on HN and <a href="http://hackdesign.org/courses/"> Hack Design </a> lessons which helped me redesign Jib.li.</p>
<!-- more -->
<h4>Before</h4>
<p><img class="hover center" src="/images/jibli_old.png" width="390"></p>
<h4>After</h4>
<p><img class="hover center" src="/images/jibli_new.png" width="400"></p>
<h2>Where to start ?</h2>
<p>We launched the public beta of jib.li on October 2012. A few weeks later we had had
plenty of feedback and proposals for new features.</p>
<p>For strategic reasons, we chose to start Jib.li with no registering process and just a "Connect with Facebook" instead.</p>
<p>We had no money to make a "how it works" video we could show
next to the home page form, like many startups do when they launch their
product. We only had a <a href="http://www.youtube.com/watch?v=KOYTefUmygA" title="Jib.li teaser video">teaser video</a> that we made before starting this project
where you see a bunch of people (our team at that time) pitching the idea.</p>
<p>The home page actually <a href="http://jib.li/homeold" title="Some styles are a little broken since we're migrating to the new design"> looked </a> like many location based services and the
typical workflow of a user was:</p>
<ol>
<li><p>Fill in the "From" and "To" location fields</p></li>
<li><p>Choose what action to take: Send, Deliver</p></li>
<li><p>A modal shows up to let him select a date depending on which action he chose</p></li>
<li><p>Redirecting the user to a listings results page</p></li>
<li><p>The user can then click on listings or create a new one if he's not satisified</p></li>
</ol>
<p>We noticed that many people when they first reached the home page, where not able to figure out what to do next.
To assist new users we used bootstrap tooltips everywhere, even on the action buttons.</p>
<p>On the graphic design aspect, we were just using a slightly customized <a href="http://bootswatch.com/cerulean/"> bootstrap theme </a></p>
<h2>Getting inspiration</h2>
<p>So after we decided it was time to have a fresh and better look, I saw the opportunity
to start practicing what I have been learning on HN, Hack Design and <a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111"> About Face 3 </a> about
UI/UX Design. It was also a good opportunity to stop frontend programming with spaghetti jQuery dom
manipulation and start using AngularJS which devprived me of my sleep hours lately.
(frontend programming will be the subject of an other article)</p>
<p>I think the most difficult step when you start working on something, no matter what kind
of project, is actually to <strong>start</strong>. For me it was no exception. I was certainly looking
for visual inspiration because a User Interface for a web application is first of all something
we see before we touch and interact with.</p>
<p>To help me filter out the overwhelming quantity of images, photos and visuals available on the internet,
I made list of words that sum up what Jib.li was about and started combining those words in search queries
for images and photos.</p>
<p>I ended up with this one when looking for the words <em>bike</em> and <em>bag</em>, which seemed to summarize the ideas
of transportation, carrying and environment which jib.li is all about.</p>
<p><img class="center" src="/images/hero_bike.jpg" width="300"></p>
<p><em>This photo comes from this <a href="http://letsgorideabike.com/blog/2011/03/beautiful-bicycles-yuba-mundo-cargo-bike/#comment-823035149"> beautiful article </a> by Dottie and all credits go to her.</em></p>
<p>When I saw this one ideas started immediately flowing and I knew where to start.</p>
<h2>The color palette</h2>
<p>The first thing I did was to choose a color palette. To do so, I used the inspiration photo
to <a href="http://vimeo.com/7109253"> extract a simple color palette.</a></p>
<p><img class="right" src="/images/color_swatch.jpg"></p>
<p>I actually repeated the process until I get a set of colors which validate these conditions:</p>
<ul>
<li>Have at most 3 main colors</li>
<li>Have dark close to black color</li>
<li>Have a light close to white color</li>
</ul>
<p>This one has two main colors, a wide blue range and the yellow/gold one. Grays and white are
just desaturated and very light colors.</p>
<p>This should suffice to always have a color to pick from this palette instead of choosing
one from a color picker, and so basically when looking for black I just choose the darkest one and when looking for white I pick
the most close to white.</p>
<p>The wide range of blue colors made me choose the blue as the main color.</p>
<p>I was heavily inspired by this <a href="http://ianstormtaylor.com/design-tip-never-use-black/"> article </a> of Ian Storm Taylor, which also made me
start using HSL (Hue, Saturation, Brightness) everywhere I wanted to get new colors from the palette.</p>
<h2>Rapid prototyping vs flat PSD design</h2>
<p>One thing I learned in interactive design is that a User Interface can't possibly be represented as a flat image only.
<a href="http://www.youtube.com/watch?v=PUv66718DII"> Bret Victor made an excellent talk </a> about the process of creation and the necessity to get immediate visual feedback.
My design process has been a mix of rapid prototyping and design exploration with <a href="https://developers.google.com/chrome-developer-tools/"> chrome developers tools </a> then representing ideas in
a PSD file as a reference for later.</p>
<p>Although I'm not going to talk much about frontend programming, this is the stack I prepared to quickly test ideas and move back and forth
from prototype to PSD.</p>
<p><a href="https://github.com/sp4ke/Angustrap.git"> The stack </a> consists of:</p>
<ul>
<li>Angular Seed project from AngularJS</li>
<li>Stylesheets using Less</li>
<li>Using git submodules to add frontend dependencies (Bootstrap, AngularUI, FontAwesome ... )</li>
</ul>
<p>Whenever I wanted to test some <em>behavior</em> feature I first tested it with Chrome, played
with styles and interactions, then tried to represent it as a layer in PSD.</p>
<p>On the other hand, when trying to work on the <em>look</em> aspect of something, I prefered the PSD
approach first, which gives more freedom on the graphics.</p>
<p><img class="hover" src="/images/jibli_design_1.jpg" width="50">
<img class="hover" src="/images/jibli_design_2.jpg" width="50">
<img class="hover" src="/images/jibli_design_3.jpg" width="50">
<img class="hover" src="/images/jibli_design_4.jpg" width="50">
<img class="hover" src="/images/jibli_design_5.jpg" width="50">
<img class="hover" src="/images/jibli_design_6.jpg" width="50">
<img class="hover" src="/images/jibli_design_7.jpg" width="50">
<img class="hover" src="/images/jibli_design_8.jpg" width="50">
<img class="hover" src="/images/jibli_design_9.jpg" width="50">
<img class="hover" src="/images/jibli_design_10.jpg" width="50">
<img class="hover" src="/images/jibli_design_11.jpg" width="50"></p>
<h2>End of Part 1</h2>
<p>I hope some programmers who are interested about web design and don't know how
to start might find some insight from this article and the next ones.</p>
<p>Part 2 will be about getting from prototype to stylesheets using chrome devtools, the importance of shadows and
some tips I learned about textures and details.</p>
]]></content>
</entry>
</feed>

@ -1,154 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Category: UI Design - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Category: UI Design">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blogblog/categories/ui-design/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<section class="archives"><h1 class="year">2013</h1>
<article itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<span class="date"><time datetime="2013-03-06T20:01:00+01:00" itemprop="datePublished">Mar 6</time></span>
<br>
<span class="tags">
<a class='category' href='/blog/blog/categories/ui-design/'>UI Design</a>, <a class='category' href='/blog/blog/categories/jib-li/'>jib.li</a>
</span>
</div>
<h1 class="title" itemprop="name"><a href="/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/">Redesigning jibli - lessons learned form Hack Design Part 1</a></h1>
</article>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,279 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title></title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Apr 18th, 2013 entrepreneurship, experience, life My Most Valuable Lesson in Life Learnt the Hard Way Hollywood movies are often introduced with a &hellip;">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blog/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner">
<div itemscope itemtype="http://schema.org/Blog">
<article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<div class="date">
<time datetime="2013-04-18T11:51:00+02:00" data-updated="true" itemprop="datePublished">Apr 18<span>th</span>, 2013</time></div>
<div class="tags">
<a class='category' href='/blog/blog/categories/entrepreneurship/'>entrepreneurship</a>, <a class='category' href='/blog/blog/categories/experience/'>experience</a>, <a class='category' href='/blog/blog/categories/life/'>life</a>
</div>
</div>
<h1 class="title" itemprop="name"><a href="/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/" itemprop="url">My Most Valuable Lesson in Life Learnt the Hard Way</a></h1>
<div class="entry-content" itemprop="articleBody">
<p>Hollywood movies are often introduced with a main character living his life until a big event happens,
something that is enough life changing to justify a compelling story. And we, as an audience,
tend to identify to that hero or some event in the story that helps us forget the boredom of real life.
I believe this is one of the secret ingredients that make the movies industry so successful.
People need to forget about their daily life because they believe it&#8217;s boring.
In the timespan of <a href="http://www.slashfilm.com/by-the-numbers-the-length-of-feature-films/2/">159 minutes</a> they are thrilled in something more exciting, adventurous, romantic &#8230;
everything that does not seem to exist in &#8220;real life&#8221;.</p>
<a href="/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/" class="more-link">Read on &rarr;</a>
</div>
</article>
<article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<div class="date">
<time datetime="2013-03-06T20:01:00+01:00" data-updated="true" itemprop="datePublished">Mar 6<span>th</span>, 2013</time></div>
<div class="tags">
<a class='category' href='/blog/blog/categories/ui-design/'>UI Design</a>, <a class='category' href='/blog/blog/categories/jib-li/'>jib.li</a>
</div>
</div>
<h1 class="title" itemprop="name"><a href="/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/" itemprop="url">Redesigning Jibli - Lessons Learned Form Hack Design Part 1</a></h1>
<div class="entry-content" itemprop="articleBody">
<p>As many programmers, I have always thought web design is a
discipline best reserved for people doing art and design.
You know, the hipster with his MacBook, his pletora of Adobe suites,
and the huge time spent learning to use them.</p>
<p>I come from a background of system administration and networking, always
fascinated by the obscure backend&#8217;s thing happening behind what you
see on your screen. Furthermore, I started web development for the sole purpose
of building <a href="http://jib.li">Jib.li</a>, as a CoFounder and CTO on this
project, and as a team which had no money to hire a full time designer.</p>
<p>Needless to say I boarded the UI Design ship on the wrong foot.</p>
<p>In this first article I am going to share my experience on how I got passionate
about creating and designing a User Interface and what I learned from all the
resources shared on HN and <a href="http://hackdesign.org/courses/"> Hack Design </a> lessons which helped me redesign Jib.li.</p>
<a href="/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/" class="more-link">Read on &rarr;</a>
</div>
</article>
<article class="post" itemprop="blogPost" itemscope itemtype="http://schema.org/BlogPosting">
<div class="meta">
<div class="date">
<time datetime="2012-04-29T20:26:09+02:00" data-updated="true" itemprop="datePublished">Apr 29<span>th</span>, 2012</time></div>
<div class="tags">
<a class='category' href='/blog/blog/categories/it/'>IT</a>, <a class='category' href='/blog/blog/categories/programming/'>programming</a>, <a class='category' href='/blog/blog/categories/python/'>python</a>
</div>
</div>
<h1 class="title" itemprop="name"><a href="/blog/Development-as-a-Service/" itemprop="url">Development as a Service on Its Baby Steps</a></h1>
<div class="entry-content" itemprop="articleBody">
<p>Let me start by presenting a new web service <a href="http://www.pythonanywhere.com/">pythonanywhere.com</a>.</p>
<p>It&#8217;s a full python development stack, ready to be used in your browser. After a quick subscription for a free account,
you have access from your dashboard to [python, ipython, bash] consoles in different python flavours.</p>
<p>You can also browse your files, make cron scripts and create python web apps on the fly.</p>
<p>The most interesting features are the consoles pause/resume feature, which can be shared
with other people. This could be very helpful to collaborate on code or teach python.
Behind the scene, it&#8217;s an encrypted ajax window over your home folder running on a remote server hosted on EC2.</p>
<p>DaaS may be on it&#8217;s first baby steps. Though, it could rapidly become a standard way to code for developers especially in startups.
Before diving in the pros and cons, let&#8217;s analyse the different development stacks possibilities.</p>
<a href="/blog/Development-as-a-Service/" class="more-link">Read on &rarr;</a>
</div>
</article>
</div>
<nav id="pagenavi">
<div class="center"><a href="/blog/blog/archives">Blog Archives</a></div>
</nav></div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,221 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>My most valuable lesson in life learnt the hard way - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="My Most Valuable Lesson in Life Learnt the Hard Way Hollywood movies are often introduced with a main character living his life until a big event &hellip;">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner"><article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h1 class="title" itemprop="name">My Most Valuable Lesson in Life Learnt the Hard Way</h1>
<div class="entry-content" itemprop="articleBody"><p>Hollywood movies are often introduced with a main character living his life until a big event happens,
something that is enough life changing to justify a compelling story. And we, as an audience,
tend to identify to that hero or some event in the story that helps us forget the boredom of real life.
I believe this is one of the secret ingredients that make the movies industry so successful.
People need to forget about their daily life because they believe it&#8217;s boring.
In the timespan of <a href="http://www.slashfilm.com/by-the-numbers-the-length-of-feature-films/2/">159 minutes</a> they are thrilled in something more exciting, adventurous, romantic &#8230;
everything that does not seem to exist in &#8220;real life&#8221;.</p>
<!-- more -->
<p>I love movies and cinema, and I really enjoy seeing a good one. However, something have always kept me a bit skeptical about the whole phenomenon.
In my sight, real life is more exciting, there&#8217;s an infinite amount of possibilities
and outcomes to what you do. Everything seem possible when you stop picturing your
actions and ideas <a href="http://www.youtube.com/watch?v=lVeSLFgcKkw">in the way society expects you to do</a>. This feeling has started filling me since I was a teenager.
It forged my personality and made me what I have been until now. People nowadays call it being an &#8220;entrepreneur&#8221; or &#8220;hacker&#8221;.
I don&#8217;t think any word could describe the way I feel about my life and my role in the current society.</p>
<p>I left my country 6 years ago and came to France in order to study computer science.
I had been to medical school before, trying to follow my dad&#8217;s footsteps.
My path through my studies has been the same thing as it has always been my whole life:
trying new things, never settle down at the same place, always thinking of the next project
and moving forward. As an immigrant student I have done many little jobs, worked for big IT
companies ( although I was not always allowed to ), joined a prestigious computer school club
where I learned so much about sysadmin in system engineering and met many people.
Still, I was always feeling something missing. Deep inside, there was a voice who has been there since the beginning.
It kept telling me what
I needed to do. I was working as a system engineer on a short term contract when a friend
(at the time) offered me to start our own startup where I would be responsible for all the
technical aspect. When I think about it now, the idea was not that attractive,
there was no business plan and we were just a team of three guys without any previous experience in
the startup business. It was one of the most important choices I had to do.
Either decline a comfortable job offer which would&#8217;ve let me acquire a legal worker
status and finish my studies working with cool technologies, and maybe even travelling.
Or jumping right into the startup adventure, with no guaranty of success, no market
research whatsoever, and no immigration status possible especially in France which
is about ten years far from a Startup Act .</p>
<p>Flash forward, I am co-founder and CTO at jib.li. Many things happened since and
long story made short, we made a pivot and had new people in the team.
I will share this story with my friend and co-founder Ryadh in an other article,
a story which I think every foreign entrepreneur to France should know about.
For the time being, Jib.li has been launched 6 months ago, had some worldwide press and
media coverage, and is currently one of the first crowd-shipping/shopping platforms.</p>
<p>Then comes last week. Something big happened. Actually it was a succession of
events that, taken alone could be considered probable, but thinking they would happen all
at the same time in the lapse of a few days made them what we define as &#8220;life changing&#8221; events.
They are totally unrelated, each having a huge impact in some aspect of my personal and
professional life. But still, they are all connected together with the same variable
that makes them what I feel like being born in a new life.</p>
<p>Each one of these events could be considered a failed, depressing twist filled with despair.
In fact, they made me feel that way and I could barely sleep at night, always feeling a pain
in my stomach like I have been punched in the nuts. I am not enough comfortable to talk about
the personal one and the next articles will explain the rest of the story. What really matters
here is the key denominator, something I can now consider, with confidence, as the most important factor in any
future project and my whole new life. I am talking about <em>Trust</em>. Of course, it seems obvious !
Well I taught it was too.</p>
<p>The history of humanity has been shaped by trust. You can&#8217;t build a pyramid if
you can&#8217;t trust the architect. You can&#8217;t build an army when people don&#8217;t trust you. You can&#8217;t learn if you don&#8217;t
trust a teacher or a mentor, and you can&#8217;t found a family if you don&#8217;t trust a partner&#8230;
It is something that must be earned. Something you can&#8217;t afford with money and power. Something you can
fake with lies and charisma . I am now convinced the only way to find trust is to look for <em>Passion</em> inside people and that every human
being have to learn it the hard way. You must be betrayed in order to acknowledge it&#8217;s worth. I sincerely hope for
you it won&#8217;t be the same as me, but I can say for sure this was my life changing event.
Anything that will come after will be different and I am very thankful I was given this precious lesson in my youth.</p>
<p>I don&#8217;t know what words could describe the aftermath. I feel new, free, light.
I feel a strength rising inside me, like the power to shape the future. I still have so many
things to learn and experience, and the pains that come with it. <a href="http://www.bbc.co.uk/programmes/p00ynyl7">Entropy</a> makes
life beautiful, the uncertainty built in the entire universe makes our lives much more interesting than any Hollywood movie.</p>
<p>Good luck to all those who create, make and change things, and for anyone else, just listen to the voice speaking to you.</p>
</div>
</article>
<section id="comment">
<h1 class="title">Comments</h1>
<div id="disqus_thread" aria-live="polite"><noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</section>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
// var disqus_developer = 1;
var disqus_identifier = 'http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/';
var disqus_url = 'http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/';
var disqus_script = 'embed.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,302 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Redesigning jibli - lessons learned form Hack Design Part 1 - </title>
<meta name="author" content="Chakib Benziane">
<meta name="description" content="Redesigning Jibli - Lessons Learned Form Hack Design Part 1 As many programmers, I have always thought web design is a
discipline best reserved for &hellip;">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/blog/atom.xml" rel="alternate" title="" type="application/atom+xml">
<link rel="canonical" href="http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/">
<link href="/blog/favicon.png" rel="shortcut icon">
<link href="/blog/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans:400italic,400,700' rel='stylesheet' type='text/css'>
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
</head>
<body>
<div class="container">
<div class="left-col">
<div class="intrude-less">
<header id="header" class="inner"><div class="profilepic">
<script src="/blog/javascripts/md5.js"></script>
<script type="text/javascript">
document.write("<a href='http://sp4ke.com'><img src='http://www.gravatar.com/avatar/" + MD5("chakib.benz@gmail.com") + "?s=160' alt='Profile Picture' style='width: 160px;'</a>");
</script>
</div>
<h1><a href="/blog/"></a></h1>
<p class="subtitle">An entrepreneur thaughts and ideas.</p>
<nav id="main-nav"><ul class="main-navigation">
<li><a href="/blog/">Blog</a></li>
<li><a href="/blog/blog/archives">Archives</a></li>
</ul>
</nav>
<nav id="sub-nav">
<div class="social">
<a class="rss" href="/blog/atom.xml" title="RSS">RSS</a>
</div>
</nav>
<!--<hgroup>
<h1><a href="/blog/"></a></h1>
<h2>An entrepreneur thaughts and ideas.</h2>
</hgroup>
-->
</header>
</div>
</div>
<div class="mid-col">
<div class="mid-col-container">
<div id="content" class="inner"><article class="post" itemscope itemtype="http://schema.org/BlogPosting">
<h1 class="title" itemprop="name">Redesigning Jibli - Lessons Learned Form Hack Design Part 1</h1>
<div class="entry-content" itemprop="articleBody"><p>As many programmers, I have always thought web design is a
discipline best reserved for people doing art and design.
You know, the hipster with his MacBook, his pletora of Adobe suites,
and the huge time spent learning to use them.</p>
<p>I come from a background of system administration and networking, always
fascinated by the obscure backend&#8217;s thing happening behind what you
see on your screen. Furthermore, I started web development for the sole purpose
of building <a href="http://jib.li">Jib.li</a>, as a CoFounder and CTO on this
project, and as a team which had no money to hire a full time designer.</p>
<p>Needless to say I boarded the UI Design ship on the wrong foot.</p>
<p>In this first article I am going to share my experience on how I got passionate
about creating and designing a User Interface and what I learned from all the
resources shared on HN and <a href="http://hackdesign.org/courses/"> Hack Design </a> lessons which helped me redesign Jib.li.</p>
<!-- more -->
<h4>Before</h4>
<p><img class="hover center" src="/blog/images/jibli_old.png" width="390"></p>
<h4>After</h4>
<p><img class="hover center" src="/blog/images/jibli_new.png" width="400"></p>
<h2>Where to start ?</h2>
<p>We launched the public beta of jib.li on October 2012. A few weeks later we had had
plenty of feedback and proposals for new features.</p>
<p>For strategic reasons, we chose to start Jib.li with no registering process and just a &#8220;Connect with Facebook&#8221; instead.</p>
<p>We had no money to make a &#8220;how it works&#8221; video we could show
next to the home page form, like many startups do when they launch their
product. We only had a <a href="http://www.youtube.com/watch?v=KOYTefUmygA" title="Jib.li teaser video">teaser video</a> that we made before starting this project
where you see a bunch of people (our team at that time) pitching the idea.</p>
<p>The home page actually <a href="http://jib.li/homeold" title="Some styles are a little broken since we're migrating to the new design"> looked </a> like many location based services and the
typical workflow of a user was:</p>
<ol>
<li><p>Fill in the &#8220;From&#8221; and &#8220;To&#8221; location fields</p></li>
<li><p>Choose what action to take: Send, Deliver</p></li>
<li><p>A modal shows up to let him select a date depending on which action he chose</p></li>
<li><p>Redirecting the user to a listings results page</p></li>
<li><p>The user can then click on listings or create a new one if he&#8217;s not satisified</p></li>
</ol>
<p>We noticed that many people when they first reached the home page, where not able to figure out what to do next.
To assist new users we used bootstrap tooltips everywhere, even on the action buttons.</p>
<p>On the graphic design aspect, we were just using a slightly customized <a href="http://bootswatch.com/cerulean/"> bootstrap theme </a></p>
<h2>Getting inspiration</h2>
<p>So after we decided it was time to have a fresh and better look, I saw the opportunity
to start practicing what I have been learning on HN, Hack Design and <a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111"> About Face 3 </a> about
UI/UX Design. It was also a good opportunity to stop frontend programming with spaghetti jQuery dom
manipulation and start using AngularJS which devprived me of my sleep hours lately.
(frontend programming will be the subject of an other article)</p>
<p>I think the most difficult step when you start working on something, no matter what kind
of project, is actually to <strong>start</strong>. For me it was no exception. I was certainly looking
for visual inspiration because a User Interface for a web application is first of all something
we see before we touch and interact with.</p>
<p>To help me filter out the overwhelming quantity of images, photos and visuals available on the internet,
I made list of words that sum up what Jib.li was about and started combining those words in search queries
for images and photos.</p>
<p>I ended up with this one when looking for the words <em>bike</em> and <em>bag</em>, which seemed to summarize the ideas
of transportation, carrying and environment which jib.li is all about.</p>
<p><img class="center" src="/blog/images/hero_bike.jpg" width="300"></p>
<p><em>This photo comes from this <a href="http://letsgorideabike.com/blog/2011/03/beautiful-bicycles-yuba-mundo-cargo-bike/#comment-823035149"> beautiful article </a> by Dottie and all credits go to her.</em></p>
<p>When I saw this one ideas started immediately flowing and I knew where to start.</p>
<h2>The color palette</h2>
<p>The first thing I did was to choose a color palette. To do so, I used the inspiration photo
to <a href="http://vimeo.com/7109253"> extract a simple color palette.</a></p>
<p><img class="right" src="/blog/images/color_swatch.jpg"></p>
<p>I actually repeated the process until I get a set of colors which validate these conditions:</p>
<ul>
<li>Have at most 3 main colors</li>
<li>Have dark close to black color</li>
<li>Have a light close to white color</li>
</ul>
<p>This one has two main colors, a wide blue range and the yellow/gold one. Grays and white are
just desaturated and very light colors.</p>
<p>This should suffice to always have a color to pick from this palette instead of choosing
one from a color picker, and so basically when looking for black I just choose the darkest one and when looking for white I pick
the most close to white.</p>
<p>The wide range of blue colors made me choose the blue as the main color.</p>
<p>I was heavily inspired by this <a href="http://ianstormtaylor.com/design-tip-never-use-black/"> article </a> of Ian Storm Taylor, which also made me
start using HSL (Hue, Saturation, Brightness) everywhere I wanted to get new colors from the palette.</p>
<h2>Rapid prototyping vs flat PSD design</h2>
<p>One thing I learned in interactive design is that a User Interface can&#8217;t possibly be represented as a flat image only.
<a href="http://www.youtube.com/watch?v=PUv66718DII"> Bret Victor made an excellent talk </a> about the process of creation and the necessity to get immediate visual feedback.
My design process has been a mix of rapid prototyping and design exploration with <a href="https://developers.google.com/chrome-developer-tools/"> chrome developers tools </a> then representing ideas in
a PSD file as a reference for later.</p>
<p>Although I&#8217;m not going to talk much about frontend programming, this is the stack I prepared to quickly test ideas and move back and forth
from prototype to PSD.</p>
<p><a href="https://github.com/sp4ke/Angustrap.git"> The stack </a> consists of:</p>
<ul>
<li>Angular Seed project from AngularJS</li>
<li>Stylesheets using Less</li>
<li>Using git submodules to add frontend dependencies (Bootstrap, AngularUI, FontAwesome &#8230; )</li>
</ul>
<p>Whenever I wanted to test some <em>behavior</em> feature I first tested it with Chrome, played
with styles and interactions, then tried to represent it as a layer in PSD.</p>
<p>On the other hand, when trying to work on the <em>look</em> aspect of something, I prefered the PSD
approach first, which gives more freedom on the graphics.</p>
<p><img class="hover" src="/blog/images/jibli_design_1.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_2.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_3.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_4.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_5.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_6.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_7.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_8.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_9.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_10.jpg" width="50">
<img class="hover" src="/blog/images/jibli_design_11.jpg" width="50"></p>
<h2>End of Part 1</h2>
<p>I hope some programmers who are interested about web design and don&#8217;t know how
to start might find some insight from this article and the next ones.</p>
<p>Part 2 will be about getting from prototype to stylesheets using chrome devtools, the importance of shadows and
some tips I learned about textures and details.</p>
</div>
</article>
<section id="comment">
<h1 class="title">Comments</h1>
<div id="disqus_thread" aria-live="polite"><noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
</div>
</section>
</div>
</div>
<footer id="footer" class="inner"><p>
Copyright &copy; 2013 - Chakib Benziane -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script src="/blog/javascripts/slash.js"></script>
<script src="/blog/javascripts/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
(function($){
$('.fancybox').fancybox();
})(jQuery);
</script> <!-- Delete or comment this line to disable Fancybox -->
<script type="text/javascript">
var disqus_shortname = 'sp4ke';
// var disqus_developer = 1;
var disqus_identifier = 'http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/';
var disqus_url = 'http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/';
var disqus_script = 'embed.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</div>
</div>
</body>
</html>

@ -1,27 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<urlset xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>
<url>
<loc>http://sp4ke.github.com/blog/Development-as-a-Service/</loc>
<lastmod>2013-03-25T17:55:25+01:00</lastmod>
</url>
<url>
<loc>
http://sp4ke.github.com/blog/redesigning-jibli-lessons-learned-form-hack-design-part-1/
</loc>
<lastmod>2013-03-12T04:02:06+01:00</lastmod>
</url>
<url>
<loc>
http://sp4ke.github.com/blog/my-most-valuable-lesson-in-life-learnt-the-hard-way/
</loc>
<lastmod>2013-04-18T13:53:05+02:00</lastmod>
</url>
<url>
<loc>http://sp4ke.github.com/blog/</loc>
<lastmod>2013-04-18T13:53:05+02:00</lastmod>
</url>
<url>
<loc>http://sp4ke.github.com/blog/blog/archives/</loc>
<lastmod>2013-04-18T13:53:05+02:00</lastmod>
</url>
</urlset>

File diff suppressed because one or more lines are too long

@ -1,12 +0,0 @@
angular
.module( 'myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ui', 'ui.directives'])
.config( ['$routeProvider', ($routeProvider)->
$routeProvider.when('/', {templateUrl: 'partials/home.html', controller: MyCtrl1})
$routeProvider.when('/freelance', {templateUrl: 'partials/freelance.html', controller: MyCtrl1})
$routeProvider.when('/projects', {templateUrl: 'partials/projects.html', controller: projectsCtrl})
$routeProvider.when('/blog', {redirectTo: '/blog'})
$routeProvider.when('/contact', {templateUrl: 'partials/contact.html', controller: MyCtrl2})
$routeProvider.otherwise({redirectTo: '/'})
])

@ -1,70 +0,0 @@
#Controllers
#
@projectsCtrl = ($scope)->
projectsCtrl.$inject = ['$scope']
@dockCtrl = ($scope, $location, $window)->
$scope.icons = [
class: 'profil'
icon: 'icon-user'
link: '/freelance'
text: 'What I Do'
,
class: 'projects'
icon: 'icon-laptop'
link: '/projects'
text: 'My work'
,
class: 'contact'
icon: 'icon-phone'
link: '/contact'
text: 'Get in touch'
,
class: 'blog'
icon: 'icon-book'
link: '/blog'
text: 'Ideas'
,
]
$scope.hovered = false
$scope.hoverText = ($index)->
$scope.hovered = true
$scope.hoveredIndex = $index
console.log $scope.hovered
$scope.hoverOut = ()->
$scope.hovered = false
$scope.hoveredIndex = null
$scope.selected = null
defaultSelected = ()->
for icon in $scope.icons
if $location.path() is icon.link
$scope.selected = $scope.icons.indexOf icon
defaultSelected()
$scope.switch = ($index)->
if $index is 3
$window.location.hash = ''
$window.location.pathname = '/blog'
return
if $scope.selected is $index
$location.path('/')
$scope.selected = null
else
$scope.selected = $index
$location.path($scope.icons[$index].link)
dockCtrl.$inject = ['$scope', '$location', '$window']
window.MyCtrl1 = ()->
MyCtrl1.$inject = []
window.MyCtrl2 = ()->
MyCtrl2.$inject = []

@ -1,18 +0,0 @@
# Directives
angular
.module('myApp.directives', [])
.directive('appVersion', ['version', (version)->
(scope, elm, attrs)->
elm.text(version)
])
.directive('hoverShow', ()->
link: (scope, elm, attrs)->
elm.bind('mouseover', {attrs: attrs}, (ev)->
elm.closest('.projects').find('.' + ev.data.attrs.hoverShow).show()
)
elm.bind('mouseout', {attrs: attrs}, (ev)->
elm.closest('.projects').find('.' + ev.data.attrs.hoverShow).hide()
)
)

@ -1,10 +0,0 @@
# Filters
angular
.module('myApp.filters', [])
.filter('interpolate',
['version', (version)->
(text)->
return String(text).replace(/\%VERSION\%/mg, version)
])

@ -1,6 +0,0 @@
# Services
# Demonstrate how to register services
#In this case it is a simple value service.
angular.module('myApp.services', [])
.value('version', '0.1');

File diff suppressed because one or more lines are too long

@ -1,31 +0,0 @@
/* app css stylesheet */
.menu {
list-style: none;
border-bottom: 0.1em solid black;
margin-bottom: 2em;
padding: 0 0 0.5em;
}
.menu:before {
content: "[";
}
.menu:after {
content: "]";
}
.menu > li {
display: inline;
}
.menu > li:before {
content: "|";
padding-right: 0.3em;
}
.menu > li:nth-child(1):before {
content: "";
padding: 0;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

@ -1,8 +0,0 @@
========================================================
This pattern is downloaded from www.subtlepatterns.com
If you need more, that's where to get'em.
========================================================

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

@ -1,101 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Chakib Benziane - Entrepreneur, Developer, Designer</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/app.css"/>
<link rel="stylesheet" href="css/bootstrap.min.css"/>
<link rel="stylesheet" href="css/bootstrap-responsive.css" type="text/css" media="all" />
<link rel="stylesheet" href="css/animate.min.css" type="text/css" />
<style>
[ng\:cloak], [ng-cloak], .ng-cloak {
display: none;
}
</style>
</head>
<body>
<!--<ul class="menu">-->
<!--<li><a href="#/view1">view1</a></li>-->
<!--<li><a href="#/view2">view2</a></li>-->
<!--</ul>-->
<div class="container-fluid main ng-cloak">
<div ng-view></div>
</div>
<div class="container-fluid dock animated fadeInUp ng-cloak" ng-controller="dockCtrl">
<div ng-class="hovered && 'hovered'"class="hoverText">
<h3>{{icons[hoveredIndex].text}}</h3>
</div>
<a ui-event="{ mouseover: 'hoverText($index)', mouseout: 'hoverOut()' }" ng-click="switch($index)" ng-class="selected == $index && 'active'" ng-repeat="icon in icons" href="javascript:void(0);"><i ng-class="[icon.class, icon.icon]"></i></a>
</div>
<!-- Allows for coffeescript compiling on the fly. -->
<!-- Not recommended for production use. See http://coffeescript.org/#scripts. -->
<!--<script src="lib/coffeescript/coffee-script.js"></script>-->
<!--<script src="coffee/services.coffee" type="text/coffeescript"></script>-->
<!--<script src="coffee/controllers.coffee" type="text/coffeescript"></script>-->
<!--<script src="coffee/filters.coffee" type="text/coffeescript"></script>-->
<!--<script src="coffee/directives.coffee" type="text/coffeescript"></script>-->
<!--<script src="coffee/app.coffee" type="text/coffeescript"></script>-->
<!--<script src="//cdnjs.cloudflare.com/ajax/libs/less.js/1.3.3/less.min.js" type="text/javascript" charset="utf-8"></script>-->
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="lib/angular/angular.js"></script>
<script>
// include angular loader, which allows the files to load in any order
/*
AngularJS v1.0.0rc1
(c) 2010-2012 AngularJS http://angularjs.org
License: MIT
*/
//'use strict';(function(i){function d(c,a,e){return c[a]||(c[a]=e())}return d(d(i,"angular",Object),"module",function(){var c={};return function(a,e,f){e&&c.hasOwnProperty(a)&&(c[a]=null);return d(c,a,function(){function b(a,b,d){return function(){c[d||"push"]([a,b,arguments]);return g}}if(!e)throw Error("No module: "+a);var c=[],d=[],h=b("$injector","invoke"),g={_invokeQueue:c,_runBlocks:d,requires:e,name:a,provider:b("$provide","provider"),factory:b("$provide","factory"),service:b("$provide","service"),
//value:b("$provide","value"),constant:b("$provide","constant","unshift"),filter:b("$filterProvider","register"),directive:b("$compileProvider","directive"),config:h,run:function(a){d.push(a);return this}};f&&h(f);return g})}})})(window);
// include a third-party async loader library
/*!
* $script.js v1.3
* https://github.com/ded/script.js
* Copyright: @ded & @fat - Dustin Diaz, Jacob Thornton 2011
* Follow our software http://twitter.com/dedfat
* License: MIT
*/
!function(a,b,c){function t(a,c){var e=b.createElement("script"),f=j;e.onload=e.onerror=e[o]=function(){e[m]&&!/^c|loade/.test(e[m])||f||(e.onload=e[o]=null,f=1,c())},e.async=1,e.src=a,d.insertBefore(e,d.firstChild)}function q(a,b){p(a,function(a){return!b(a)})}var d=b.getElementsByTagName("head")[0],e={},f={},g={},h={},i="string",j=!1,k="push",l="DOMContentLoaded",m="readyState",n="addEventListener",o="onreadystatechange",p=function(a,b){for(var c=0,d=a.length;c<d;++c)if(!b(a[c]))return j;return 1};!b[m]&&b[n]&&(b[n](l,function r(){b.removeEventListener(l,r,j),b[m]="complete"},j),b[m]="loading");var s=function(a,b,d){function o(){if(!--m){e[l]=1,j&&j();for(var a in g)p(a.split("|"),n)&&!q(g[a],n)&&(g[a]=[])}}function n(a){return a.call?a():e[a]}a=a[k]?a:[a];var i=b&&b.call,j=i?b:d,l=i?a.join(""):b,m=a.length;c(function(){q(a,function(a){h[a]?(l&&(f[l]=1),o()):(h[a]=1,l&&(f[l]=1),t(s.path?s.path+a+".js":a,o))})},0);return s};s.get=t,s.ready=function(a,b,c){a=a[k]?a:[a];var d=[];!q(a,function(a){e[a]||d[k](a)})&&p(a,function(a){return e[a]})?b():!function(a){g[a]=g[a]||[],g[a][k](b),c&&c(d)}(a.join("|"));return s};var u=a.$script;s.noConflict=function(){a.$script=u;return this},typeof module!="undefined"&&module.exports?module.exports=s:a.$script=s}(this,document,setTimeout)
// load all of the dependencies asynchronously.
$script([
'js/app.js',
'js/services.js',
'js/controllers.js',
'js/filters.js',
'js/directives.js',
//'lib/jquery/jquery.min.js',
'lib/less/less.min.js',
'lib/angular-ui/common/module.js',
'lib/angular-ui/modules/directives/event/event.js'
], function() {
// when all is done, execute bootstrap angular application
angular.bootstrap(document, ['myApp']);
});
</script>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-31299938-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</body>
</html>

@ -1,31 +0,0 @@
// Generated by CoffeeScript 1.4.0
(function() {
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ui', 'ui.directives']).config([
'$routeProvider', function($routeProvider) {
$routeProvider.when('/', {
templateUrl: 'partials/home.html',
controller: MyCtrl1
});
$routeProvider.when('/freelance', {
templateUrl: 'partials/freelance.html',
controller: MyCtrl1
});
$routeProvider.when('/projects', {
templateUrl: 'partials/projects.html',
controller: projectsCtrl
});
$routeProvider.when('/blog', {
redirectTo: '/blog'
});
$routeProvider.when('/contact', {
templateUrl: 'partials/contact.html',
controller: MyCtrl2
});
return $routeProvider.otherwise({
redirectTo: '/'
});
}
]);
}).call(this);

@ -1,85 +0,0 @@
// Generated by CoffeeScript 1.4.0
(function() {
this.projectsCtrl = function($scope) {};
projectsCtrl.$inject = ['$scope'];
this.dockCtrl = function($scope, $location, $window) {
var defaultSelected;
$scope.icons = [
{
"class": 'profil',
icon: 'icon-user',
link: '/freelance',
text: 'What I Do'
}, {
"class": 'projects',
icon: 'icon-laptop',
link: '/projects',
text: 'My work'
}, {
"class": 'contact',
icon: 'icon-phone',
link: '/contact',
text: 'Get in touch'
}, {
"class": 'blog',
icon: 'icon-book',
link: '/blog',
text: 'Ideas'
}
];
$scope.hovered = false;
$scope.hoverText = function($index) {
$scope.hovered = true;
$scope.hoveredIndex = $index;
return console.log($scope.hovered);
};
$scope.hoverOut = function() {
$scope.hovered = false;
return $scope.hoveredIndex = null;
};
$scope.selected = null;
defaultSelected = function() {
var icon, _i, _len, _ref, _results;
_ref = $scope.icons;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
icon = _ref[_i];
if ($location.path() === icon.link) {
_results.push($scope.selected = $scope.icons.indexOf(icon));
} else {
_results.push(void 0);
}
}
return _results;
};
defaultSelected();
return $scope["switch"] = function($index) {
if ($index === 3) {
$window.location.hash = '';
$window.location.pathname = '/blog';
return;
}
if ($scope.selected === $index) {
$location.path('/');
return $scope.selected = null;
} else {
$scope.selected = $index;
return $location.path($scope.icons[$index].link);
}
};
};
dockCtrl.$inject = ['$scope', '$location', '$window'];
window.MyCtrl1 = function() {};
MyCtrl1.$inject = [];
window.MyCtrl2 = function() {};
MyCtrl2.$inject = [];
}).call(this);

@ -1,27 +0,0 @@
// Generated by CoffeeScript 1.4.0
(function() {
angular.module('myApp.directives', []).directive('appVersion', [
'version', function(version) {
return function(scope, elm, attrs) {
return elm.text(version);
};
}
]).directive('hoverShow', function() {
return {
link: function(scope, elm, attrs) {
elm.bind('mouseover', {
attrs: attrs
}, function(ev) {
return elm.closest('.projects').find('.' + ev.data.attrs.hoverShow).show();
});
return elm.bind('mouseout', {
attrs: attrs
}, function(ev) {
return elm.closest('.projects').find('.' + ev.data.attrs.hoverShow).hide();
});
}
};
});
}).call(this);

@ -1,12 +0,0 @@
// Generated by CoffeeScript 1.4.0
(function() {
angular.module('myApp.filters', []).filter('interpolate', [
'version', function(version) {
return function(text) {
return String(text).replace(/\%VERSION\%/mg, version);
};
}
]);
}).call(this);

@ -1,6 +0,0 @@
// Generated by CoffeeScript 1.4.0
(function() {
angular.module('myApp.services', []).value('version', '0.1');
}).call(this);

Binary file not shown.

@ -1,140 +0,0 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
This is a custom SVG webfont generated by Font Squirrel.
Copyright : Generated in 2009 by FontLab Studio Copyright info pending
</metadata>
<defs>
<font id="webfontATSw5sgI" horiz-adv-x="708" >
<font-face units-per-em="2048" ascent="1536" descent="-512" />
<missing-glyph horiz-adv-x="532" />
<glyph unicode=" " horiz-adv-x="532" />
<glyph unicode="&#x09;" horiz-adv-x="532" />
<glyph unicode="&#xa0;" horiz-adv-x="532" />
<glyph unicode="!" horiz-adv-x="575" d="M174 100.5q0 49.5 33 81t82 31.5t80.5 -31.5t31.5 -81t-31.5 -82t-80.5 -32.5t-82 32.5t-33 82zM195 1679h188l-27 -1302h-135z" />
<glyph unicode="&#x22;" horiz-adv-x="774" d="M92 1464q0 49 33 81t82 32q61 0 93 -50t32 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 81.5zM442 1464q0 49 33 81t82 32q59 0 92 -50t33 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 81.5z" />
<glyph unicode="#" horiz-adv-x="1689" d="M82 489l35 148h338l88 362h-348l34 148h351l106 430h152l-107 -430h361l106 430h152l-107 -430h365l-35 -148h-367l-88 -362h377l-35 -148h-379l-118 -489h-152l119 489h-361l-118 -489h-152l119 489h-336zM606 637h361l88 362h-361z" />
<glyph unicode="$" horiz-adv-x="1341" d="M117 281l125 118q131 -213 387 -252v607q-78 25 -129 44t-111.5 54t-95.5 75t-59.5 100t-24.5 136q0 117 42 204t109.5 133t133 68.5t135.5 28.5v125h131v-127q260 -25 411 -186l-127 -111q-106 109 -284 132v-537q109 -35 176.5 -63.5t145 -82t116.5 -132t39 -183.5 q0 -205 -138 -322.5t-339 -129.5v-119h-131v123q-336 39 -512 297zM381 1163q0 -86 64.5 -138t183.5 -91v498q-98 -14 -173 -76t-75 -193zM760 143q129 12 217 87t88 202q0 113 -79 173.5t-226 107.5v-570z" />
<glyph unicode="%" horiz-adv-x="2066" d="M123 1167.5q0 118.5 35 205.5t93 133t122.5 67.5t136.5 21.5q74 0 138.5 -20.5t123.5 -67.5t93 -135t34 -209q-2 -227 -115.5 -326.5t-271.5 -99.5q-72 0 -136.5 21.5t-123.5 67.5t-94 134.5t-35 207zM276 1167q0 -168 70 -241.5t166 -73.5t163.5 72.5t69.5 238.5 q0 170 -68.5 244t-166.5 74q-96 -2 -165 -75t-69 -239zM350 -96l1188 1763h176l-1188 -1763h-176zM1167 416q2 227 115 327.5t272 102.5q74 0 138.5 -21.5t124 -67.5t93.5 -135.5t34 -209.5q-2 -227 -116 -326.5t-272 -99.5q-72 0 -136 21.5t-123.5 67.5t-94.5 134t-35 207z M1323 412q0 -166 68.5 -239t165 -73t164 73t69.5 239q0 168 -67.5 242.5t-163.5 76.5q-96 0 -166 -74.5t-70 -244.5z" />
<glyph unicode="&#x26;" horiz-adv-x="1802" d="M123 410q0 150 95 254t267 200q-104 115 -157.5 203t-53.5 174q0 92 38 159.5t103.5 104.5t138.5 54.5t155 17.5q178 0 302 -80t124 -256q0 -121 -102.5 -210t-295.5 -187l377 -404q31 47 58 102l69 138l55 113l127 -78q-162 -324 -200 -387q182 -180 211 -174q37 0 53 3 t41.5 29.5t50.5 81.5l111 -65q-35 -78 -66 -124t-66.5 -63.5t-57 -21.5t-66.5 -4q-72 -8 -306 207q-184 -211 -491 -211q-59 0 -140 23.5t-168 70.5t-146.5 134t-59.5 196zM295 410q0 -84 68.5 -144.5t142.5 -84t131 -23.5q227 2 377 151l-432 455q-135 -74 -211 -157.5 t-76 -196.5zM446 1241q0 -90 195 -295q100 51 160.5 88t111 93.5t50.5 113.5q0 113 -74 163t-180 50q-109 0 -186 -51t-77 -162z" />
<glyph unicode="'" horiz-adv-x="423" d="M92 1464q0 49 33 81t82 32q61 0 93 -50t32 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 81.5z" />
<glyph unicode="(" horiz-adv-x="692" d="M123 520q0 98 13.5 220t49 269.5t89 267.5t143.5 205t200 95l13 -143q-96 -35 -167 -144.5t-104.5 -255t-49 -273.5t-15.5 -241q0 -111 15.5 -238.5t49 -273t104.5 -256t167 -143.5l-13 -144q-113 12 -202.5 98.5t-142 205t-88 264t-49 266.5t-13.5 221z" />
<glyph unicode=")" horiz-adv-x="692" d="M61 -391q96 33 167 143.5t105 256t49 273.5t15 238q0 113 -15 241t-49 273.5t-104.5 255t-167.5 144.5l13 143q111 -10 201 -95t143 -205t89 -267.5t49 -269.5t13 -220q0 -100 -13 -221t-49 -266.5t-88 -264t-142.5 -204.5t-202.5 -99z" />
<glyph unicode="*" horiz-adv-x="1265" d="M100 1161l52 133l413 -166l-4 449h144l-5 -449l414 166l51 -133l-424 -166l295 -327l-118 -101l-285 353l-283 -353l-123 101l295 327z" />
<glyph unicode="+" horiz-adv-x="1331" d="M102 496v137h484v493h137v-493h506v-137h-506v-496h-137v496h-484z" />
<glyph unicode="," horiz-adv-x="413" d="M82 100.5q0 49.5 32.5 81t82.5 31.5q61 0 93 -50t32 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 82z" />
<glyph unicode="-" d="M113 492v143h483v-143h-483z" />
<glyph unicode="." horiz-adv-x="411" d="M92 100.5q0 49.5 33 81t82 31.5t80.5 -31.5t31.5 -81t-31.5 -82t-80.5 -32.5t-82 32.5t-33 82z" />
<glyph unicode="/" horiz-adv-x="884" d="M41 -532l633 2109h170l-633 -2109h-170z" />
<glyph unicode="0" horiz-adv-x="1253" d="M123 579.5q0 165.5 44 287.5t118.5 187.5t159.5 96.5t181.5 31t181.5 -31t159.5 -96.5t118.5 -187.5t44 -287.5t-44 -287.5t-118.5 -187.5t-159.5 -96.5t-181.5 -31t-181.5 31t-159.5 96.5t-118.5 187.5t-44 287.5zM295 579.5q0 -237.5 96 -344t235.5 -106.5t235.5 106.5 t96 344t-96 344t-235.5 106.5t-235.5 -106.5t-96 -344z" />
<glyph unicode="1" horiz-adv-x="731" d="M102 936l293 221h166v-1157h-166v983l-182 -154z" />
<glyph unicode="2" horiz-adv-x="1126" d="M102 0v131l71 49q44 31 155.5 120t196.5 169t156 176t71 162q0 109 -56.5 161t-152.5 50q-53 0 -104.5 -19.5t-85.5 -46t-59.5 -54.5t-37.5 -46l-12 -18q-104 98 -105 100q43 78 155 162t251 86q180 0 280.5 -92.5t100.5 -270.5q0 -139 -165 -323.5t-376 -345.5h627 l2 -150h-912z" />
<glyph unicode="3" horiz-adv-x="1142" d="M82 -313l108 106q10 -8 28 -20.5t80 -30.5t130 -16q92 0 184.5 43t164 147t71.5 250q0 98 -74 173t-174 75q-41 0 -86 -6.5t-80 -13.5t-62.5 -15t-43.5 -14l-17 -5v144q166 68 262.5 148.5t96.5 197.5q0 74 -52.5 120t-125.5 46q-53 0 -99.5 -14.5t-76 -36t-51 -43 t-32.5 -35.5l-8 -15l-96 95q4 8 13.5 22.5t41 52t69.5 65.5t102.5 51.5t133.5 23.5q145 0 247 -93.5t102 -238.5q0 -158 -183 -293q152 -18 257.5 -126.5t109.5 -264.5q0 -147 -57.5 -268t-148.5 -192t-191.5 -108.5t-196.5 -37.5q-88 0 -175 31.5t-130 64.5z" />
<glyph unicode="4" horiz-adv-x="1286" d="M82 0v90l803 1067h108v-1007h232v-150h-232v-440h-166v440h-745zM307 141l39 9h481v688l-491 -666l-29 -29v-2z" />
<glyph unicode="5" horiz-adv-x="1208" d="M143 -301l107 104q8 -8 24.5 -21t79 -34.5t135.5 -21.5q150 0 281 115.5t131 328.5q0 115 -84 218.5t-203 103.5q-158 0 -270 -76h-166v741h770v-156h-604v-413q119 53 270 53q180 0 317.5 -143.5t145.5 -327.5q0 -147 -57 -268t-146.5 -192.5t-188.5 -110.5t-196 -39 q-104 0 -190 34.5t-121 69.5z" />
<glyph unicode="6" horiz-adv-x="1269" d="M131 727q0 360 170 620.5t424 260.5q188 0 356 -135l-110 -107q-100 84 -240 84q-115 0 -202 -76t-134 -195.5t-71.5 -240.5t-26.5 -236q176 268 414 269q193 0 314.5 -111.5t121.5 -353.5q0 -80 -25.5 -164t-78 -167t-151.5 -136t-230 -53q-254 0 -392.5 191.5 t-138.5 549.5zM319 481q35 -168 123 -256t220 -88q111 0 185.5 66.5t101 145.5t26.5 157q0 164 -74 238.5t-190 74.5q-230 0 -392 -338z" />
<glyph unicode="7" horiz-adv-x="1058" d="M10 -328q86 53 339 497.5t437 823.5h-696v164h907v-121q-195 -410 -478 -918.5t-394 -557.5z" />
<glyph unicode="8" horiz-adv-x="1216" d="M133 350q2 143 97.5 263t224.5 208q-281 223 -281 439q0 92 38 160.5t103.5 106.5t138 55t154.5 17t155 -17t138.5 -55t103 -106.5t37.5 -160.5q0 -143 -98 -255t-221 -186q86 -63 137 -106t109.5 -104.5t86 -125t27.5 -133.5q0 -78 -24.5 -140.5t-59 -100t-87 -65.5 t-93.5 -40t-93 -19.5t-72 -7.5h-42h-4h-36q-13 0 -68 6.5t-95 18.5t-95.5 40t-91.5 65.5t-62.5 101t-26.5 141.5zM307 350q0 -55 19.5 -98t55.5 -66.5t67.5 -39t74.5 -19.5l55 -5q11 -1 29 -1h2q23 0 45.5 1t72.5 13t86 33.5t65.5 69t29.5 112.5q0 86 -86 174t-254 209 q-248 -160 -262 -383zM348 1260q0 -90 67.5 -174.5t188.5 -178.5q53 29 105.5 68t105.5 119t53 166q0 111 -75.5 159.5t-184 48.5t-184.5 -48.5t-76 -159.5z" />
<glyph unicode="9" horiz-adv-x="1269" d="M123 662q0 80 25.5 163.5t78 166.5t151.5 136.5t230 53.5q254 0 392.5 -191.5t138.5 -550.5q0 -109 -20.5 -224.5t-69 -234t-116 -212t-171 -151.5t-225.5 -58q-117 0 -217.5 37.5t-155.5 76.5l112 109q119 -66 259 -66q115 0 202.5 75t136 194.5t72 239.5t27.5 237 q-180 -266 -414 -266q-193 0 -314.5 111.5t-121.5 353.5zM295 662q0 -164 73.5 -239t190.5 -75q227 0 391 336q-35 170 -123 258t-219 88q-111 0 -185.5 -66.5t-101 -145t-26.5 -156.5z" />
<glyph unicode=":" horiz-adv-x="514" d="M143 100.5q0 49.5 33 81t82 31.5t81 -31.5t32 -81t-32 -82t-81 -32.5t-82 32.5t-33 82zM143 850q0 49 33 81t82 32t81 -32t32 -81t-32 -82t-81 -33t-82 33t-33 82z" />
<glyph unicode=";" horiz-adv-x="526" d="M143 100.5q0 49.5 33 81t82 31.5q61 0 93 -50t32 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 82zM143 850q0 49 33 81t82 32t81 -32t32 -81t-32 -82t-81 -33t-82 33t-33 82z" />
<glyph unicode="&#x3c;" horiz-adv-x="1433" d="M154 500v147l1136 514v-147l-975 -441l975 -440v-147z" />
<glyph unicode="=" horiz-adv-x="1394" d="M133 344v137h1129v-137h-1129zM133 672v137h1129v-137h-1129z" />
<glyph unicode="&#x3e;" horiz-adv-x="1433" d="M143 -14v147l973 440l-973 441v147l1137 -514v-147z" />
<glyph unicode="?" horiz-adv-x="1032" d="M84 1393q6 12 19.5 31.5t56.5 68.5t91 87t125 68.5t156 30.5q104 0 184.5 -25.5t125.5 -64.5t72.5 -91t35.5 -96t8 -91q0 -78 -24.5 -147.5t-81.5 -139.5t-93 -104l-114 -107q-164 -150 -164 -213q0 -88 94 -172l-104 -90q-53 47 -78.5 76.5t-47 79t-21.5 108.5 q0 90 52 164t161 170q74 68 118.5 116t86.5 119.5t44 139.5q0 225 -254 225q-59 0 -115.5 -25.5t-95 -61.5t-69.5 -72t-45 -62l-14 -25zM399 100.5q0 49.5 33 81t82 31.5t81 -31.5t32 -81t-32 -82t-81 -32.5t-82 32.5t-33 82z" />
<glyph unicode="@" horiz-adv-x="2195" d="M123 535q0 266 141.5 507.5t378 388t502.5 146.5q215 0 395 -76t294 -199.5t176.5 -276.5t62.5 -312q0 -158 -54.5 -283t-133.5 -195.5t-175 -117.5t-170 -62.5t-129 -15.5q-166 0 -127 182q-209 -184 -412 -182q-276 2 -276 383q0 162 56.5 308.5t141.5 243.5t183 154.5 t184 57.5q190 0 297 -164l29 121l160 -37q-209 -928 -209 -938q6 -6 57 4t123 46t139.5 94.5t112.5 164t39 236.5q0 127 -51.5 249.5t-145.5 224t-242.5 164t-324.5 62.5q-221 0 -421 -125t-318.5 -328.5t-118.5 -424.5q0 -330 255 -552.5t603 -222.5q182 0 321.5 48.5 t341.5 216.5l103 -127q-231 -190 -392 -245.5t-374 -55.5q-270 0 -503.5 119.5t-376 337t-142.5 481.5zM760 422q0 -254 112 -260q78 -2 160 39t147.5 105.5t100.5 105.5t61 77l76 345q-55 135 -117.5 182t-138.5 47q-135 0 -268 -188.5t-133 -452.5z" />
<glyph unicode="A" horiz-adv-x="1474" d="M61 0l582 1577h188l582 -1577h-190l-199 537h-575l-197 -537h-191zM506 692h461l-230 627z" />
<glyph unicode="B" horiz-adv-x="1308" d="M174 0v1577h180v-115q117 76 190.5 106.5t164.5 30.5q166 0 284.5 -111.5t118.5 -344.5q-2 -223 -160 -324q129 -59 180.5 -154.5t51.5 -179.5v-10q0 -43 -1 -70.5t-11.5 -85t-29 -97.5t-57 -90t-94 -82t-142.5 -53.5t-198 -21.5q-137 4 -297 117v-92h-180zM354 236 q147 -92 297 -93q78 0 138.5 16.5t97.5 36t63.5 58.5t37.5 61.5t17.5 67.5t6.5 56v46q0 31 -13.5 65t-46 77t-106.5 72.5t-178 33.5q-59 -4 -314 -4v-493zM354 877h112q32 0 102.5 3t102.5 10l85 19q53 12 78.5 32t54.5 47.5t40 67.5t11 91q-2 145 -69.5 215t-161.5 70 q-160 0 -355 -119v-436z" />
<glyph unicode="C" horiz-adv-x="1357" d="M123 752q0 203 59.5 369.5t154.5 267t208.5 154.5t228.5 54q92 0 174 -22.5t134.5 -53t92 -62.5t58.5 -54l16 -23l-125 -120l-11 17q-7 11 -38 40t-66.5 50.5t-99 38.5t-137.5 17q-186 0 -325.5 -174t-139.5 -499q0 -256 131 -430.5t320 -174.5q45 0 89 6.5t81 16.5 t70.5 23.5t61 28t50.5 28.5t40 27.5l29.5 23.5t18.5 16l6 7l111 -107q-61 -76 -117 -115q-176 -127 -436 -127q-274 0 -456.5 222.5t-182.5 554.5z" />
<glyph unicode="D" horiz-adv-x="1503" d="M174 0v1577h180v-174q205 193 465 194q111 0 207 -45t178 -137t129 -256t47 -381q0 -342 -179 -572.5t-443 -230.5q-190 4 -404 142v-117h-180zM354 281q197 -129 404 -129q188 0 315 177t127 449q0 315 -111.5 477t-263.5 166q-281 0 -471 -194v-946z" />
<glyph unicode="E" horiz-adv-x="1150" d="M174 0v1577h651l215 10v-186h-686v-508h584v-156h-584v-561h500l215 10v-186h-895z" />
<glyph unicode="F" horiz-adv-x="1112" d="M174 0v1577h651l215 10v-186h-686v-508h584v-156h-584v-737h-180z" />
<glyph unicode="G" horiz-adv-x="1525" d="M123 764q0 184 48 330.5t122 237.5t173 152.5t194.5 86t191.5 26.5q90 0 173 -24.5t138.5 -60t98.5 -71.5t61 -61l20 -24l-124 -121q-4 8 -14.5 21.5t-43.5 47t-70.5 59.5t-100 47.5t-130.5 23.5q-90 0 -180 -35t-176 -108.5t-140.5 -210t-54.5 -316.5q0 -100 30 -201.5 t90 -196t171 -153.5t254 -61q98 0 217 54t119 113v306h-211q-109 0 -166 30v164q74 -18 172 -18h365v-490q0 -135 -150.5 -233t-337.5 -103q-160 0 -290 51.5t-211.5 132.5t-137 187.5t-78 210t-22.5 207.5z" />
<glyph unicode="H" horiz-adv-x="1519" d="M174 0v1577h180v-684h811v684h181v-1577h-181v737h-811v-737h-180z" />
<glyph unicode="I" horiz-adv-x="528" d="M174 0v1577h180v-1577h-180z" />
<glyph unicode="J" horiz-adv-x="585" d="M-20 -369q109 31 181 113t72 221v1612h181v-1612q0 -94 -26 -173t-63.5 -131t-90 -93t-96.5 -61.5t-93 -36.5z" />
<glyph unicode="K" horiz-adv-x="1265" d="M174 0v1577h180v-711l541 711h227l-590 -737q45 -6 112 -38t106 -77q45 -45 244.5 -365.5t230.5 -355.5v-4h-219q-35 37 -188.5 295t-190.5 297q-82 90 -185 90q-61 0 -88 -6v-676h-180z" />
<glyph unicode="L" horiz-adv-x="1202" d="M174 0v1577h180v-1401h561l215 10v-186h-956z" />
<glyph unicode="M" horiz-adv-x="1742" d="M174 0v1577h180l514 -1352l2 -14l2 14l517 1352h180v-1577h-180v1106l2 31l-9 -31l-424 -1106h-174l-424 1106l-8 31l2 -31v-1106h-180z" />
<glyph unicode="N" horiz-adv-x="1482" d="M174 0v1577h180v-2l762 -1239l14 -29l-2 29v1241h181v-1577h-181v2l-761 1243l-15 29l2 -29v-1245h-180z" />
<glyph unicode="O" horiz-adv-x="1554" d="M123 790.5q0 225.5 55 389t152.5 252t208 127t241.5 38.5q102 -2 192.5 -25.5t176.5 -80.5t146.5 -146.5t98.5 -229.5t38 -320q0 -227 -55.5 -391t-152 -252.5t-207 -127t-241.5 -38.5t-240.5 38.5t-206 126t-151.5 251t-55 389zM303 795q0 -180 40 -310.5t109.5 -200 t149.5 -100t174 -30.5t174 30.5t149.5 99t110.5 198.5t41 309q0 176 -40 305t-109.5 198.5t-148.5 101t-173 34.5q-94 0 -175 -31t-151.5 -100.5t-110.5 -197.5t-40 -306z" />
<glyph unicode="P" horiz-adv-x="1265" d="M174 0v1577h180v-123q190 143 365 143q160 -6 301 -140t143 -355q0 -287 -138 -458t-349 -171q-170 2 -322 107v-580h-180zM354 760q166 -129 330 -131q133 4 220 131t87 342q-2 145 -88 233t-184 95q-98 0 -176 -29t-189 -98v-543z" />
<glyph unicode="Q" horiz-adv-x="1554" d="M123 780q0 182 38 325.5t99.5 235t148.5 150.5t178 82.5t193 23.5q129 -2 239.5 -44t206 -131t151 -253.5t55.5 -388.5q0 -207 -47.5 -362.5t-131.5 -244.5t-181 -135t-214 -58q70 -82 232 -82q53 0 192 32l49 -161q-88 -39 -241 -39q-96 0 -174 25.5t-124.5 68.5t-73 80 t-42.5 78q-244 29 -398.5 218t-154.5 580zM303 784q0 -180 40 -310t109.5 -199.5t149.5 -100.5t174 -31t174 31t149.5 99.5t110.5 198.5t41 308q0 143 -26.5 256t-71.5 184.5t-106.5 120t-127 67.5t-139.5 22q-94 0 -175 -33t-150.5 -103.5t-110.5 -201t-41 -308.5z" />
<glyph unicode="R" horiz-adv-x="1349" d="M174 0v1577h180v-115q111 70 187.5 102.5t169.5 32.5q168 -4 295 -112.5t127 -335.5q0 -152 -54.5 -258.5t-128 -155.5t-170.5 -69q82 -70 271.5 -338.5t267.5 -323.5v-4h-223q-53 39 -134 146.5t-149 211t-150.5 192.5t-148.5 101q-113 0 -160 2v-653h-180zM354 799h303 q121 2 211 82t93 268q0 139 -76 207.5t-174 73.5q-100 0 -176 -27t-181 -88v-516z" />
<glyph unicode="S" horiz-adv-x="1361" d="M117 281l125 118q78 -125 202.5 -189.5t272.5 -68.5q143 0 245.5 76t102.5 215q0 53 -22.5 97t-50 71t-84 53.5t-95.5 40t-108 33.5l-21 6q-94 29 -144.5 46.5t-124 55t-111.5 77.5t-66.5 104.5t-28.5 146.5q0 106 36 187.5t88 127.5t119.5 74.5t122 37.5t105.5 9 q150 0 280 -51t211 -139l-127 -111q-131 137 -364 138q-43 0 -87 -11.5t-95.5 -38t-84 -84t-32.5 -139.5q0 -45 22.5 -82t48 -59.5t85 -48t90 -35.5t106.5 -33q90 -29 146.5 -49t132 -60t119 -86t75 -118t31.5 -160q0 -217 -153.5 -336t-370.5 -119q-397 13 -596 304z" />
<glyph unicode="T" horiz-adv-x="1150" d="M20 1421v156h1110v-156h-468v-1421h-181v1421h-461z" />
<glyph unicode="U" horiz-adv-x="1460" d="M174 489v1088h180v-1083q0 -94 29 -163t70 -106t96 -59.5t97 -27.5t85 -5t84 5t96.5 27.5t95.5 58.5t69.5 104.5t29.5 160.5v1088h180v-1088q0 -133 -43 -232t-102.5 -151.5t-141 -83t-143 -39t-125.5 -8.5q-66 0 -126 8.5t-143 39t-142.5 83t-102.5 151.5t-43 232z" />
<glyph unicode="V" horiz-adv-x="1433" d="M61 1577h191l459 -1296l6 -27l6 27l459 1296h190l-561 -1577h-188z" />
<glyph unicode="W" horiz-adv-x="2019" d="M61 1577h189l328 -1270l4 -24l4 24l327 1270h191l328 -1270l4 -24l4 24l327 1270h191l-447 -1577h-149l-348 1217l-6 36l-7 -36l-344 -1217h-149z" />
<glyph unicode="X" horiz-adv-x="1345" d="M61 0l500 786l-500 791h220l391 -616l393 616h219l-502 -791l502 -786h-221l-391 612l-389 -612h-222z" />
<glyph unicode="Y" horiz-adv-x="1263" d="M20 1577h218l397 -627l399 627h209l-520 -821v-756h-178v756z" />
<glyph unicode="Z" horiz-adv-x="1257" d="M104 0v168l789 1241h-768v168h987v-164l-788 -1245h594q23 -1 44 -1q154 0 193 40v-174q-18 -16 -78.5 -24.5t-111.5 -8.5h-52h-809z" />
<glyph unicode="[" horiz-adv-x="735" d="M174 -532v2109h418v-123h-246v-1864h246v-122h-418z" />
<glyph unicode="\" horiz-adv-x="905" d="M51 1577h170l633 -2109h-170z" />
<glyph unicode="]" horiz-adv-x="735" d="M143 -410h246v1864h-246v123h418v-2109h-418v122z" />
<glyph unicode="^" horiz-adv-x="1339" d="M82 0l514 1126h147l514 -1126h-147l-440 965l-441 -965h-147z" />
<glyph unicode="_" horiz-adv-x="1353" d="M113 0h1128v-131h-1128v131z" />
<glyph unicode="`" horiz-adv-x="729" d="M113 1432l43 145l460 -229l-43 -97z" />
<glyph unicode="a" horiz-adv-x="1155" d="M123 283q0 72 14.5 124t53 103t120.5 87t207 54q213 29 285 47v129q0 51 -32 117t-95 66q-219 0 -344 -107q-18 -20 -16.5 -39.5t16.5 -34.5l-164 -30q-20 26 -20 64q0 24 8 52q20 74 92 115q218 121 445 121h7q100 0 165 -61.5t84.5 -129t19.5 -133.5v-555 q0 -16 4 -40.5t32.5 -73.5t77.5 -80l-110 -103q-119 47 -158 199q-186 -199 -385 -199q-20 0 -49 4.5t-77 22.5t-86 49t-66.5 91.5t-28.5 140.5zM293 283q0 -49 17.5 -85t42 -51.5t42 -21.5t29.5 -6q104 0 204.5 66.5t174.5 158.5v207q-100 -20 -266 -43 q-152 -20 -198 -74.5t-46 -150.5z" />
<glyph unicode="b" horiz-adv-x="1292" d="M174 0v1679h172v-770q189 242 414 242h4q180 -2 292.5 -170t112.5 -399q0 -287 -125.5 -447t-347.5 -160q-156 0 -350 156v-131h-172zM346 319q76 -76 174 -126t176 -50q137 0 219 117t82 322q0 162 -64.5 280.5t-168.5 120.5h-4q-243 0 -414 -266v-398z" />
<glyph unicode="c" horiz-adv-x="1044" d="M113 543q0 295 149 454q144 154 320 154h14q66 -2 125 -21.5t97 -46t67.5 -52t44.5 -44.5l12 -16l-108 -103q-2 4 -8.5 12.5t-27 28t-46 34.5t-68.5 28.5t-92 15.5h-8q-114 0 -205 -113q-94 -117 -94 -331q0 -172 82 -288t215 -116q51 0 81.5 4t83 32t109.5 81l107 -102 q-82 -82 -156 -124t-116 -48.5t-109 -6.5q-209 0 -339 162t-130 406z" />
<glyph unicode="d" horiz-adv-x="1333" d="M123 545q0 287 126 446.5t347 159.5q156 0 350 -156v684h172v-1409q2 -16 7 -39.5t39 -77t87 -79.5l-141 -99q-143 78 -164 242q-189 -242 -414 -242h-4q-180 2 -292.5 170.5t-112.5 399.5zM295 545q0 -162 64.5 -281t168.5 -121h8q243 0 410 267v397q-80 76 -176 126 t-174 50q-137 0 -219 -116.5t-82 -321.5z" />
<glyph unicode="e" horiz-adv-x="1187" d="M113 551q0 242 138 421t347 179q119 0 209 -46t136 -107.5t73.5 -139.5t35 -127t7.5 -84v-76h-774q0 -193 85 -318.5t236 -125.5q115 0 195 49q80 47 153 146l105 -101q-72 -88 -141.5 -144.5t-135 -74.5t-95.5 -22.5t-81 -4.5q-227 0 -360 167t-133 409zM309 723h570 q-10 47 -27.5 89t-48.5 87t-84 72.5t-121 27.5q-100 0 -177 -76.5t-112 -199.5z" />
<glyph unicode="f" horiz-adv-x="825" d="M61 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332v-983h-170v983h-146z" />
<glyph unicode="g" horiz-adv-x="1261" d="M123 -221q2 125 45 200.5t127 137.5q-96 41 -105 133q0 96 146 213q-170 96 -170 332q0 92 44 165.5t113.5 113.5t142.5 60.5t140 20.5q63 0 137 -18q133 121 310 120q55 0 123 -20l-29 -143q-37 12 -94 12q-88 0 -166 -33q160 -102 160 -278q0 -115 -44.5 -197 t-115 -122t-140 -56.5t-141.5 -16.5q-70 0 -123 11q-121 -86 -121 -164q6 -6 52.5 -9t120.5 -5l73 -3q119 -6 207 -21t179 -49t140.5 -101.5t49.5 -163.5q0 -199 -144.5 -330t-425.5 -131q-199 0 -345 98.5t-146 243.5zM297 -221q0 -82 94 -135.5t223 -53.5q197 0 301.5 87 t104.5 221q0 53 -36 90t-103.5 55t-128 26.5t-146.5 12.5q-119 0 -147 2q-84 -51 -123 -113.5t-39 -191.5zM338 795q0 -80 26.5 -135.5t70.5 -81t85 -34.5t86 -9t87 11t85 37.5t69.5 81t26.5 130.5q0 113 -86 171t-182 58t-182 -58t-86 -171z" />
<glyph unicode="h" horiz-adv-x="1241" d="M174 0v1679h172v-790q270 262 492 262q260 0 260 -350v-801h-172v801q0 178 -88 178q-233 0 -492 -268v-711h-172z" />
<glyph unicode="i" horiz-adv-x="555" d="M174 1475q0 45 29.5 73.5t75 28.5t74 -28.5t28.5 -73.5t-28.5 -75t-74 -30t-75 30t-29.5 75zM193 0v1126h169v-1126h-169z" />
<glyph unicode="j" horiz-adv-x="452" d="M-72 -401q61 8 111.5 101t50.5 212v1214h170v-1214q0 -178 -87 -308t-193 -167zM72 1475q0 45 29.5 73.5t74.5 28.5t74 -28.5t29 -73.5t-29 -75t-74 -30t-74.5 30t-29.5 75z" />
<glyph unicode="k" horiz-adv-x="1157" d="M174 0v1679h172v-950q383 268 449 397h174q-35 -133 -467 -458q66 -27 114 -80l338 -381q190 -207 213 -207h-231q-25 8 -102.5 91l-192.5 217l-147 169q-61 63 -99 74q-20 6 -49 -2v-549h-172z" />
<glyph unicode="l" horiz-adv-x="573" d="M174 299v1380h170v-1380q0 -111 23 -133q45 -45 135 -45l-6 -146q-180 0 -250 70q-72 72 -72 254z" />
<glyph unicode="m" horiz-adv-x="1882" d="M174 0v1126h172v-223q225 248 426 248q221 0 254 -254q227 254 432 254q260 0 260 -350v-801h-172v801q0 178 -88 178q-74 0 -140.5 -24.5t-123.5 -74t-87 -80t-75 -85.5v-715h-172v801q0 178 -88 178q-74 0 -140.5 -24.5t-123.5 -74t-87 -80t-75 -85.5v-715h-172z" />
<glyph unicode="n" horiz-adv-x="1261" d="M174 0v1126h172v-237q270 262 492 262q260 0 260 -350v-801h-172v801q0 178 -88 178q-227 0 -492 -268v-711h-172z" />
<glyph unicode="o" horiz-adv-x="1224" d="M123 563q0 166 41 285t112.5 182.5t154.5 92t181.5 28.5t181.5 -28.5t154.5 -92t112.5 -182.5t41 -285t-41 -284.5t-112.5 -182t-154.5 -92.5t-181.5 -29t-181.5 29t-154.5 92.5t-112.5 182t-41 284.5zM295 563.5q0 -237.5 91 -341t226.5 -103.5t226.5 103.5t91 341 t-91 341t-226.5 103.5t-226.5 -103.5t-91 -341z" />
<glyph unicode="p" horiz-adv-x="1292" d="M174 -532v1658h172v-217q189 242 414 242h4q180 -2 292.5 -170t112.5 -399q0 -287 -125.5 -447t-347.5 -160q-156 0 -350 156v-663h-172zM346 319q76 -76 174 -126t176 -50q137 0 219 117t82 322q0 162 -64.5 280.5t-168.5 120.5h-4q-243 0 -414 -266v-398z" />
<glyph unicode="q" horiz-adv-x="1292" d="M123 545q0 287 126 446.5t347 159.5q156 0 350 -156v131h172v-1658h-172v747q-193 -240 -414 -240h-4q-180 2 -292.5 170.5t-112.5 399.5zM295 545q0 -162 64.5 -281t168.5 -121h8q243 0 410 267v397q-80 76 -176 126t-174 50q-137 0 -219 -116.5t-82 -321.5z" />
<glyph unicode="r" horiz-adv-x="940" d="M174 0v1126h172v-217q141 242 285 242q78 0 146.5 -28.5t96.5 -57.5l29 -27l-119 -114q-49 63 -145 63q-158 0 -293 -282v-705h-172z" />
<glyph unicode="s" horiz-adv-x="1026" d="M92 205l119 96q45 -82 135 -131t191 -51q92 0 157.5 49t65.5 141q0 55 -43 96t-87 58.5t-124 42t-129 44t-106.5 56.5t-85 92.5t-27.5 130.5q0 78 26.5 138.5t65.5 94.5t90 55.5t91 27.5t79 6q223 0 354 -131l-110 -107q-88 94 -244 95q-39 0 -77 -11.5t-74.5 -54.5 t-36.5 -113q0 -35 17 -60.5t57 -46t70 -31.5t89 -29q74 -23 110.5 -35.5t95 -43t87.5 -62.5t52.5 -87t23.5 -125q0 -162 -115 -248t-277 -86q-131 0 -250.5 59.5t-189.5 170.5z" />
<glyph unicode="t" horiz-adv-x="819" d="M92 983v143h144v308h172v-308h270v-143h-270v-655q0 -41 2 -66.5t11 -64.5t32.5 -58.5t60.5 -19.5q96 0 178 78l96 -93q-135 -129 -319 -129q-233 0 -233 353v655h-144z" />
<glyph unicode="u" horiz-adv-x="1261" d="M164 326v800h172v-800q0 -178 88 -179q233 0 491 269v710h172v-1126h-172v236q-272 -260 -491 -261q-260 1 -260 351z" />
<glyph unicode="v" horiz-adv-x="1144" d="M72 1126h198l293 -870l6 -39l4 19q2 18 2 20q246 813 312 870h186q-35 -43 -140.5 -324.5t-193.5 -541.5l-88 -260h-149z" />
<glyph unicode="w" horiz-adv-x="1632" d="M72 1126h186l223 -839l6 -43l7 43l239 839h148l239 -839l8 -43l7 43q217 817 258 839h168q-25 -25 -114 -306t-165 -550l-78 -270h-145l-252 868l-248 -868h-162z" />
<glyph unicode="x" horiz-adv-x="1216" d="M82 0q29 12 187.5 226t250.5 349l-397 551h217l278 -407q266 395 304 407h213q-49 -23 -420 -548l409 -578h-217l-291 434q-295 -426 -321 -434h-213z" />
<glyph unicode="y" horiz-adv-x="1126" d="M59 -414q137 8 217 88q39 39 74 98.5t90 192.5l56 137l-394 1024h183l305 -790q307 754 352 790h195q-45 -43 -130 -232t-405 -974l-55 -131q-20 -47 -62.5 -113.5t-91.5 -113.5q-119 -115 -291 -125z" />
<glyph unicode="z" horiz-adv-x="1060" d="M102 0v145l635 838h-635v143h842v-143l-635 -838h525q113 0 145 35v-145q-12 -14 -49 -22.5t-68 -10.5l-31 -2h-729z" />
<glyph unicode="{" horiz-adv-x="962" d="M164 526v103q88 0 137 38t55 74l4 37v611q0 47 9.5 94t31 99t68.5 85t113 33q59 0 118.5 -16.5t90.5 -32.5l28 -19l-57 -143q-57 39 -180 39q-49 0 -50 -139v-613q0 -6 -1 -16t-9 -35t-20.5 -48.5t-39 -51t-61.5 -47.5q37 -20 64 -48t39 -50.5t19 -48t8 -36t1 -16.5v-612 q0 -139 50 -140q55 0 100 10.5t63 18.5l17 10l57 -143q-102 -68 -237 -68q-66 0 -113 33t-68.5 85t-31 99t-9.5 95v610q0 6 -1 16t-12 36t-29.5 45.5t-58.5 35.5t-95 16z" />
<glyph unicode="|" horiz-adv-x="503" d="M174 -532v2232h156v-2232h-156z" />
<glyph unicode="}" horiz-adv-x="962" d="M143 -477l58 143q57 -39 180 -39q49 0 49 140v610q0 14 4 37.5t36 77t89 86.5q-57 33 -89 83t-36 74.5t-4 40.5v613q0 139 -49 139q-55 0 -100 -10.5t-64 -18.5l-16 -10l-58 143q102 68 238 68q66 0 113 -33t68.5 -85t30.5 -99t9 -94v-611q0 -6 1 -16t11.5 -36t29 -45 t59 -35.5t96.5 -16.5v-103q-53 0 -93 -14t-58.5 -33.5t-30 -44t-13.5 -36t-2 -19.5v-612q0 -47 -9 -94.5t-30.5 -99.5t-69 -85t-112.5 -33q-59 0 -118.5 16.5t-90.5 32.5z" />
<glyph unicode="~" horiz-adv-x="1349" d="M123 709q10 8 31.5 20t99.5 32.5t168 20.5q82 0 256 -63q176 -61 262 -62q72 0 130 11.5t81 23.5l23 13l53 -103q-106 -68 -287 -67q-94 0 -295 69q-154 55 -223 55q-78 0 -137.5 -12t-79.5 -24l-21 -13z" />
<glyph unicode="&#xad;" d="M113 492v143h483v-143h-483z" />
<glyph unicode="&#x2000;" horiz-adv-x="860" />
<glyph unicode="&#x2001;" horiz-adv-x="1722" />
<glyph unicode="&#x2002;" horiz-adv-x="860" />
<glyph unicode="&#x2003;" horiz-adv-x="1722" />
<glyph unicode="&#x2004;" horiz-adv-x="573" />
<glyph unicode="&#x2005;" horiz-adv-x="430" />
<glyph unicode="&#x2006;" horiz-adv-x="286" />
<glyph unicode="&#x2007;" horiz-adv-x="286" />
<glyph unicode="&#x2008;" horiz-adv-x="215" />
<glyph unicode="&#x2009;" horiz-adv-x="344" />
<glyph unicode="&#x200a;" horiz-adv-x="94" />
<glyph unicode="&#x2010;" d="M113 492v143h483v-143h-483z" />
<glyph unicode="&#x2011;" d="M113 492v143h483v-143h-483z" />
<glyph unicode="&#x2012;" d="M113 492v143h483v-143h-483z" />
<glyph unicode="&#x2013;" horiz-adv-x="1312" d="M61 498v133h1129v-133h-1129z" />
<glyph unicode="&#x2014;" horiz-adv-x="1558" d="M82 498v133h1395v-133h-1395z" />
<glyph unicode="&#x2018;" horiz-adv-x="729" d="M113 1432l43 145l460 -229l-43 -97z" />
<glyph unicode="&#x2019;" horiz-adv-x="423" d="M92 1464q0 49 33 81t82 32q61 0 93 -50t32 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 81.5z" />
<glyph unicode="&#x201c;" horiz-adv-x="774" d="M92 1245q2 147 152 332l86 -29q-102 -127 -123 -243q55 0 90 -33t35 -82t-33 -81t-82 -32q-61 0 -93 50t-32 118zM442 1245q2 147 152 332l86 -29q-102 -127 -123 -243q55 0 90 -33t35 -82t-33 -81t-82 -32q-61 0 -93 50t-32 118z" />
<glyph unicode="&#x201d;" horiz-adv-x="774" d="M92 1464q0 49 33 81t82 32q61 0 93 -50t32 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 81.5zM442 1464q0 49 33 81t82 32q59 0 92 -50t33 -118q-2 -147 -152 -332l-86 29q102 127 121 244q-55 0 -89 32.5t-34 81.5z" />
<glyph unicode="&#x2026;" horiz-adv-x="1234" d="M915 100.5q0 49.5 33 81t82 31.5t80.5 -31.5t31.5 -81t-31.5 -82t-80.5 -32.5t-82 32.5t-33 82zM504 100.5q0 49.5 33 81t82 31.5t80.5 -31.5t31.5 -81t-31.5 -82t-80.5 -32.5t-82 32.5t-33 82zM92 100.5q0 49.5 33 81t82 31.5t80.5 -31.5t31.5 -81t-31.5 -82 t-80.5 -32.5t-82 32.5t-33 82z" />
<glyph unicode="&#x202f;" horiz-adv-x="344" />
<glyph unicode="&#x205f;" horiz-adv-x="430" />
<glyph unicode="&#x2122;" horiz-adv-x="2893" d="M1325 0v1577h180l514 -1352l2 -14l2 14l517 1352h180v-1577h-180v1106l2 31l-9 -31l-424 -1106h-174l-424 1106l-8 31l2 -31v-1106h-180zM20 1421v156h1110v-156h-468v-1421h-181v1421h-461z" />
<glyph unicode="&#xe000;" horiz-adv-x="1125" d="M0 1125h1125v-1125h-1125v1125z" />
<glyph unicode="&#xfb01;" horiz-adv-x="1380" d="M999 1475q0 45 29.5 73.5t75 28.5t74 -28.5t28.5 -73.5t-28.5 -75t-74 -30t-75 30t-29.5 75zM1018 0v1126h169v-1126h-169zM61 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332 v-983h-170v983h-146z" />
<glyph unicode="&#xfb02;" horiz-adv-x="1398" d="M999 299v1380h170v-1380q0 -111 23 -133q45 -45 135 -45l-6 -146q-180 0 -250 70q-72 72 -72 254zM61 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332v-983h-170v983h-146z" />
<glyph unicode="&#xfb03;" horiz-adv-x="2205" d="M1825 1475q0 45 29.5 73.5t75 28.5t74 -28.5t28.5 -73.5t-28.5 -75t-74 -30t-75 30t-29.5 75zM1844 0v1126h169v-1126h-169zM886 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332 v-983h-170v983h-146zM61 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332v-983h-170v983h-146z" />
<glyph unicode="&#xfb04;" horiz-adv-x="2224" d="M1825 299v1380h170v-1380q0 -111 23 -133q45 -45 135 -45l-6 -146q-180 0 -250 70q-72 72 -72 254zM886 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332v-983h-170v983h-146z M61 983v143h146v197q0 367 317 367q207 0 363 -129l-111 -107q-119 92 -252 92q-49 0 -79.5 -15t-45 -51t-18.5 -68t-4 -89v-197h332v-143h-332v-983h-170v983h-146z" />
</font>
</defs></svg>

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Binary file not shown.

@ -1,10 +0,0 @@
// Angustrap v0.1
// This file is for less compiling prupose, do not modify !
@import "../lib/bootstrap/less/bootstrap.less";
@import "../lib/fontawesome/less/font-awesome.less";
@FontAwesomePath: "../lib/fontawesome/font";
@import "variables.less";
@import "theme.less";
@import "../lib/bootstrap/less/utilities.less";

@ -1,187 +0,0 @@
body {
font: 18px/27px 'junctionregularRegular', Arial, sans-serif;
color: @textColor;
h1,
h2,
h3,
h4,
h5 {
font-family: @headingFont;
@media (max-width: 767px) {
text-shadow: 0 1px 0 rgba(0, 0, 0, .45);
}
}
h2 {
font-size: 40px;
font-weight: 400;
line-height: 40px;
}
}
.main {
height: 70%;
text-align: center;
padding-top: 3%;
padding-left: 0;
padding-right: 0;
.profil {
.qrcode {
display: block;
position: absolute;
left: 65%;
top: 30%;
opacity: 0;
.transition(all 500ms ease);
}
&:hover .qrcode {
opacity: 1;
}
padding-top: 8%;
h2 {
padding-bottom: 3%;
}
}
.hero {
padding-bottom: 2%;
}
.freelance {
@media (max-width: 767px) {
padding-bottom: 16%;
}
.row-fluid {
div {
padding: 10px;
}
}
}
.contact {
padding-top: 10%;
a {
text-decoration: none !important;
color: @textColor;
.transition(all 200ms ease);
padding-left: .5em;
padding-right: .5em;
&:hover {
color: @contactColor;
.transition(all 50ms ease);
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.28);
}
}
}
.projects {
margin-top: 5%;
.details {
/*position: fixed;*/
/*right: 2%;*/
/*top: 20%;*/
&.github {
padding-top: 5%;
}
}
a {
text-decoration: none !important;
color: @textColor;
&:hover {
color: @projectsColor;
}
}
.title {
text-align: right;
padding-right: 3em;
.transition(all 200ms ease-out);
border-right: 5px solid @textColor;
h2 {
padding-bottom: .6em;
}
}
}
}
.dock {
.animation-delay(1.5s);
width: 100%;
position: fixed;
bottom: 0;
text-align: center;
background: #fff;
.box-shadow(0 -30px 40px #fff);
.hoverText {
top: -5%;
display: none;
&.hovered {
display: block;
}
}
a {
color: @dockIconColor;
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.18);
padding-left: 1.5em;
padding-right: 1.5em;
.transition(all 100ms ease);
display: inline-block;
&:hover, &.active {
text-decoration: none;
.contact {
color: @contactColor;
}
.profil {
color: @profilColor;
}
.projects {
color: @projectsColor;
}
.blog {
color: @blogColor;
}
}
i {
font-size: 4.5em;
.transition(all 200ms ease);
&.contact {
font-size: 4.5em;
}
@media (max-width: 767px) {
font-size: 2em;
&.contact {
font-size: 1.5em;
}
}
}
}
}

@ -1,40 +0,0 @@
@import url('http://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800');
@import url('http://fonts.googleapis.com/css?family=Gentium+Book+Basic');
@import url('http://fonts.googleapis.com/css?family=Lato:100,300,400,700,900');
@headingFont: "Open Sans";
@titleFont: "Gentium Book Basic";
@orange: #ef4723;
@darkGrey: #222;
@white: rgb(252, 252, 252);
@dockIconColor: rgb(224,224,224);
@profilColor: rgb(81, 250, 128);
@projectsColor: rgb(87, 221, 247);
@blogColor: rgb(255, 140, 150);
@contactColor: rgb(249, 255, 107);
@font-face {
font-family: 'junctionregularRegular';
src: url('Junction-webfont.eot');
src: url('Junction-webfont.eot?#iefix') format('embedded-opentype'),
url('Junction-webfont.woff') format('woff'),
url('Junction-webfont.ttf') format('truetype'),
url('Junction-webfont.svg#junctionregularRegular') format('svg');
font-weight: normal;
font-style: normal;
}
@textFontSize: 18px;
@textColor: rgb(167, 167, 167);
// Animation delay
.animation-delay(@delay: 500ms) {
-webkit-animation-delay : @delay;
-moz-animation-delay : @delay;
animation-delay : @delay;
}

@ -1,60 +0,0 @@
# [Cha Cha Cha Changes](http://www.youtube.com/watch?v=pl3vxEudif8&t=0m53s)
## Master
## v0.4.0
* **Validate directive** has been upgraded
* **API BREAKING CHANGE!** now takes expressions instead of function references
* You must explicitly specify the $value variable, but you no longer need to create a function
* **NEW FEATURE** uiValidateWatch allows you to re-fire a validation rule (or all rules) when a related model changes (confirm_password)
* **CodeMirror directive** has been updated
* Now works with v3.02
* **NEW FEATURE** uiRefresh lets you specify an expression to watch for changes to refresh codemirror (useful for modals)
* **Mask directive** has many new fixes
* Fixes for **uiDate**
* **DateFormat directive** can now be declared in **uiConfig**
* **uiJq Passthru directive** has upgrades to support a wider variety of directives
* Now fires asyncronously post-angular-rendering of the view (**uiDefer** option is now always true)
* New **uiRefresh** lets you specify an expression to watch to re-fire the plugin (call $(elm).focus() when a modal opens)
* **Select2 directive** now adds support for setting the selected item by specifying a simple ID
* FINALLY have unit-tests for Select2!
* **IEShiv** has been simplified and stripped of browser-sniffing code (just use conditional comments)
* **Calendar directive** now performs better watching of events data
* Added optional equalsTracker attr (increment to force update from scope)
* **Sortable directive** now properly supports connectWith option
* New **route directive** that sets a boolean based on a pattern match of the current route (useful for tabs/navigation)
* Refactored **If directive** to be tidier
* **API BREAKING CHANGE!** **Modal directive** has been completely removed (if you still need it, grab the files from v0.3.x)
## v0.3.0
* New **format** filter
* Lots of cleanup! Consistent indentation, linting
* Custom builds via grunt (soon to be leveraged via builder)
* uiDate now watches options
* Rewrote ui-keypress (API is not backwards-compatible)
* **ui-**keypress has been expanded into **ui-keyup**, **ui-keydown** and **ui-keypress**
* The **ui-keypress** can now be used to `$event.preventDefault()` as expected
* Multiple combinations are separated by spaces, while multi-key combos are separated by dashes: `'enter alt-space 13-shift':'whatever()'`
* The string-notation (__a and be or c and d__) has been dropped completely
* Can now pass (or globally define) the value uiReset resets to
## v0.2.0
* Unit tests. Unit tests. Unit tests.
* New **inflector** filter (previously named **prettifier**)
* Added 2 alternative modes, now contains: humanize, underscore and variable
* **Passthrough directive** (uiJq) now fixes common ngModel problems due to trigger(change). Can optionally be disabled
* Removed **Length Filter** (you can instead do {{ ( myArray | filter: { gender:'m' } ).length }})
* Added **validate directive**, allows you to pass validation functions
* **Sortable directive**
* Fixed **unique filter**
* **Highlight filter** has had bug fixes
* **Event directive** has been refactored / improved
* **Keypress directive** has been refactored / improved
* New **if-directive** instead of **remove directive** (removed)
* New **google maps directive**
* New **animate directive** that transitions the injection of new DOM elements (transitioning the removal of DOM is still not supported yet)
* Improvements to **scrollfix directive**
## v0.1.0
* New folder structure
* Too many to list

@ -1,21 +0,0 @@
The MIT License
Copyright (c) 2012 the AngularUI Team, http://angular-ui.github.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

@ -1,73 +0,0 @@
# AngularUI - The companion suite for AngularJS
***
[![Build Status](https://secure.travis-ci.org/angular-ui/angular-ui.png)](http://travis-ci.org/angular-ui/angular-ui)
## Usage
### Requirements
* **AngularJS v1.0.0+** is currently required.
* **jQuery / Plugins** _(depends on directive)._ Check specific directive dependencies for more information
## Installation
The repository comes with the modules pre-built and compressed into the `build/` directory.
```javascript
angular.module('myApp', ['ui']);
```
The modules can be found in the [Directives](https://github.com/angular-ui/angular-ui/tree/master/modules/directives) and [Filters](https://github.com/angular-ui/angular-ui/tree/master/modules/filters) folders. Check out the readme file associated with each module for specific module usage information.
## Development
You do not need to build the project to use it - see above - but if you are working on it then this is what you need to know.
### Requirements
0. Install [Node.js](http://nodejs.org/) and NPM (should come with)
1. Install local dependencies:
```bash
$ npm install
```
2. Install global dependencies `grunt`, `coffee-script`, and `testacular`:
```bash
$ npm install -g testacular coffee-script grunt
```
### Build Files & Run Tests
Before you commit, always run `grunt` to build and test everything once.
```bash
$ grunt
```
### Test & Develop
The modules come with unit tests that should be run on any changes and certainly before commiting changes to the project. The unit tests should also provide further insight into the usage of the modules.
First, start the testacular server:
```bash
$ grunt server
```
Then, open your browser to http://localhost:8080 and run the watch command to re-run tests on every save:
```bash
$ grunt watch
```
### Publishing
For core team: if you wish to publish a new version follow these steps:
1. Bump the version number inside `package.json`
2. Build and test
3. Commit the updated `package.json` and `build/` folder on their own commit
4. Tag the commit: `git tag v[maj].[min].[patch]`
5. Push the tag: `git push [angular-ui] master --tags`

@ -1,59 +0,0 @@
/**
* AngularUI - The companion suite for AngularJS
* @version v0.4.0 - 2013-02-15
* @link http://angular-ui.github.com
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
// READ: http://docs-next.angularjs.org/guide/ie
// element tags are statically defined in order to accommodate lazy-loading whereby directives are also unknown
// The ieshiv takes care of our ui.directives and AngularJS's ng-view, ng-include, ng-pluralize, ng-switch.
// However, IF you have custom directives that can be used as html tags (yours or someone else's) then
// add list of directives into <code>window.myCustomTags</code>
// <!--[if lte IE 8]>
// <script>
// window.myCustomTags = [ 'yourCustomDirective', 'somebodyElsesDirective' ]; // optional
// </script>
// <script src="build/angular-ui-ieshiv.js"></script>
// <![endif]-->
(function (exports) {
var debug = window.ieShivDebug || false,
tags = [ "ngInclude", "ngPluralize", "ngView", "ngSwitch", "uiCurrency", "uiCodemirror", "uiDate", "uiEvent",
"uiKeypress", "uiKeyup", "uiKeydown", "uiMask", "uiMapInfoWindow", "uiMapMarker", "uiMapPolyline",
"uiMapPolygon", "uiMapRectangle", "uiMapCircle", "uiMapGroundOverlay", "uiModal", "uiReset",
"uiScrollfix", "uiSelect2", "uiShow", "uiHide", "uiToggle", "uiSortable", "uiTinymce"
];
window.myCustomTags = window.myCustomTags || []; // externally defined by developer using angular-ui directives
tags.push.apply(tags, window.myCustomTags);
var toCustomElements = function (str) {
var result = [];
var dashed = str.replace(/([A-Z])/g, function ($1) {
return " " + $1.toLowerCase();
});
var tokens = dashed.split(' ');
var ns = tokens[0];
var dirname = tokens.slice(1).join('-');
// this is finite list and it seemed senseless to create a custom method
result.push(ns + ":" + dirname);
result.push(ns + "-" + dirname);
result.push("x-" + ns + "-" + dirname);
result.push("data-" + ns + "-" + dirname);
return result;
};
for (var i = 0, tlen = tags.length; i < tlen; i++) {
var customElements = toCustomElements(tags[i]);
for (var j = 0, clen = customElements.length; j < clen; j++) {
var customElement = customElements[j];
document.createElement(customElement);
}
}
})(window);

@ -1,7 +0,0 @@
/**
* AngularUI - The companion suite for AngularJS
* @version v0.4.0 - 2013-02-15
* @link http://angular-ui.github.com
* @license MIT License, http://www.opensource.org/licenses/MIT
*/
(function(e){var t=window.ieShivDebug||!1,n=["ngInclude","ngPluralize","ngView","ngSwitch","uiCurrency","uiCodemirror","uiDate","uiEvent","uiKeypress","uiKeyup","uiKeydown","uiMask","uiMapInfoWindow","uiMapMarker","uiMapPolyline","uiMapPolygon","uiMapRectangle","uiMapCircle","uiMapGroundOverlay","uiModal","uiReset","uiScrollfix","uiSelect2","uiShow","uiHide","uiToggle","uiSortable","uiTinymce"];window.myCustomTags=window.myCustomTags||[],n.push.apply(n,window.myCustomTags);var r=function(e){var t=[],n=e.replace(/([A-Z])/g,function(e){return" "+e.toLowerCase()}),r=n.split(" "),i=r[0],s=r.slice(1).join("-");return t.push(i+":"+s),t.push(i+"-"+s),t.push("x-"+i+"-"+s),t.push("data-"+i+"-"+s),t};for(var i=0,s=n.length;i<s;i++){var o=r(n[i]);for(var u=0,a=o.length;u<a;u++){var f=o[u];document.createElement(f)}}})(window);

@ -1,50 +0,0 @@
/**
* import components to builds angular-ui.css
*/
/* ui-reset */
.ui-resetwrap {
position: relative;
display: inline-block;
}
.ui-reset {
position: absolute;
top: 0;
right: 0;
z-index: 2;
display: none;
height: 100%;
cursor: pointer;
}
.ui-resetwrap:hover .ui-reset {
display: block;
}
/* ui-currency */
.ui-currency-pos {
color: green;
}
.ui-currency-neg {
color: red;
}
.ui-currency-zero {
color: blue;
}
.ui-currency-pos.ui-bignum,
.ui-currency-neg.ui-smallnum {
font-size: 110%;
}
/* highlight */
.ui-match {
background: yellow;
}

File diff suppressed because it is too large Load Diff

@ -1 +0,0 @@
.ui-resetwrap{position:relative;display:inline-block}.ui-reset{position:absolute;top:0;right:0;z-index:2;display:none;height:100%;cursor:pointer}.ui-resetwrap:hover .ui-reset{display:block}.ui-currency-pos{color:green}.ui-currency-neg{color:red}.ui-currency-zero{color:blue}.ui-currency-pos.ui-bignum,.ui-currency-neg.ui-smallnum{font-size:110%}.ui-match{background:yellow}

File diff suppressed because one or more lines are too long

@ -1,47 +0,0 @@
# angular-ui-ieshiv
## Important!
If not installed properly, angular WILL throw an exception.
"No module: ui.directives"
Which means you have not included the angular-ui library in the file, or the shiv is in the wrong place.
WHY? Well, angular is throwing the exception and I can't catch and stop it. If properly setup, you should be good.
If not, then you should probably fix it or yank it out. Of course, then you won't have the shiv for ie.
## Description
This is used in order to support IE versions that do not support custom elements. For example:
<ng-view></ng-view>
<ui-currency ng-model="somenum"></ui-currency>
IE 8 and earlier do not allow custom tag elements into the DOM. It just ignores them.
In order to remedy, the trick is to tell browser by calling document.createElement('my-custom-element').
Then you can use, <my-custom-element>...</my-custom-element>, you also may need to define css styles.
In current version, this will automagically define directives found in the ui.directives module and
angular's ngView, ngInclude, ngPluralize directives.
## Usage
The shiv needs to run after angular has compiled the application. Best to load angular-ui-ieshiv.js at
bottom of <head> section.
<!--[if lte IE 8]> <script src="build/angular-ui-ieshiv.js"></script><![endif]-->
### Options
There will be
### Notes
- modules are searched for directives
- only IE 8 and earlier will cause shiv to run
- there will be a slight performance hit (for IE)
### Todo
- provide ability to specify which directives to include/exclude
- automagically locate all custom directives in current ng-app (this will involve recursion)

@ -1,52 +0,0 @@
// READ: http://docs-next.angularjs.org/guide/ie
// element tags are statically defined in order to accommodate lazy-loading whereby directives are also unknown
// The ieshiv takes care of our ui.directives and AngularJS's ng-view, ng-include, ng-pluralize, ng-switch.
// However, IF you have custom directives that can be used as html tags (yours or someone else's) then
// add list of directives into <code>window.myCustomTags</code>
// <!--[if lte IE 8]>
// <script>
// window.myCustomTags = [ 'yourCustomDirective', 'somebodyElsesDirective' ]; // optional
// </script>
// <script src="build/angular-ui-ieshiv.js"></script>
// <![endif]-->
(function (exports) {
var debug = window.ieShivDebug || false,
tags = [ "ngInclude", "ngPluralize", "ngView", "ngSwitch", "uiCurrency", "uiCodemirror", "uiDate", "uiEvent",
"uiKeypress", "uiKeyup", "uiKeydown", "uiMask", "uiMapInfoWindow", "uiMapMarker", "uiMapPolyline",
"uiMapPolygon", "uiMapRectangle", "uiMapCircle", "uiMapGroundOverlay", "uiModal", "uiReset",
"uiScrollfix", "uiSelect2", "uiShow", "uiHide", "uiToggle", "uiSortable", "uiTinymce"
];
window.myCustomTags = window.myCustomTags || []; // externally defined by developer using angular-ui directives
tags.push.apply(tags, window.myCustomTags);
var toCustomElements = function (str) {
var result = [];
var dashed = str.replace(/([A-Z])/g, function ($1) {
return " " + $1.toLowerCase();
});
var tokens = dashed.split(' ');
var ns = tokens[0];
var dirname = tokens.slice(1).join('-');
// this is finite list and it seemed senseless to create a custom method
result.push(ns + ":" + dirname);
result.push(ns + "-" + dirname);
result.push("x-" + ns + "-" + dirname);
result.push("data-" + ns + "-" + dirname);
return result;
};
for (var i = 0, tlen = tags.length; i < tlen; i++) {
var customElements = toCustomElements(tags[i]);
for (var j = 0, clen = customElements.length; j < clen; j++) {
var customElement = customElements[j];
document.createElement(customElement);
}
}
})(window);

@ -1,5 +0,0 @@
angular.module('ui.config', []).value('ui.config', {});
angular.module('ui.filters', ['ui.config']);
angular.module('ui.directives', ['ui.config']);
angular.module('ui', ['ui.filters', 'ui.directives', 'ui.config']);

@ -1,7 +0,0 @@
/**
* import components to builds angular-ui.css
*/
@import "mixins.less";
@import "modules/directives/reset/stylesheets/reset.less";
@import "modules/directives/currency/stylesheets/currency.less";
@import "modules/filters/highlight/highlight.less";

@ -1,11 +0,0 @@
.border-radius(@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
.box-shadow(@shadow: 0 1px 3px rgba(0,0,0,.25)) {
-webkit-box-shadow: @shadow;
-moz-box-shadow: @shadow;
box-shadow: @shadow;
}

@ -1,124 +0,0 @@
var testacular = require('testacular');
/*global module:false*/
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-recess');
// Project configuration.
grunt.initConfig({
builddir: 'build',
pkg: '<json:package.json>',
meta: {
banner: '/**\n' + ' * <%= pkg.description %>\n' +
' * @version v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
' * @link <%= pkg.homepage %>\n' +
' * @license MIT License, http://www.opensource.org/licenses/MIT\n' + ' */'
},
concat: {
build: {
src: ['<banner:meta.banner>', 'common/*.js'],
dest: '<%= builddir %>/<%= pkg.name %>.js'
},
ieshiv: {
src: ['<banner:meta.banner>', 'common/ieshiv/*.js'],
dest: '<%= builddir %>/<%= pkg.name %>-ieshiv.js'
}
},
min: {
build: {
src: ['<banner:meta.banner>', '<config:concat.build.dest>'],
dest: '<%= builddir %>/<%= pkg.name %>.min.js'
},
ieshiv: {
src: ['<banner:meta.banner>', '<config:concat.ieshiv.dest>'],
dest: '<%= builddir %>/<%= pkg.name %>-ieshiv.min.js'
}
},
recess: {
build: {
src: ['common/**/*.less'],
dest: '<%= builddir %>/<%= pkg.name %>.css',
options: {
compile: true
}
},
min: {
src: '<config:recess.build.dest>',
dest: '<%= builddir %>/<%= pkg.name %>.min.css',
options: {
compress: true
}
}
},
lint: {
files: ['grunt.js', 'common/**/*.js', 'modules/**/*.js']
},
watch: {
files: ['modules/**/*.js', 'common/**/*.js', 'templates/**/*.js'],
tasks: 'build test'
}
});
// Default task.
grunt.registerTask('default', 'build test');
grunt.registerTask('build', 'build all or some of the angular-ui modules', function () {
var jsBuildFiles = grunt.config('concat.build.src');
var lessBuildFiles = [];
if (this.args.length > 0) {
this.args.forEach(function(moduleName) {
var modulejs = grunt.file.expandFiles('modules/*/' + moduleName + '/*.js');
var moduleless = grunt.file.expandFiles('modules/*/' + moduleName + '/stylesheets/*.less', 'modules/*/' + moduleName + '/*.less');
jsBuildFiles = jsBuildFiles.concat(modulejs);
lessBuildFiles = lessBuildFiles.concat(moduleless);
});
grunt.config('concat.build.src', jsBuildFiles);
grunt.config('recess.build.src', lessBuildFiles);
} else {
grunt.config('concat.build.src', jsBuildFiles.concat(['modules/*/*/*.js']));
grunt.config('recess.build.src', lessBuildFiles.concat(grunt.config('recess.build.src')));
}
grunt.task.run('concat min recess:build recess:min');
});
grunt.registerTask('dist', 'change dist location', function() {
var dir = this.args[0];
if (dir) { grunt.config('builddir', dir); }
});
grunt.registerTask('server', 'start testacular server', function () {
//Mark the task as async but never call done, so the server stays up
var done = this.async();
testacular.server.start({ configFile: 'test/test-config.js'});
});
grunt.registerTask('test', 'run tests (make sure server task is run first)', function () {
var done = this.async();
grunt.utils.spawn({
cmd: process.platform === 'win32' ? 'testacular.cmd' : 'testacular',
args: process.env.TRAVIS ? ['start', 'test/test-config.js', '--single-run', '--no-auto-watch', '--reporters=dots', '--browsers=Firefox'] : ['run']
}, function (error, result, code) {
if (error) {
grunt.warn("Make sure the testacular server is online: run `grunt server`.\n" +
"Also make sure you have a browser open to http://localhost:8080/.\n" +
error.stdout + error.stderr);
//the testacular runner somehow modifies the files if it errors(??).
//this causes grunt's watch task to re-fire itself constantly,
//unless we wait for a sec
setTimeout(done, 1000);
} else {
grunt.log.write(result.stdout);
done();
}
});
});
};

@ -1,36 +0,0 @@
/**
* Animates the injection of new DOM elements by simply creating the DOM with a class and then immediately removing it
* Animations must be done using CSS3 transitions, but provide excellent flexibility
*
* @todo Add proper support for animating out
* @param [options] {mixed} Can be an object with multiple options, or a string with the animation class
* class {string} the CSS class(es) to use. For example, 'ui-hide' might be an excellent alternative class.
* @example <li ng-repeat="item in items" ui-animate=" 'ui-hide' ">{{item}}</li>
*/
angular.module('ui.directives').directive('uiAnimate', ['ui.config', '$timeout', function (uiConfig, $timeout) {
var options = {};
if (angular.isString(uiConfig.animate)) {
options['class'] = uiConfig.animate;
} else if (uiConfig.animate) {
options = uiConfig.animate;
}
return {
restrict: 'A', // supports using directive as element, attribute and class
link: function ($scope, element, attrs) {
var opts = {};
if (attrs.uiAnimate) {
opts = $scope.$eval(attrs.uiAnimate);
if (angular.isString(opts)) {
opts = {'class': opts};
}
}
opts = angular.extend({'class': 'ui-animate'}, options, opts);
element.addClass(opts['class']);
$timeout(function () {
element.removeClass(opts['class']);
}, 20, false);
}
};
}]);

@ -1,71 +0,0 @@
/*
* sample unit testing for sample templates and implementations
*/
describe('uiAnimate', function () {
// declare these up here to be global to all tests
var $rootScope, $compile, $timeout, uiConfig = angular.module('ui.config');
beforeEach(module('ui.directives'));
// inject in angular constructs. Injector knows about leading/trailing underscores and does the right thing
// otherwise, you would need to inject these into each test
beforeEach(inject(function (_$rootScope_, _$compile_, _$timeout_) {
$rootScope = _$rootScope_;
$compile = _$compile_;
$timeout = _$timeout_;
}));
afterEach(function () {
uiConfig.value('ui.config', {});
});
describe('behavior', function () {
it('should add a ui-animate class when the dom is compiled', function () {
var element = $compile('<div ui-animate></div>')($rootScope);
expect(element.hasClass('ui-animate')).toBeTruthy();
});
it('should remove the ui-animate class immediately after injection', function () {
var element = $compile('<div ui-animate></div>')($rootScope);
$timeout.flush();
expect(element.hasClass('ui-animate')).toBeFalsy();
});
});
describe('options', function () {
describe('passed', function () {
it('should use a string as the class', function () {
var element = $compile('<div ui-animate=" \'ui-hide\' "></div>')($rootScope);
expect(element.hasClass('ui-hide')).toBeTruthy();
});
it('should use an object\'s class attribute as the class', function () {
var element = $compile('<div ui-animate=" { \'class\' : \'ui-hide\' } "></div>')($rootScope);
expect(element.hasClass('ui-hide')).toBeTruthy();
});
});
describe('global', function () {
var uiConfig;
beforeEach(inject(function ($injector) {
uiConfig = $injector.get('ui.config');
}));
it('should use a string as the class', function () {
uiConfig.animate = 'ui-hide-global';
var element = $compile('<div ui-animate></div>')($rootScope);
expect(element.hasClass('ui-hide-global')).toBeTruthy();
});
it('should use an object\'s class attribute as the class', function () {
uiConfig.animate = { 'class': 'ui-hide-global' };
var element = $compile('<div ui-animate></div>')($rootScope);
expect(element.hasClass('ui-hide-global')).toBeTruthy();
});
});
});
});

@ -1,66 +0,0 @@
/*
* AngularJs Fullcalendar Wrapper for the JQuery FullCalendar
* API @ http://arshaw.com/fullcalendar/
*
* Angular Calendar Directive that takes in the [eventSources] nested array object as the ng-model and watches (eventSources.length + eventSources[i].length) for changes.
* Can also take in multiple event urls as a source object(s) and feed the events per view.
* The calendar will watch any eventSource array and update itself when a delta is created
* An equalsTracker attrs has been added for use cases that would render the overall length tracker the same even though the events have changed to force updates.
*
*/
angular.module('ui.directives').directive('uiCalendar',['ui.config', '$parse', function (uiConfig,$parse) {
uiConfig.uiCalendar = uiConfig.uiCalendar || {};
//returns calendar
return {
require: 'ngModel',
restrict: 'A',
link: function(scope, elm, attrs, $timeout) {
var sources = scope.$eval(attrs.ngModel);
var tracker = 0;
/* returns the length of all source arrays plus the length of eventSource itself */
var getSources = function () {
var equalsTracker = scope.$eval(attrs.equalsTracker);
tracker = 0;
angular.forEach(sources,function(value,key){
if(angular.isArray(value)){
tracker += value.length;
}
});
if(angular.isNumber(equalsTracker)){
return tracker + sources.length + equalsTracker;
}else{
return tracker + sources.length;
}
};
/* update the calendar with the correct options */
function update() {
//calendar object exposed on scope
scope.calendar = elm.html('');
var view = scope.calendar.fullCalendar('getView');
if(view){
view = view.name; //setting the default view to be whatever the current view is. This can be overwritten.
}
/* If the calendar has options added then render them */
var expression,
options = {
defaultView : view,
eventSources: sources
};
if (attrs.uiCalendar) {
expression = scope.$eval(attrs.uiCalendar);
} else {
expression = {};
}
angular.extend(options, uiConfig.uiCalendar, expression);
scope.calendar.fullCalendar(options);
}
update();
/* watches all eventSources */
scope.$watch(getSources, function( newVal, oldVal )
{
update();
});
}
};
}]);

@ -1,8 +0,0 @@
{
"core": [ "jquery" ],
"internal": [],
"external": [
"http://arshaw.com/js/fullcalendar-1.5.4/fullcalendar/fullcalendar.css",
"http://arshaw.com/js/fullcalendar-1.5.4/fullcalendar/fullcalendar.js"
]
}

@ -1,216 +0,0 @@
/*global beforeEach, afterEach, describe, it, inject, expect, module, spyOn, fullcalendar, angular, $*/
describe('uiCalendar', function () {
'use strict';
var scope, $compile;
beforeEach(module('ui'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
scope = _$rootScope_.$new();
$compile = _$compile_;
//Date Objects needed for event
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
// create an array of events, to pass into the directive.
scope.events = [
{title: 'All Day Event',start: new Date(y, m, 1),url: 'http://www.angularjs.org'},
{title: 'Long Event',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
{id: 999,title: 'Repeating Event',start: new Date(y, m, d - 3, 16, 0),allDay: false},
{id: 999,title: 'Repeating Event',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
// create an array of events, to pass into the directive.
scope.events2 = [
{title: 'All Day Event 2',start: new Date(y, m, 1),url: 'http://www.atlantacarlocksmith.com'},
{title: 'Long Event 2',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
{id: 998,title: 'Repeating Event 2',start: new Date(y, m, d - 3, 16, 0),allDay: false},
{id: 998,title: 'Repeating Event 2',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
//array to test equalsTracker with
scope.events3 = [
{title: 'All Day Event 3',start: new Date(y, m, 1),url: 'http://www.atlantacarlocksmith.com'},
{title: 'Long Event 3',start: new Date(y, m, d - 5),end: new Date(y, m, d - 2)},
{id: 998,title: 'Repeating Event 3',start: new Date(y, m, d - 3, 16, 0),allDay: false},
{id: 998,title: 'Repeating Event 3',start: new Date(y, m, d + 4, 16, 0),allDay: true}];
// create an array of events, to pass into the directive.
scope.events4 = [{title: 'All Day Event 3',start: new Date(y, m, 1),url: 'http://www.yoyoyo.com'}];
//equalsTracker to force the calendar to update on rare occasions
//ie... an event source is replacing another and has the same length as the prior eventSource
//or... replacing an eventSource that is an object with another eventSource
scope.equalsTracker = 0;
//event Sources array
scope.eventSources = [scope.events,scope.events2]; //End of Events Array
scope.addSource = function(source) {
scope.eventSources.push(source);
};
scope.addChild = function(array) {
array.push({
title: 'Click for Google ' + scope.events.length,
start: new Date(y, m, 28),
end: new Date(y, m, 29),
url: 'http://google.com/'
});
};
scope.remove = function(array,index) {
array.splice(index,1);
};
scope.uiConfig = {
calendar:{
height: 200,
weekends: false,
defaultView: 'month'
}
};
}));
afterEach(function() {
angular.module('ui.config').value('ui.config', {}); // cleanup
});
describe('compiling this directive and checking for events inside the calendar', function () {
/* test the calendar's events length */
it('should excpect to load 4 events to scope', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length).toBe(4);
});
/* test to check the title of the first event. */
it('should excpect to be All Day Event', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[0][0].title).toBe('All Day Event');
});
/* test to make sure the event has a url assigned to it. */
it('should expect the url to = http://www.angularjs.org', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[0][0].url).toBe('http://www.angularjs.org');
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[1][0].url).toBe('http://www.atlantacarlocksmith.com');
});
/* test the 3rd events' allDay field. */
it('should expect the fourth Events all Day field to equal true', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[0][3].allDay).toNotBe(false);
});
/* Tests the height of the calendar. */
it('should expect the calendar attribute height to be 200', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].height).toEqual(200);
});
/* Tests the weekends boolean of the calendar. */
it('should expect the calendar attribute weekends to be false', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].weekends).toEqual(false);
});
/* Test to make sure that when an event is added to the calendar everything is updated with the new event. */
it('should expect the scopes events to increase by 2', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length).toEqual(4);
scope.addChild(scope.events);
scope.addChild(scope.events);
expect($.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length).toEqual(6);
});
/* Test to make sure the calendar is updating itself on changes to events length. */
it('should expect the calendar to update itself with new events', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
var clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
expect(clientEventsLength).toEqual(4);
//remove an event from the scope.
scope.remove(scope.events,0);
//events should auto update inside the calendar.
clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
expect(clientEventsLength).toEqual(3);
});
/* Test to make sure header options can be overwritten */
it('should overwrite default header options', function () {
spyOn($.fn, 'fullCalendar');
scope.uiConfig2 = {
calendar:{
header: {center: 'title'}
}
};
$compile('<div ui-calendar="uiConfig2.calendar" ng-model="eventSources"></div>')(scope);
expect($.fn.fullCalendar.mostRecentCall.args[0].hasOwnProperty('header')).toEqual(true);
var header = $.fn.fullCalendar.mostRecentCall.args[0].header;
expect(header).toEqual({center: 'title'});
});
/* Test to see if calendar is watching all eventSources for changes. */
it('should update the calendar if any eventSource array contains a delta', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
var clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
var clientEventsLength2 = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[1].length;
expect(clientEventsLength).toEqual(4);
expect(clientEventsLength2).toEqual(4);
//remove an event from the scope.
scope.remove(scope.events2,0);
//events should auto update inside the calendar.
clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
clientEventsLength2 = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[1].length;
expect(clientEventsLength).toEqual(4);
expect(clientEventsLength2).toEqual(3);
scope.remove(scope.events,0);
clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
expect(clientEventsLength).toEqual(3);
});
/* Test to see if calendar is updating when a new eventSource is added. */
it('should update the calendar if an eventSource is Added', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources"></div>')(scope);
var clientEventSources = $.fn.fullCalendar.mostRecentCall.args[0].eventSources.length;
expect(clientEventSources).toEqual(2);
//add new source to calendar
scope.addSource(scope.events4);
//eventSources should auto update inside the calendar.
clientEventSources = $.fn.fullCalendar.mostRecentCall.args[0].eventSources.length;
expect(clientEventSources).toEqual(3);
//go ahead and add some more events to the array and check those too.
scope.addChild(scope.events4);
var clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[2].length;
expect(clientEventsLength).toEqual(2);
});
/* Test to see if calendar is updating when an eventSource replaces another with an equal length. */
it('should update the calendar if an eventSource has same length as prior eventSource', function () {
spyOn($.fn, 'fullCalendar');
$compile('<div ui-calendar="uiConfig.calendar" ng-model="eventSources" equals-tracker="equalsTracker"></div>')(scope);
var clientEventSources = $.fn.fullCalendar.mostRecentCall.args[0].eventSources;
var clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
expect(clientEventsLength).toEqual(4);
expect(clientEventSources.length).toEqual(2);
expect(clientEventSources[1][0].title).toEqual('All Day Event 2');
//replace source with one that has the same length
scope.eventSources.splice(1,1,scope.events3);
//must update the equalsTracker as we would detect that the length is equal from controller
scope.equalsTracker++;
//eventSources should update inside the calendar since we incremented the equalsTracker
clientEventSources = $.fn.fullCalendar.mostRecentCall.args[0].eventSources;
expect(clientEventSources.length).toEqual(2);
expect(clientEventSources[1][0].title).toEqual('All Day Event 3');
//remove an event to prove autobinding still works
scope.remove(scope.events,0);
clientEventsLength = $.fn.fullCalendar.mostRecentCall.args[0].eventSources[0].length;
expect(clientEventsLength).toEqual(3);
});
});
});

@ -1,77 +0,0 @@
/*global angular, CodeMirror, Error*/
/**
* Binds a CodeMirror widget to a <textarea> element.
*/
angular.module('ui.directives').directive('uiCodemirror', ['ui.config', '$timeout', function (uiConfig, $timeout) {
'use strict';
var events = ["cursorActivity", "viewportChange", "gutterClick", "focus", "blur", "scroll", "update"];
return {
restrict:'A',
require:'ngModel',
link:function (scope, elm, attrs, ngModel) {
var options, opts, onChange, deferCodeMirror, codeMirror;
if (elm[0].type !== 'textarea') {
throw new Error('uiCodemirror3 can only be applied to a textarea element');
}
options = uiConfig.codemirror || {};
opts = angular.extend({}, options, scope.$eval(attrs.uiCodemirror));
onChange = function (aEvent) {
return function (instance, changeObj) {
var newValue = instance.getValue();
if (newValue !== ngModel.$viewValue) {
ngModel.$setViewValue(newValue);
scope.$apply();
}
if (typeof aEvent === "function")
aEvent(instance, changeObj);
};
};
deferCodeMirror = function () {
codeMirror = CodeMirror.fromTextArea(elm[0], opts);
codeMirror.on("change", onChange(opts.onChange));
for (var i = 0, n = events.length, aEvent; i < n; ++i) {
aEvent = opts["on" + events[i].charAt(0).toUpperCase() + events[i].slice(1)];
if (aEvent === void 0) continue;
if (typeof aEvent !== "function") continue;
codeMirror.on(events[i], aEvent);
}
// CodeMirror expects a string, so make sure it gets one.
// This does not change the model.
ngModel.$formatters.push(function (value) {
if (angular.isUndefined(value) || value === null) {
return '';
}
else if (angular.isObject(value) || angular.isArray(value)) {
throw new Error('ui-codemirror cannot use an object or an array as a model');
}
return value;
});
// Override the ngModelController $render method, which is what gets called when the model is updated.
// This takes care of the synchronizing the codeMirror element with the underlying model, in the case that it is changed by something else.
ngModel.$render = function () {
codeMirror.setValue(ngModel.$viewValue);
};
// Watch ui-refresh and refresh the directive
if (attrs.uiRefresh) {
scope.$watch(attrs.uiRefresh, function(newVal, oldVal){
// Skip the initial watch firing
if (newVal !== oldVal)
$timeout(codeMirror.refresh);
});
}
};
$timeout(deferCodeMirror);
}
};
}]);

@ -1,8 +0,0 @@
{
"core": [ "jquery" ],
"internal": [],
"external": [
"http://codemirror.net/lib/codemirror.js",
"http://codemirror.net/lib/codemirror.css",
]
}

@ -1,160 +0,0 @@
/*global beforeEach, afterEach, describe, it, inject, expect, module, spyOn, CodeMirror, angular, $*/
/**
* TODO Test all the CodeMirror events : cursorActivity viewportChange gutterClick focus blur scroll update.
* with <textarea ui-codemirror="{onChange: doChange ,onCursorActivity: doSomething}" ng-model="foo">
*
*/
describe('uiCodemirror', function () {
'use strict';
// declare these up here to be global to all tests
var scope, $compile, $timeout, uiConfig = angular.module('ui.config');
beforeEach(module('ui.directives'));
beforeEach(function () {
uiConfig.value('ui.config', {codemirror: {bar: 'baz'}});
});
// inject in angular constructs. Injector knows about leading/trailing underscores and does the right thing
// otherwise, you would need to inject these into each test
beforeEach(inject(function (_$rootScope_, _$compile_, _$timeout_) {
scope = _$rootScope_.$new();
$compile = _$compile_;
$timeout = _$timeout_;
}));
afterEach(function () {
uiConfig.value('ui.config', {}); // cleanup
});
describe('compiling this directive', function () {
it('should throw an error if used against a non-textarea', function () {
function compile() {
$compile('<div ui-codemirror ng-model="foo"></div>')(scope);
}
expect(compile).toThrow();
});
it('should not throw an error when used against a textarea', function () {
function compile() {
$compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
}
expect(compile).not.toThrow();
});
it('should throw an error when no ngModel attribute defined', function () {
function compile() {
$compile('<textarea ui-codemirror></textarea>')(scope);
}
expect(compile).toThrow();
});
it('should watch the uiCodemirror attribute', function () {
spyOn(scope, '$watch');
$compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
$timeout.flush();
expect(scope.$watch).toHaveBeenCalled();
});
});
describe('while spying on the CodeMirror instance', function () {
var codemirror;
beforeEach(function () {
var fromTextArea = CodeMirror.fromTextArea;
spyOn(CodeMirror, 'fromTextArea').andCallFake(function () {
codemirror = fromTextArea.apply(this, arguments);
return codemirror;
});
});
describe('verify the directive options', function () {
it('should include the passed options', function () {
$compile('<textarea ui-codemirror="{oof: \'baar\'}" ng-model="foo"></textarea>')(scope);
$timeout.flush();
expect(CodeMirror.fromTextArea.mostRecentCall.args[1].oof).toEqual("baar");
});
it('should include the default options', function () {
$compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
$timeout.flush();
expect(CodeMirror.fromTextArea.mostRecentCall.args[1].bar).toEqual('baz');
});
});
describe('when uiRefresh is added', function () {
it('should trigger the CodeMirror.refresh() method', function () {
$compile('<textarea ui-codemirror ng-model="foo" ui-refresh="bar"></textarea>')(scope);
$timeout.flush();
spyOn(codemirror, 'refresh');
scope.$apply('bar = true');
$timeout.flush();
expect(codemirror.refresh).toHaveBeenCalled();
});
});
describe('when the IDE changes', function () {
it('should update the model', function () {
$compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
scope.$apply("foo = 'bar'");
$timeout.flush();
var value = 'baz';
codemirror.setValue(value);
expect(scope.foo).toBe(value);
});
});
describe('when the model changes', function () {
it('should update the IDE', function () {
var element = $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
scope.foo = 'bar';
scope.$apply();
$timeout.flush();
expect(codemirror.getValue()).toBe(scope.foo);
});
});
describe('when the model is undefined/null', function () {
it('should update the IDE with an empty string', function () {
var element = $compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
scope.$apply();
$timeout.flush();
expect(scope.foo).toBe(undefined);
expect(codemirror.getValue()).toBe('');
scope.$apply('foo = "bar"');
expect(scope.foo).toBe('bar');
expect(codemirror.getValue()).toBe('bar');
scope.$apply('foo = null');
expect(scope.foo).toBe(null);
expect(codemirror.getValue()).toBe('');
});
});
});
describe('when the model is an object or an array', function () {
it('should throw an error', function () {
function compileWithObject() {
$compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
$timeout.flush();
scope.foo = {};
scope.$apply();
}
function compileWithArray() {
$compile('<textarea ui-codemirror ng-model="foo"></textarea>')(scope);
$timeout.flush();
scope.foo = [];
scope.$apply();
}
expect(compileWithObject).toThrow();
expect(compileWithArray).toThrow();
});
});
});

@ -1,46 +0,0 @@
# ui-currency directive
This directive gives greater control over your currency elements by allowing you to set CSS styles based on the number's sign.
In angular, you are only able to specify what the currency symbol is (however, you might not want to change it for localization).
## Usage
Apply the directive to your html elements:
myAppModule.controller('MyController', function($scope) {
$scope.SomeNumber = 123;
});
<span ui-currency ng-model="SomeNumber"></span>
Default styles are in angular-ui.css and are pretty boring, you could just override these in your
stylesheet and make things most excellent (e.g. increasing size for negatives, doing a hover sorta thingy )
.ui-currency-pos {
color: green;
}
.ui-currency-neg {
color: red;
}
.ui-currency-zero {
color: blue;
}
.ui-currency-pos.ui-bignum, .ui-currency-neg.ui-smallnum {
font-size: 110%;
}
### Options
All the options can be controlled by ui.config (see Global Defaults) or passed in the ui-currency attribute on the declaration.
The symbol attribute defaults to null and is then controlled by the default locale settings.
<span ui-currency="{ pos='pstyle' neg='nstyle' zero='zstyle' symbol='USD$' bignum='1000' smallnum='-1000'}" ng-model="SomeNumber" ></span>
If the model is greater than or equal to 1000 add ui-bignum to css class, if less than or equal to -1000 add ui-small num. If attr is-total attribute
is set the bignum/smallnum is not applied. This is useful if the options are global and you don't want totals to necessarily have these classes.
### Notes
This directive wraps angular's currency filter. If that changes, you are on your own.

@ -1,45 +0,0 @@
/*
Gives the ability to style currency based on its sign.
*/
angular.module('ui.directives').directive('uiCurrency', ['ui.config', 'currencyFilter' , function (uiConfig, currencyFilter) {
var options = {
pos: 'ui-currency-pos',
neg: 'ui-currency-neg',
zero: 'ui-currency-zero'
};
if (uiConfig.currency) {
angular.extend(options, uiConfig.currency);
}
return {
restrict: 'EAC',
require: 'ngModel',
link: function (scope, element, attrs, controller) {
var opts, // instance-specific options
renderview,
value;
opts = angular.extend({}, options, scope.$eval(attrs.uiCurrency));
renderview = function (viewvalue) {
var num;
num = viewvalue * 1;
element.toggleClass(opts.pos, (num > 0) );
element.toggleClass(opts.neg, (num < 0) );
element.toggleClass(opts.zero, (num === 0) );
if (viewvalue === '') {
element.text('');
} else {
element.text(currencyFilter(num, opts.symbol));
}
return true;
};
controller.$render = function () {
value = controller.$viewValue;
element.val(value);
renderview(value);
};
}
};
}]);

@ -1,14 +0,0 @@
/* ui-currency */
.ui-currency-pos {
color: green;
}
.ui-currency-neg {
color: red;
}
.ui-currency-zero {
color: blue;
}
.ui-currency-pos.ui-bignum, .ui-currency-neg.ui-smallnum {
font-size: 110%;
}

@ -1,95 +0,0 @@
describe('uiCurrency', function () {
var scope;
beforeEach(module('ui'));
beforeEach(inject(function ($rootScope) {
scope = $rootScope.$new();
}));
describe('use on a div element with two-way binding', function () {
it('should have ui-currency-pos style non-zero positive model number ', function () {
inject(function ($compile) {
var element;
element = $compile("<div ui-currency ng-model='aNum'></div>")(scope);
scope.$apply(function () {
scope.aNum = 0.5123;
});
expect(element.text()).toEqual('$0.51');
expect(element.hasClass('ui-currency-pos')).toBeTruthy();
expect(element.hasClass('ui-currency-neg')).toBeFalsy();
expect(element.hasClass('ui-currency-zero')).toBeFalsy();
});
});
it('should have ui-currency-neg style when negative model number', function () {
inject(function ($compile) {
var element;
element = $compile("<div ui-currency ng-model='aNum'></div>")(scope);
scope.$apply(function () {
scope.aNum = -123;
});
expect(element.text()).toEqual('($123.00)');
expect(element.hasClass('ui-currency-pos')).toBeFalsy();
expect(element.hasClass('ui-currency-neg')).toBeTruthy();
});
});
it('should have ui-currency-zero style when zero model number', function () {
inject(function ($compile) {
var element;
element = $compile("<div ui-currency ng-model='aNum'></div>")(scope);
scope.$apply(function () {
scope.aNum = 0;
});
expect(element.text()).toEqual('$0.00');
expect(element.hasClass('ui-currency-pos')).toBeFalsy();
expect(element.hasClass('ui-currency-neg')).toBeFalsy();
expect(element.hasClass('ui-currency-zero')).toBeTruthy();
});
});
it('should not have any ui-currency styles or a value at all when missing scope model value', function () {
inject(function ($compile) {
var element;
element = $compile("<div ui-currency ng-model='aMissingNum'></div>")(scope);
expect(element.text()).toEqual('');
expect(element.hasClass('ui-currency-pos')).toBeFalsy();
expect(element.hasClass('ui-currency-neg')).toBeFalsy();
expect(element.hasClass('ui-currency-zero')).toBeFalsy();
});
});
it('should not have any ui-currency styles or a value at all when provided a non-numeric model value', function () {
inject(function ($compile) {
var element;
element = $compile("<div ui-currency ng-model='aBadNum'></div>")(scope);
scope.$apply(function () {
scope.aBadNum = 'bad';
});
expect(element.text()).toEqual('');
expect(element.hasClass('ui-currency-pos')).toBeFalsy();
expect(element.hasClass('ui-currency-neg')).toBeFalsy();
expect(element.hasClass('ui-currency-zero')).toBeFalsy();
});
});
it('should have user-defined positive style when provided in uiCurrency attr', function () {
inject(function ($compile) {
var element;
element = $compile("<div ui-currency=\"{ pos:'pstyle' }\" ng-model='aNum'></div>")(scope);
scope.$apply(function () {
scope.aNum = 1;
});
expect(element.hasClass('pstyle')).toBeTruthy();
});
});
// Presumption is if above works then no need to test other cases, given the coverage in previous describe
});
describe('use on a tag element', function () {
it('should have a defined element', function () {
inject(function ($compile) {
var element;
element = $compile("<ui-currency ng-model='aNum'></ui-currency>")(scope);
scope.$apply(function () {
scope.aNum = 1;
});
expect(element).toBeDefined();
expect(element.text()).toEqual('$1.00');
});
});
});
});

@ -1,73 +0,0 @@
# ui-date directive
This directive allows you to add a date-picker to your form elements.
# Requirements
- JQuery
- JQueryUI
- [Date.toISOString()](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Date/toISOString) (requires [polyfill](https://github.com/kriskowal/es5-shim/) for &le;IE8)
# Usage
Load the script file in your application:
<script type="text/javascript" src="angular-ui.js"></script>
Add the date module as a dependency to your application module:
var myAppModule = angular.module('MyApp', ['ui.directives'])
Apply the directive to your form elements:
<input ui-date name="DateOfBirth"></input>
## Options
All the jQueryUI DatePicker options can be passed through the directive.
myAppModule.controller('MyController', function($scope) {
$scope.dateOptions = {
changeYear: true,
changeMonth: true,
yearRange: '1900:-0'
};
});
<input ui-date="dateOptions" name="DateOfBirth"></input>
## Static Inline Picker
If you want a static picker then simply apply the directive to a div rather than an input element.
<div ui-date="dateOptions" name="DateOfBirth"></div>
# Working with ng-model
The ui-date directive plays nicely with ng-model and validation directives such as ng-required.
If you add the ng-model directive to same the element as ui-date then the picked date is automatically synchronized with the model value.
_The ui-date directive stores and expects the model value to be a standard javascript Date object._
## ui-date-format directive
The ui-date directive only works with Date objects.
If you want to pass date strings to and from the date directive via ng-model then you must use the ui-date-format directive.
This directive specifies the format of the date string that will be expected in the ng-model.
The format string syntax is that defined by the JQueryUI Date picker. For example
<input ui-date ui-date-format="DD, d MM, yy" ng-model="myDate"></input>
Now you can set myDate in the controller.
$scope.myDate = "Thursday, 11 October, 2012";
## ng-required directive
If you apply the required directive to element then the form element is invalid until a date is picked.
Note: Remember that the ng-required directive must be explictly set, i.e. to "true". This is especially true on divs:
<div ui-date="dateOptions" name="DateOfBirth" ng-required="true"></div>

@ -1,111 +0,0 @@
/*global angular */
/*
jQuery UI Datepicker plugin wrapper
@note If IE8 make sure you have a polyfill for Date.toISOString()
@param [ui-date] {object} Options to pass to $.fn.datepicker() merged onto ui.config
*/
angular.module('ui.directives')
.directive('uiDate', ['ui.config', function (uiConfig) {
'use strict';
var options;
options = {};
if (angular.isObject(uiConfig.date)) {
angular.extend(options, uiConfig.date);
}
return {
require:'?ngModel',
link:function (scope, element, attrs, controller) {
var getOptions = function () {
return angular.extend({}, uiConfig.date, scope.$eval(attrs.uiDate));
};
var initDateWidget = function () {
var opts = getOptions();
// If we have a controller (i.e. ngModelController) then wire it up
if (controller) {
var updateModel = function () {
scope.$apply(function () {
var date = element.datepicker("getDate");
element.datepicker("setDate", element.val());
controller.$setViewValue(date);
element.blur();
});
};
if (opts.onSelect) {
// Caller has specified onSelect, so call this as well as updating the model
var userHandler = opts.onSelect;
opts.onSelect = function (value, picker) {
updateModel();
scope.$apply(function() {
userHandler(value, picker);
});
};
} else {
// No onSelect already specified so just update the model
opts.onSelect = updateModel;
}
// In case the user changes the text directly in the input box
element.bind('change', updateModel);
// Update the date picker when the model changes
controller.$render = function () {
var date = controller.$viewValue;
if ( angular.isDefined(date) && date !== null && !angular.isDate(date) ) {
throw new Error('ng-Model value must be a Date object - currently it is a ' + typeof date + ' - use ui-date-format to convert it from a string');
}
element.datepicker("setDate", date);
};
}
// If we don't destroy the old one it doesn't update properly when the config changes
element.datepicker('destroy');
// Create the new datepicker widget
element.datepicker(opts);
if ( controller ) {
// Force a render to override whatever is in the input text box
controller.$render();
}
};
// Watch for changes to the directives options
scope.$watch(getOptions, initDateWidget, true);
}
};
}
])
.directive('uiDateFormat', ['ui.config', function(uiConfig) {
var directive = {
require:'ngModel',
link: function(scope, element, attrs, modelCtrl) {
var dateFormat = attrs.uiDateFormat || uiConfig.dateFormat;
if ( dateFormat ) {
// Use the datepicker with the attribute value as the dateFormat string to convert to and from a string
modelCtrl.$formatters.push(function(value) {
if (angular.isString(value) ) {
return $.datepicker.parseDate(dateFormat, value);
}
});
modelCtrl.$parsers.push(function(value){
if (value) {
return $.datepicker.formatDate(dateFormat, value);
}
});
} else {
// Default to ISO formatting
modelCtrl.$formatters.push(function(value) {
if (angular.isString(value) ) {
return new Date(value);
}
});
modelCtrl.$parsers.push(function(value){
if (value) {
return value.toISOString();
}
});
}
}
};
return directive;
}]);

@ -1,5 +0,0 @@
{
"core": [ "jquery", "jquery-ui" ],
"internal": [],
"external": []
}

@ -1,354 +0,0 @@
/*global describe, beforeEach, it, inject, expect, module, $*/
describe('uiDate', function() {
'use strict';
var selectDate;
selectDate = function(element, date) {
element.datepicker('setDate', date);
$.datepicker._selectDate(element);
};
beforeEach(module('ui.directives'));
describe('simple use on input element', function() {
it('should have a date picker attached', function() {
inject(function($compile, $rootScope) {
var element;
element = $compile("<input ui-date/>")($rootScope);
expect(element.datepicker()).toBeDefined();
});
});
it('should be able to get the date from the model', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<input ui-date ng-model='x'/>")($rootScope);
$rootScope.$apply(function() {
$rootScope.x = aDate;
});
expect(element.datepicker('getDate')).toEqual(aDate);
});
});
it('should put the date in the model', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<input ui-date ng-model='x'/>")($rootScope);
$rootScope.$apply();
selectDate(element, aDate);
expect($rootScope.x).toEqual(aDate);
});
});
it('should blur the input element after selecting a date', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<input ui-date ng-model='x'/>")($rootScope);
$rootScope.$apply();
$(document.body).append(element); // Need to add it to the document so that it can get focus
element.focus();
expect(document.activeElement).toEqual(element[0]);
selectDate(element, aDate);
expect(document.activeElement).not.toEqual(element[0]);
element.remove(); // And then remove it again!
});
});
});
describe('when model is not a Date', function() {
var element;
var scope;
beforeEach(inject(function($compile, $rootScope) {
element = $compile('<input ui-date="{dateFormat: \'yy-mm-dd\'}" ng-model="x"/>')($rootScope);
scope = $rootScope;
}));
it('should not freak out when the model is null', function() {
scope.$apply(function() {
scope.x = null;
});
expect(element.datepicker('getDate')).toBe(null);
});
it('should not freak out when the model is undefined', function() {
scope.$apply(function() {
scope.x = undefined;
});
expect(element.datepicker('getDate')).toBe(null);
});
it('should throw an error if you try to pass in a boolean when the model is false', function() {
expect(function() {
scope.$apply(function() {
scope.x = false;
});
}).toThrow();
});
});
it('should update the input field correctly on a manual update', function() {
inject(function($compile, $rootScope) {
var dateString = '2012-08-17';
var dateObj = $.datepicker.parseDate('yy-mm-dd', dateString);
var element = $compile('<input ui-date="{dateFormat: \'yy-mm-dd\'}" ng-model="x"/>')($rootScope);
$rootScope.$apply(function() {
$rootScope.x = dateObj;
});
// Now change the data in the input box
dateString = '2012-8-01';
dateObj = $.datepicker.parseDate('yy-mm-dd', dateString);
element.val(dateString);
element.trigger("change");
expect(element.datepicker('getDate')).toEqual(dateObj);
expect(element.val()).toEqual('2012-08-01');
$rootScope.$digest();
expect($rootScope.x).toEqual(dateObj);
});
});
describe("use with user events", function() {
it('should call the user onSelect event within a scope.$apply context', function() {
inject(function($compile, $rootScope) {
var watched = false;
$rootScope.myDateSelected = function() {
$rootScope.watchMe = true;
}
$rootScope.$watch("watchMe", function(watchMe) {
if (watchMe) {
watched = true;
}
});
var aDate = new Date(2012,9,11);
var element = $compile('<input ui-date="{onSelect: myDateSelected}" ng-model="x"/>')($rootScope);
$rootScope.$apply();
selectDate(element, aDate);
expect(watched).toBeTruthy();
});
});
});
describe('use with ng-required directive', function() {
it('should be invalid initially', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<input ui-date ng-model='x' ng-required='true' />")($rootScope);
$rootScope.$apply();
expect(element.hasClass('ng-invalid')).toBeTruthy();
});
});
it('should be valid if model has been specified', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<input ui-date ng-model='x' ng-required='true' />")($rootScope);
$rootScope.$apply(function() {
$rootScope.x = aDate;
});
expect(element.hasClass('ng-valid')).toBeTruthy();
});
});
it('should be valid after the date has been picked', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<input ui-date ng-model='x' ng-required='true' />")($rootScope);
$rootScope.$apply();
selectDate(element, aDate);
expect(element.hasClass('ng-valid')).toBeTruthy();
});
});
});
describe('simple use on a div element', function() {
it('should have a date picker attached', function() {
inject(function($compile, $rootScope) {
var element;
element = $compile("<div ui-date></div>")($rootScope);
expect(element.datepicker()).toBeDefined();
});
});
it('should be able to get the date from the model', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<div ui-date ng-model='x'></div>")($rootScope);
$rootScope.$apply(function() {
$rootScope.x = aDate;
});
expect(element.datepicker('getDate')).toEqual(aDate);
});
});
it('should put the date in the model', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<div ui-date ng-model='x'></div>")($rootScope);
$rootScope.$apply();
selectDate(element, aDate);
expect($rootScope.x).toEqual(aDate);
});
});
});
describe('use with ng-required directive', function() {
it('should be invalid initially', function() {
inject(function($compile, $rootScope) {
var element = $compile("<div ui-date ng-model='x' ng-required='true' ></div>")($rootScope);
$rootScope.$apply();
expect(element.hasClass('ng-invalid')).toBeTruthy();
});
});
it('should be valid if model has been specified', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<div ui-date ng-model='x' ng-required='true' ></div>")($rootScope);
$rootScope.$apply(function() {
$rootScope.x = aDate;
});
expect(element.hasClass('ng-valid')).toBeTruthy();
});
});
it('should be valid after the date has been picked', function() {
inject(function($compile, $rootScope) {
var aDate, element;
aDate = new Date(2010, 12, 1);
element = $compile("<div ui-date ng-model='x' ng-required='true' ></div>")($rootScope);
$rootScope.$apply();
selectDate(element, aDate);
expect(element.hasClass('ng-valid')).toBeTruthy();
});
});
});
describe('when attribute options change', function() {
it('should watch attribute and update date widget accordingly', function() {
inject(function($compile, $rootScope) {
var element;
$rootScope.config = {
minDate: 5
};
element = $compile("<input ui-date='config' ng-model='x'/>")($rootScope);
$rootScope.$apply();
expect(element.datepicker("option", "minDate")).toBe(5);
$rootScope.$apply(function() {
$rootScope.config.minDate = 10;
});
expect(element.datepicker("option", "minDate")).toBe(10);
});
});
});
});
describe('uiDateFormat', function() {
beforeEach(module('ui.directives'));
describe('$formatting', function() {
it('should parse the date correctly from an ISO string', function() {
inject(function($compile, $rootScope) {
var aDate, aDateString, element;
aDate = new Date(2012,8,17);
aDateString = (aDate).toISOString();
element = $compile('<input ui-date-format ng-model="x"/>')($rootScope);
$rootScope.x = aDateString;
$rootScope.$digest();
// Check that the model has not been altered
expect($rootScope.x).toEqual(aDateString);
// Check that the viewValue has been parsed correctly
expect(element.controller('ngModel').$viewValue).toEqual(aDate);
});
});
it('should parse the date correctly from a custom string', function() {
inject(function($compile, $rootScope) {
var aDate = new Date(2012, 9, 11);
var aDateString = "Thursday, 11 October, 2012";
var element = $compile('<input ui-date-format="DD, d MM, yy" ng-model="x"/>')($rootScope);
$rootScope.x = aDateString;
$rootScope.$digest();
// Check that the model has not been altered
expect($rootScope.x).toEqual(aDateString);
// Check that the viewValue has been parsed correctly
expect(element.controller('ngModel').$viewValue).toEqual(aDate);
});
});
it('should handle unusual model values', function() {
inject(function($compile, $rootScope) {
var element = $compile('<input ui-date-format ng-model="x"/>')($rootScope);
$rootScope.x = false;
$rootScope.$digest();
// Check that the model has not been altered
expect($rootScope.x).toEqual(false);
// Check that the viewValue has been parsed correctly
expect(element.controller('ngModel').$viewValue).toEqual(null);
$rootScope.x = undefined;
$rootScope.$digest();
// Check that the model has not been altered
expect($rootScope.x).toBeUndefined();
// Check that the viewValue has been parsed correctly
expect(element.controller('ngModel').$viewValue).toEqual(null);
$rootScope.x = null;
$rootScope.$digest();
// Check that the model has not been altered
expect($rootScope.x).toBeNull();
// Check that the viewValue has been parsed correctly
expect(element.controller('ngModel').$viewValue).toEqual(null);
});
});
});
describe('$parsing', function() {
it('should format a selected date correctly to an ISO string', function() {
inject(function($compile, $rootScope) {
var aDate = new Date(2012,8,17);
var aDateString = (aDate).toISOString();
var element = $compile('<input ui-date-format ng-model="x"/>')($rootScope);
$rootScope.$digest();
element.controller('ngModel').$setViewValue(aDate);
// Check that the model is updated correctly
expect($rootScope.x).toEqual(aDateString);
// Check that the $viewValue has not been altered
expect(element.controller('ngModel').$viewValue).toEqual(aDate);
});
});
it('should format a selected date correctly to a custom string', function() {
inject(function($compile, $rootScope) {
var format = 'DD, d MM, yy';
var aDate = new Date(2012,9,11);
var aDateString = "Thursday, 11 October, 2012";
var element = $compile('<input ui-date-format="' + format + '" ng-model="x"/>')($rootScope);
$rootScope.$digest();
element.controller('ngModel').$setViewValue(aDate);
// Check that the model is updated correctly
expect($rootScope.x).toEqual(aDateString);
// Check that the $viewValue has not been altered
expect(element.controller('ngModel').$viewValue).toEqual(aDate);
});
});
});
describe('with uiConfig', function() {
var element, scope, config;
var format = 'DD, d MM, yy';
var aDate = new Date(2012,9,11);
var aDateString = "Thursday, 11 October, 2012";
var aISODateString = aDate.toISOString();
beforeEach(inject(['$compile', '$rootScope', 'ui.config', function($compile, $rootScope, uiConfig) {
config = uiConfig;
element = $compile('<input ui-date-format ng-model="x"/>')($rootScope);
scope = $rootScope;
}]));
it('use ISO if not config value', function() {
scope.x = aISODateString;
scope.$digest();
expect(element.controller('ngModel').$viewValue).toEqual(aDate);
});
it('use format value if config given', function() {
config.dateFormat = format;
scope.x = aDateString;
scope.$digest();
expect(element.controller('ngModel').$viewValue).toEqual(aDate);
});
});
});

@ -1,27 +0,0 @@
/**
* General-purpose Event binding. Bind any event not natively supported by Angular
* Pass an object with keynames for events to ui-event
* Allows $event object and $params object to be passed
*
* @example <input ui-event="{ focus : 'counter++', blur : 'someCallback()' }">
* @example <input ui-event="{ myCustomEvent : 'myEventHandler($event, $params)'}">
*
* @param ui-event {string|object literal} The event to bind to as a string or a hash of events with their callbacks
*/
angular.module('ui.directives').directive('uiEvent', ['$parse',
function ($parse) {
return function (scope, elm, attrs) {
var events = scope.$eval(attrs.uiEvent);
angular.forEach(events, function (uiEvent, eventName) {
var fn = $parse(uiEvent);
elm.bind(eventName, function (evt) {
var params = Array.prototype.slice.call(arguments);
//Take out first paramater (event object);
params = params.splice(1);
scope.$apply(function () {
fn(scope, {$event: evt, $params: params});
});
});
});
};
}]);

@ -1,79 +0,0 @@
describe('uiEvent', function () {
var $scope, $rootScope, $compile;
beforeEach(module('ui.directives'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
//helper for creating event elements
function eventElement(scope, eventObject) {
scope._uiEvent = eventObject || {};
return $compile('<span ui-event="_uiEvent">')(scope);
}
describe('test', function () {
it('should work with dblclick event and assignment', function () {
$scope = $rootScope.$new();
var elm = eventElement($scope, {'dblclick': 'dbl=true'});
expect($scope.dbl).toBeUndefined();
elm.trigger('dblclick');
expect($scope.dbl).toBe(true);
});
it('should work with two events in one key a function', function () {
$scope = $rootScope.$new();
$scope.counter = 0;
$scope.myfn = function () {
$scope.counter++;
};
var elm = eventElement($scope, {'keyup mouseenter': 'myfn()'});
elm.trigger('keyup');
elm.trigger('mouseenter');
expect($scope.counter).toBe(2);
});
it('should work work with multiple entries', function () {
$scope = $rootScope.$new();
$scope.amount = 5;
var elm = eventElement($scope, {
'click': 'amount=amount*2',
'mouseenter': 'amount=amount*4',
'keyup': 'amount=amount*3'
});
elm.trigger('click');
expect($scope.amount).toBe(10);
elm.trigger('mouseenter');
expect($scope.amount).toBe(40);
elm.trigger('keyup');
expect($scope.amount).toBe(120);
});
it('should allow passing of $event object', function () {
$scope = $rootScope.$new();
$scope.clicky = function (par1, $event, par2) {
expect($event.foo).toBe('bar');
expect(par1).toBe(1);
expect(par2).toBe(2);
};
var elm = eventElement($scope, {'click': 'clicky(1, $event, 2)'});
$(elm).trigger({
type: 'click',
foo: 'bar'
});
});
it('should allow passing of $params object', function () {
$scope = $rootScope.$new();
$scope.onStuff = function ($event, $params) {
expect($event.type).toBe('stuff');
expect($params[0]).toBe('foo');
expect($params[1]).toBe('bar');
};
var elm = eventElement($scope, {'stuff': 'onStuff($event, $params)'});
$(elm).trigger('stuff', ['foo', 'bar']);
});
});
});

@ -1,39 +0,0 @@
/*
* Defines the ui-if tag. This removes/adds an element from the dom depending on a condition
* Originally created by @tigbro, for the @jquery-mobile-angular-adapter
* https://github.com/tigbro/jquery-mobile-angular-adapter
*/
angular.module('ui.directives').directive('uiIf', [function () {
return {
transclude: 'element',
priority: 1000,
terminal: true,
restrict: 'A',
compile: function (element, attr, transclude) {
return function (scope, element, attr) {
var childElement;
var childScope;
scope.$watch(attr['uiIf'], function (newValue) {
if (childElement) {
childElement.remove();
childElement = undefined;
}
if (childScope) {
childScope.$destroy();
childScope = undefined;
}
if (newValue) {
childScope = scope.$new();
transclude(childScope, function (clone) {
childElement = clone;
element.after(clone);
});
}
});
};
}
};
}]);

@ -1,57 +0,0 @@
describe('ui-if', function () {
var scope, $compile, elm;
beforeEach(module('ui.directives'));
beforeEach(inject(function ($rootScope, _$compile_) {
scope = $rootScope.$new();
$compile = _$compile_;
elm = $('<div>');
}));
function makeIf(expr) {
elm.append($compile('<div ui-if="' + expr + '"><div>Hi</div></div>')(scope));
scope.$apply();
}
it('should immediately remove element if condition is false', function () {
makeIf('false');
expect(elm.children().length).toBe(0);
});
it('should leave the element if condition is true', function () {
makeIf('true');
expect(elm.children().length).toBe(1);
});
it('should create then remove the element if condition changes', function () {
scope.hello = true;
makeIf('hello');
expect(elm.children().length).toBe(1);
scope.$apply('hello = false');
expect(elm.children().length).toBe(0);
});
it('should create a new scope', function () {
scope.$apply('value = true');
elm.append($compile(
'<div ui-if="value"><span ng-init="value=false"></span></div>'
)(scope));
scope.$apply();
expect(elm.children('div').length).toBe(1);
});
it('should play nice with other elements beside it', function () {
scope.values = [1, 2, 3, 4];
elm.append($compile(
'<div ng-repeat="i in values"></div>' +
'<div ui-if="values.length==4"></div>' +
'<div ng-repeat="i in values"></div>'
)(scope));
scope.$apply();
expect(elm.children().length).toBe(9);
scope.$apply('values.splice(0,1)');
expect(elm.children().length).toBe(6);
scope.$apply('values.push(1)');
expect(elm.children().length).toBe(9);
});
});

@ -1,112 +0,0 @@
# uiJq :: jQuery Passthru Directive
This directive is designed to reduce the need for you to create new directives for fairly simple jQuery plugins or behaviors. Instead of listing plugin compatibility, this document attempts to break down what **uiJq** (jQuery Passthru Directive) is doing so that you can figure out how to circumvent problems you encounter and at the same time understand how the AngularJS template engine works.
## Injecting, Compiling, and Linking functions
When you create a directive, there are up to 3 function layers for you to define[[1]](#footnotes):
```js
myApp.directive('uiJq', function uiJqInjectingFunction(){
// === InjectingFunction === //
// Logic is executed 0 or 1 times per app (depending on if directive is used).
// Useful for bootstrap and global configuration
return {
compile: function uiJqCompilingFunction($templateElement, $templateAttributes) {
// === CompilingFunction === //
// Logic is executed once (1) for every instance of ui-jq in your original UNRENDERED template.
// Scope is UNAVAILABLE as the templates are only being cached.
// You CAN examine the DOM and cache information about what variables
// or expressions will be used, but you cannot yet figure out their values.
// Angular is caching the templates, now is a good time to inject new angular templates
// as children or future siblings to automatically run..
return function uiJqLinkingFunction($scope, $linkElement, $linkAttributes) {
// === LinkingFunction === //
// Logic is executed once (1) for every RENDERED instance.
// Once for each row in an ng-repeat when the row is created.
// If ui-if or ng-switch may also affect if this is executed.
// Scope IS available because controller logic has finished executing.
// All variables and expression values can finally be determined.
// Angular is rendering cached templates. It's too late to add templates for angular
// to automatically run. If you MUST inject new templates, you must $compile them manually.
};
}
};
})
```
You can _only_ access data in `$scope` inside the **LinkingFunction**. Since the template logic may remove or duplicate elements, you can _only_ rely on the final DOM configuration in the **LinkingFunction**. You still _cannot_ rely upon **children** or **following-siblings** since they have not been linked yet.
## Deferred Execution
Even though you can evaluate variables and expressions by the time we hit our `LinkingFunction`, children DOM elements haven't been rendered yet. Sometimes jQuery plugins need to know the number and size of the DOM element's children (such as slideshows or layout managers like Isotope). To add support for these plugins, we decided to delay the plugin's execution using [$timeout](http://docs.angularjs.org/api/ng.$timeout) so that AngularJS can finish rendering the rest of the page.
**This does _NOT_ accomodate for async changes such as loading `$scope` data via AJAX**
If you need to wait till your `$scope` data finishes loading before calling **uiJq** try using [ui-if](http://angular-ui.github.com/#directives-if).
## $element === angular.element() === jQuery()
To make working with the DOM easier, AngularJS contains a miniaturized version of jQuery called jqlite. This emulates some of the core features of jQuery using an _almost_ identical API as jQuery. Any time you see an AngularJS DOM element, it will be the equivalent to a `jQuery()` wrapped DOM element.
**You do _NOT_ have to wrap AngularJS elements in `jQuery()`**
If you are noticing that the full array of jQuery methods (or plugins) aren't available on an AngularJS element, it's because you either forgot to load the jQuery lib, or you forgot to load it **BEFORE** loading AngularJS. If AngularJS doesn't see jQuery already loaded by the time AngularJS loads, it will use it's own jqlite library instead.
**If jQuery plugins complain about missing jQuery methods, you should probably double check this**
Since an AngularJS element is the same as a jQuery() wrapped element, you can essentially call any jQuery method or plugin the same exact way you would have done outside of angular. This is how uiJq works.
uiJq simply takes the string passed and uses it to call a method on the AngularJS element for you:
```js
$('input[type=date]').datepicker() === $('input[type=date]')["datepicker"]() === $linkElement["datepicker"]()
```
## uiOptions and ui.config
Since all jQuery methods take arguments (such as the options for datepicker or the class name for `addClass()`) we provided an easy way for you to pass these options. These options are evaluated from angular so that you can define them in your app:
```js
$('input').datepicker(options) === $linkElement.datepicker(uiOptions)
```
Since there's a good chance you'll use the same options for a plugin across your entire app as defaults, we allow you to declare them inside [ui.config](http://angular-ui.github.com/#defaults). Just remember to use the `jq` key and the `pluginName` subkey:
```js
myApp.value('ui.config', {
jq: {
datepicker: {
// default datepicker options go here
}
}
})
```
Because we're awesome, if your `ui.config` options is an object and your `ui-options` is also an object, we'll merge them together for you with `ui-options` taking priority! If `ui-options` is a primitive the defaults will be ignored.
## uiRefresh
Sometimes you need to call the same jQuery method / plugin multiple times on the same element during an app lifecycle:
```js
// every time the login modal is shown, focus on the username field
$('.modal').on('show', function(){
$('.login-username').focus()
})
```
To make this easy, we added a `ui-refresh` property. This is the equivalent to a `$scope.$watch()` and you can pretend that whatever expression you pass to `ui-refresh` will be just like any expression you pass to `$watch()`. Every time this expression changes (by reference, not by value) uiJq will re-fire:
```html
<input ui-jq="focus" ui-refresh="isLoginFormVisible">
```
## Footnotes
1. A [transcluding function](http://docs.angularjs.org/guide/directive) is actually a 4th layer, but this is not used by uiJq

@ -1,64 +0,0 @@
/**
* General-purpose jQuery wrapper. Simply pass the plugin name as the expression.
*
* It is possible to specify a default set of parameters for each jQuery plugin.
* Under the jq key, namespace each plugin by that which will be passed to ui-jq.
* Unfortunately, at this time you can only pre-define the first parameter.
* @example { jq : { datepicker : { showOn:'click' } } }
*
* @param ui-jq {string} The $elm.[pluginName]() to call.
* @param [ui-options] {mixed} Expression to be evaluated and passed as options to the function
* Multiple parameters can be separated by commas
* @param [ui-refresh] {expression} Watch expression and refire plugin on changes
*
* @example <input ui-jq="datepicker" ui-options="{showOn:'click'},secondParameter,thirdParameter" ui-refresh="iChange">
*/
angular.module('ui.directives').directive('uiJq', ['ui.config', '$timeout', function uiJqInjectingFunction(uiConfig, $timeout) {
return {
restrict: 'A',
compile: function uiJqCompilingFunction(tElm, tAttrs) {
if (!angular.isFunction(tElm[tAttrs.uiJq])) {
throw new Error('ui-jq: The "' + tAttrs.uiJq + '" function does not exist');
}
var options = uiConfig.jq && uiConfig.jq[tAttrs.uiJq];
return function uiJqLinkingFunction(scope, elm, attrs) {
var linkOptions = [];
// If ui-options are passed, merge (or override) them onto global defaults and pass to the jQuery method
if (attrs.uiOptions) {
linkOptions = scope.$eval('[' + attrs.uiOptions + ']');
if (angular.isObject(options) && angular.isObject(linkOptions[0])) {
linkOptions[0] = angular.extend({}, options, linkOptions[0]);
}
} else if (options) {
linkOptions = [options];
}
// If change compatibility is enabled, the form input's "change" event will trigger an "input" event
if (attrs.ngModel && elm.is('select,input,textarea')) {
elm.on('change', function() {
elm.trigger('input');
});
}
// Call jQuery method and pass relevant options
function callPlugin() {
$timeout(function() {
elm[attrs.uiJq].apply(elm, linkOptions);
}, 0, false);
}
// If ui-refresh is used, re-fire the the method upon every change
if (attrs.uiRefresh) {
scope.$watch(attrs.uiRefresh, function(newVal) {
callPlugin();
});
}
callPlugin();
};
}
};
}]);

@ -1,111 +0,0 @@
describe('uiJq', function () {
var scope, compile, timeout;
scope = null;
beforeEach(module('ui.directives'));
beforeEach(function () {
jQuery.fn.foo = function () {};
module(function ($provide) {
$provide.value('ui.config', {
jq: {foo: {}}
});
});
});
beforeEach(inject(function ($rootScope, $compile, $timeout) {
scope = $rootScope.$new();
compile = $compile;
timeout = $timeout;
}));
describe('function or plugin isn\'t found', function () {
it('should throw an error', function () {
expect(function () {
compile("<div ui-jq='failure'></div>")(scope);
}).toThrow();
});
});
describe('calling a jQuery element function', function () {
it('should just like, sort of work and junk', function () {
spyOn(jQuery.fn, 'foo');
compile("<div ui-jq='foo'></div>")(scope);
timeout.flush();
expect(jQuery.fn.foo).toHaveBeenCalled();
});
it('should fire after the view has rendered', function() {
var length;
jQuery.fn.bar = function() {
length = $(this).children().length;
console.log(length);
};
scope.$apply('items=[1, 2]');
compile("<ul ui-jq='bar'><li ng-repeat='item in items'></li></ul>")(scope);
scope.$apply();
timeout.flush();
expect(length).toBe(2);
});
});
describe('calling a jQuery element function with options', function() {
it('should not copy options.pizza to global', function() {
spyOn(jQuery.fn, 'foo');
compile('<div ui-jq="foo" ui-options="{pizza:true}"></div><div ui-jq="foo" ui-options="{}"></div>')(scope);
timeout.flush();
expect(jQuery.fn.foo.calls[0].args).toEqual([{pizza: true}]);
expect(jQuery.fn.foo.calls[1].args).toEqual([{}]);
});
});
describe('using ui-refresh', function() {
it('should execute exactly once if the expression is never set', function() {
spyOn(jQuery.fn, 'foo');
compile('<div ui-jq="foo" ui-refresh="bar"></div>')(scope);
timeout.flush();
expect(jQuery.fn.foo.callCount).toBe(1);
});
it('should execute exactly once if the expression is set at initialization', function() {
spyOn(jQuery.fn, 'foo');
scope.$apply('bar = true');
compile('<div ui-jq="foo" ui-refresh="bar"></div>')(scope);
timeout.flush();
expect(jQuery.fn.foo.callCount).toBe(1);
});
it('should execute once for each time the expression changes', function() {
spyOn(jQuery.fn, 'foo');
scope.$apply('bar = 1');
compile('<div ui-jq="foo" ui-refresh="bar"></div>')(scope);
timeout.flush();
expect(jQuery.fn.foo.callCount).toBe(1);
scope.$apply('bar = bar+1');
timeout.flush();
expect(jQuery.fn.foo.callCount).toBe(2);
scope.$apply('bar = bar+1');
timeout.flush();
expect(jQuery.fn.foo.callCount).toBe(3);
});
});
describe('change events', function() {
it('should trigger an `input` event', function() {
var bar = false;
var element = compile('<input ui-jq="foo" ng-model="foobar">')(scope);
element.bind('input', function(){
bar = true;
});
element.trigger('change');
expect(bar).toBe(true);
});
it('should ignore controls without ngModel attribute', function() {
var bar = false;
var element = compile('<input ui-jq="foo">')(scope);
element.bind('input', function(){
bar = true;
});
element.trigger('change');
expect(bar).toBe(false);
});
it('should ignore non-form controls', function() {
var bar = false;
var element = compile('<div ui-jq="foo"></div ng-model="foobar">')(scope);
element.bind('input', function(){
bar = true;
});
element.trigger('change');
expect(bar).toBe(false);
});
});
});

@ -1,110 +0,0 @@
angular.module('ui.directives').factory('keypressHelper', ['$parse', function keypress($parse){
var keysByCode = {
8: 'backspace',
9: 'tab',
13: 'enter',
27: 'esc',
32: 'space',
33: 'pageup',
34: 'pagedown',
35: 'end',
36: 'home',
37: 'left',
38: 'up',
39: 'right',
40: 'down',
45: 'insert',
46: 'delete'
};
var capitaliseFirstLetter = function (string) {
return string.charAt(0).toUpperCase() + string.slice(1);
};
return function(mode, scope, elm, attrs) {
var params, combinations = [];
params = scope.$eval(attrs['ui'+capitaliseFirstLetter(mode)]);
// Prepare combinations for simple checking
angular.forEach(params, function (v, k) {
var combination, expression;
expression = $parse(v);
angular.forEach(k.split(' '), function(variation) {
combination = {
expression: expression,
keys: {}
};
angular.forEach(variation.split('-'), function (value) {
combination.keys[value] = true;
});
combinations.push(combination);
});
});
// Check only matching of pressed keys one of the conditions
elm.bind(mode, function (event) {
// No need to do that inside the cycle
var altPressed = event.metaKey || event.altKey;
var ctrlPressed = event.ctrlKey;
var shiftPressed = event.shiftKey;
var keyCode = event.keyCode;
// normalize keycodes
if (mode === 'keypress' && !shiftPressed && keyCode >= 97 && keyCode <= 122) {
keyCode = keyCode - 32;
}
// Iterate over prepared combinations
angular.forEach(combinations, function (combination) {
var mainKeyPressed = (combination.keys[keysByCode[event.keyCode]] || combination.keys[event.keyCode.toString()]) || false;
var altRequired = combination.keys.alt || false;
var ctrlRequired = combination.keys.ctrl || false;
var shiftRequired = combination.keys.shift || false;
if (
mainKeyPressed &&
( altRequired == altPressed ) &&
( ctrlRequired == ctrlPressed ) &&
( shiftRequired == shiftPressed )
) {
// Run the function
scope.$apply(function () {
combination.expression(scope, { '$event': event });
});
}
});
});
};
}]);
/**
* Bind one or more handlers to particular keys or their combination
* @param hash {mixed} keyBindings Can be an object or string where keybinding expression of keys or keys combinations and AngularJS Exspressions are set. Object syntax: "{ keys1: expression1 [, keys2: expression2 [ , ... ]]}". String syntax: ""expression1 on keys1 [ and expression2 on keys2 [ and ... ]]"". Expression is an AngularJS Expression, and key(s) are dash-separated combinations of keys and modifiers (one or many, if any. Order does not matter). Supported modifiers are 'ctrl', 'shift', 'alt' and key can be used either via its keyCode (13 for Return) or name. Named keys are 'backspace', 'tab', 'enter', 'esc', 'space', 'pageup', 'pagedown', 'end', 'home', 'left', 'up', 'right', 'down', 'insert', 'delete'.
* @example <input ui-keypress="{enter:'x = 1', 'ctrl-shift-space':'foo()', 'shift-13':'bar()'}" /> <input ui-keypress="foo = 2 on ctrl-13 and bar('hello') on shift-esc" />
**/
angular.module('ui.directives').directive('uiKeydown', ['keypressHelper', function(keypressHelper){
return {
link: function (scope, elm, attrs) {
keypressHelper('keydown', scope, elm, attrs);
}
};
}]);
angular.module('ui.directives').directive('uiKeypress', ['keypressHelper', function(keypressHelper){
return {
link: function (scope, elm, attrs) {
keypressHelper('keypress', scope, elm, attrs);
}
};
}]);
angular.module('ui.directives').directive('uiKeyup', ['keypressHelper', function(keypressHelper){
return {
link: function (scope, elm, attrs) {
keypressHelper('keyup', scope, elm, attrs);
}
};
}]);

@ -1,67 +0,0 @@
describe('uiKeydown', function () {
var $scope, $compile;
var createKeyEvent = function (mainKey, alt, ctrl, shif) {
var keyEvent = jQuery.Event("keydown");
keyEvent.keyCode = mainKey;
keyEvent.altKey = alt || false;
keyEvent.ctrlKey = ctrl || false;
keyEvent.shiftKey = shif || false;
return keyEvent;
};
var createElement = function (elementDef) {
var elementStr = angular.isString(elementDef) ? elementDef : angular.toJson(elementDef);
return $compile("<span ui-keydown='" + elementStr + "'></span>")($scope);
};
beforeEach(module('ui.directives'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
$scope.cb = function (event) {
this.event1 = event;
};
}));
it('should support single key press', function () {
createElement({'13': 'event=true'}).trigger(createKeyEvent(13));
expect($scope.event).toBe(true);
});
it('should support combined key press', function () {
createElement({'ctrl-shift-13': 'event=true'}).trigger(createKeyEvent(13, false, true, true));
expect($scope.event).toBe(true);
});
it('should support alternative combinations', function () {
$scope.event = 0;
createElement({'ctrl-shift-14 ctrl-shift-13': 'event=event+1'}).trigger(createKeyEvent(13, false, true, true)).trigger(createKeyEvent(14, false, true, true));
expect($scope.event).toBe(2);
});
it('should support multiple key press definitions', function () {
var elm = createElement({'13': 'event1=true', 'ctrl-shift-13': 'event2=true'});
elm.trigger(createKeyEvent(13));
expect($scope.event1).toBe(true);
elm.trigger(createKeyEvent(13, false, true, true));
expect($scope.event2).toBe(true);
});
it('should support $event in expressions', function () {
var element = createElement({'esc': 'cb($event)', '13': 'event2=$event'});
element.trigger(createKeyEvent(27));
expect($scope.event1.keyCode).toBe(27);
element.trigger(createKeyEvent(13));
expect($scope.event2.keyCode).toBe(13);
});
});

@ -1,67 +0,0 @@
describe('uiKeypress', function () {
var $scope, $compile;
var createKeyEvent = function (mainKey, alt, ctrl, shif) {
var keyEvent = jQuery.Event("keypress");
keyEvent.keyCode = mainKey;
keyEvent.altKey = alt || false;
keyEvent.ctrlKey = ctrl || false;
keyEvent.shiftKey = shif || false;
return keyEvent;
};
var createElement = function (elementDef) {
var elementStr = angular.isString(elementDef) ? elementDef : angular.toJson(elementDef);
return $compile("<span ui-keypress='" + elementStr + "'></span>")($scope);
};
beforeEach(module('ui.directives'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
$scope.cb = function (event) {
this.event1 = event;
};
}));
it('should support single key press', function () {
createElement({'13': 'event=true'}).trigger(createKeyEvent(13));
expect($scope.event).toBe(true);
});
it('should support combined key press', function () {
createElement({'ctrl-shift-13': 'event=true'}).trigger(createKeyEvent(13, false, true, true));
expect($scope.event).toBe(true);
});
it('should support alternative combinations', function () {
$scope.event = 0;
createElement({'ctrl-shift-14 ctrl-shift-13': 'event=event+1'}).trigger(createKeyEvent(13, false, true, true)).trigger(createKeyEvent(14, false, true, true));
expect($scope.event).toBe(2);
});
it('should support multiple key press definitions', function () {
var elm = createElement({'13': 'event1=true', 'ctrl-shift-13': 'event2=true'});
elm.trigger(createKeyEvent(13));
expect($scope.event1).toBe(true);
elm.trigger(createKeyEvent(13, false, true, true));
expect($scope.event2).toBe(true);
});
it('should support $event in expressions', function () {
var element = createElement({'esc': 'cb($event)', '13': 'event2=$event'});
element.trigger(createKeyEvent(27));
expect($scope.event1.keyCode).toBe(27);
element.trigger(createKeyEvent(13));
expect($scope.event2.keyCode).toBe(13);
});
});

@ -1,67 +0,0 @@
describe('uiKeyup', function () {
var $scope, $compile;
var createKeyEvent = function (mainKey, alt, ctrl, shif) {
var keyEvent = jQuery.Event("keyup");
keyEvent.keyCode = mainKey;
keyEvent.altKey = alt || false;
keyEvent.ctrlKey = ctrl || false;
keyEvent.shiftKey = shif || false;
return keyEvent;
};
var createElement = function (elementDef) {
var elementStr = angular.isString(elementDef) ? elementDef : angular.toJson(elementDef);
return $compile("<span ui-keyup='" + elementStr + "'></span>")($scope);
};
beforeEach(module('ui.directives'));
beforeEach(inject(function (_$rootScope_, _$compile_) {
$compile = _$compile_;
$scope = _$rootScope_.$new();
$scope.cb = function (event) {
this.event1 = event;
};
}));
it('should support single key press', function () {
createElement({'13': 'event=true'}).trigger(createKeyEvent(13));
expect($scope.event).toBe(true);
});
it('should support combined key press', function () {
createElement({'ctrl-shift-13': 'event=true'}).trigger(createKeyEvent(13, false, true, true));
expect($scope.event).toBe(true);
});
it('should support alternative combinations', function () {
$scope.event = 0;
createElement({'ctrl-shift-14 ctrl-shift-13': 'event=event+1'}).trigger(createKeyEvent(13, false, true, true)).trigger(createKeyEvent(14, false, true, true));
expect($scope.event).toBe(2);
});
it('should support multiple key press definitions', function () {
var elm = createElement({'13': 'event1=true', 'ctrl-shift-13': 'event2=true'});
elm.trigger(createKeyEvent(13));
expect($scope.event1).toBe(true);
elm.trigger(createKeyEvent(13, false, true, true));
expect($scope.event2).toBe(true);
});
it('should support $event in expressions', function () {
var element = createElement({'esc': 'cb($event)', '13': 'event2=$event'});
element.trigger(createKeyEvent(27));
expect($scope.event1.keyCode).toBe(27);
element.trigger(createKeyEvent(13));
expect($scope.event2.keyCode).toBe(13);
});
});

@ -1,125 +0,0 @@
(function () {
var app = angular.module('ui.directives');
//Setup map events from a google map object to trigger on a given element too,
//then we just use ui-event to catch events from an element
function bindMapEvents(scope, eventsStr, googleObject, element) {
angular.forEach(eventsStr.split(' '), function (eventName) {
//Prefix all googlemap events with 'map-', so eg 'click'
//for the googlemap doesn't interfere with a normal 'click' event
var $event = { type: 'map-' + eventName };
google.maps.event.addListener(googleObject, eventName, function (evt) {
element.triggerHandler(angular.extend({}, $event, evt));
//We create an $apply if it isn't happening. we need better support for this
//We don't want to use timeout because tons of these events fire at once,
//and we only need one $apply
if (!scope.$$phase) scope.$apply();
});
});
}
app.directive('uiMap',
['ui.config', '$parse', function (uiConfig, $parse) {
var mapEvents = 'bounds_changed center_changed click dblclick drag dragend ' +
'dragstart heading_changed idle maptypeid_changed mousemove mouseout ' +
'mouseover projection_changed resize rightclick tilesloaded tilt_changed ' +
'zoom_changed';
var options = uiConfig.map || {};
return {
restrict: 'A',
//doesn't work as E for unknown reason
link: function (scope, elm, attrs) {
var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
var map = new google.maps.Map(elm[0], opts);
var model = $parse(attrs.uiMap);
//Set scope variable for the map
model.assign(scope, map);
bindMapEvents(scope, mapEvents, map, elm);
}
};
}]);
app.directive('uiMapInfoWindow',
['ui.config', '$parse', '$compile', function (uiConfig, $parse, $compile) {
var infoWindowEvents = 'closeclick content_change domready ' +
'position_changed zindex_changed';
var options = uiConfig.mapInfoWindow || {};
return {
link: function (scope, elm, attrs) {
var opts = angular.extend({}, options, scope.$eval(attrs.uiOptions));
opts.content = elm[0];
var model = $parse(attrs.uiMapInfoWindow);
var infoWindow = model(scope);
if (!infoWindow) {
infoWindow = new google.maps.InfoWindow(opts);
model.assign(scope, infoWindow);
}
bindMapEvents(scope, infoWindowEvents, infoWindow, elm);
/* The info window's contents dont' need to be on the dom anymore,
google maps has them stored. So we just replace the infowindow element
with an empty div. (we don't just straight remove it from the dom because
straight removing things from the dom can mess up angular) */
elm.replaceWith('<div></div>');
//Decorate infoWindow.open to $compile contents before opening
var _open = infoWindow.open;
infoWindow.open = function open(a1, a2, a3, a4, a5, a6) {
$compile(elm.contents())(scope);
_open.call(infoWindow, a1, a2, a3, a4, a5, a6);
};
}
};
}]);
/*
* Map overlay directives all work the same. Take map marker for example
* <ui-map-marker="myMarker"> will $watch 'myMarker' and each time it changes,
* it will hook up myMarker's events to the directive dom element. Then
* ui-event will be able to catch all of myMarker's events. Super simple.
*/
function mapOverlayDirective(directiveName, events) {
app.directive(directiveName, [function () {
return {
restrict: 'A',
link: function (scope, elm, attrs) {
scope.$watch(attrs[directiveName], function (newObject) {
bindMapEvents(scope, events, newObject, elm);
});
}
};
}]);
}
mapOverlayDirective('uiMapMarker',
'animation_changed click clickable_changed cursor_changed ' +
'dblclick drag dragend draggable_changed dragstart flat_changed icon_changed ' +
'mousedown mouseout mouseover mouseup position_changed rightclick ' +
'shadow_changed shape_changed title_changed visible_changed zindex_changed');
mapOverlayDirective('uiMapPolyline',
'click dblclick mousedown mousemove mouseout mouseover mouseup rightclick');
mapOverlayDirective('uiMapPolygon',
'click dblclick mousedown mousemove mouseout mouseover mouseup rightclick');
mapOverlayDirective('uiMapRectangle',
'bounds_changed click dblclick mousedown mousemove mouseout mouseover ' +
'mouseup rightclick');
mapOverlayDirective('uiMapCircle',
'center_changed click dblclick mousedown mousemove ' +
'mouseout mouseover mouseup radius_changed rightclick');
mapOverlayDirective('uiMapGroundOverlay',
'click dblclick');
})();

@ -1,102 +0,0 @@
xdescribe('uiMap', function () {
var scope, $rootScope, $compile;
beforeEach(module('ui.directives'));
beforeEach(inject(function (_$compile_, _$rootScope_) {
$rootScope = _$rootScope_;
$compile = _$compile_;
}));
function createMap(options, events) {
scope.gmapOptions = options || {};
scope.gmapEvents = events || {};
$compile("<div ui-map='gmap' ui-options='gmapOptions'" +
"' ui-event='gmapEvents'></div>")(scope);
}
function createWindow(options, events, inner) {
scope.gOptions = options || {};
scope.gEvents = events || {};
inner = inner || angular.element('');
var elm = angular.element("<div ui-map-info-window='ginfo' " +
"ui-options='gOptions' ui-event='gEvents'></div>");
elm.append(inner);
$compile(elm)(scope);
}
describe('test', function () {
beforeEach(function () {
scope = $rootScope.$new();
});
it('should bind google map object to scope', function () {
createMap();
expect(scope.gmap).toBeTruthy();
});
it('should create google map with given options', function () {
var center = new google.maps.LatLng(40, 40);
createMap({center: center});
expect(scope.gmap.getCenter()).toBe(center);
});
it('should pass events to the element as "map-eventname"', function () {
scope.zoomy = false;
scope.county = 0;
createMap({}, {
'map-zoom_changed': 'zoomy = true',
'map-dblclick map-dragend': 'county = county + 1'
});
google.maps.event.trigger(scope.gmap, 'zoom_changed');
expect(scope.zoomy).toBeTruthy();
google.maps.event.trigger(scope.gmap, 'dblclick');
expect(scope.county).toBe(1);
google.maps.event.trigger(scope.gmap, 'dragend');
expect(scope.county).toBe(2);
});
});
describe('test infoWindow', function () {
beforeEach(function () {
scope = $rootScope.$new();
});
it('should bind info window to scope', function () {
createWindow();
expect(scope.ginfo).toBeTruthy();
});
it('should create info window with given options & content', function () {
var content = $('<h1>Hi</h1>');
createWindow({ zIndex: 5 }, {}, content);
expect(scope.ginfo.getZIndex()).toBe(5);
expect(scope.ginfo.getContent().innerHTML)
.toBe($('<div>').append(content).html());
});
it('should $compile content and recognize scope changes', function () {
var inner = $('<input ng-model="myVal">');
createWindow({}, {}, inner);
createMap();
scope.$apply(function () {
scope.myVal = 'initial';
});
scope.ginfo.open(scope.gmap, scope.gmap.getCenter());
expect(inner.val()).toBe('initial');
scope.$apply(function () {
scope.myVal = 'final';
});
expect(inner.val()).toBe('final');
});
it('should recognize infowindow events in ui-event as "map-eventname"', function () {
createWindow({}, {
'map-closeclick': 'closed = true'
});
createMap();
google.maps.event.trigger(scope.ginfo, 'closeclick');
expect(scope.closed).toBe(true);
});
});
});

Some files were not shown because too many files have changed in this diff Show More