top is generally a nice utility for that kind of tasks. But, there is a better and cleaner alternative: htop. A comparison picture is worth a thousand words.Install it on OSX using:
brew install htop
top is generally a nice utility for that kind of tasks. But, there is a better and cleaner alternative: htop. A comparison picture is worth a thousand words.brew install htop
meteor create Polaroid cd PolaroidNow create a common fullstack JS directory structure only targeted for a client WebApp without server side integration:
mkdir -p client/lib client/models client/startup client/stylesheets client/views lib packages public/imgRemove the automatically created files:
rm -rf Polaroid.*Add the following package with Meteor:
meteor add coffeescript meteor add stylusAnd this one with Meteorite:
mrt add jade mrt add famonoEasy as pie.
public/img/camera.png that you'll find in the Zip file that Famo.us provides in their download section.
client/stylesheets/app.styl is kept as its minimum as most of the CSS rules are handled by Famo.us.
@import 'nib' html background: #404040 body -webkit-touch-callout: none user-select: none font-family: 'AvenirNext-Medium'
client/index.jade is kept as its minimum as most of the tags are handled by Famo.ushead title Famo.us Polaroid body +index template(name='index')That's it, a simple
template loaded by Meteor.
client/lib/polaroid.coffee:
# Declare Polaroid namespace
window.Polaroid ?= {}
client/lib/famous.coffee:
# Declare Famo.us namespace
window.Famous ?= {}
lib directory is used as it is loaded first by Meteor.
client/models/slidedata.coffee:Polaroid.SlideData =
userId: "109813050055185479846"
albumId: "6013105701911614529"
picasaUrl: "https://picasaweb.google.com/data/feed/api/user/"
queryParams: "?alt=json&hl=en_US&access=visible&fields=entry(id,media:group(media:content,media:description,media:keywords,media:title))"
defaultImage: "https://lh4.googleusercontent.com/-HbYp2q1BZfQ/U3LXxmWoy7I/AAAAAAAAAJk/VqI5bGooDaA/s1178-no/1.jpg"
getUrl: ->
@picasaUrl + @userId + "/albumid/" + @albumId + @queryParams
parse: (data) ->
urls = []
data = JSON.parse(data)
entries = data.feed.entry
i = 0
while i < entries.length
media = entries[i].media$group
urls.push media.media$content[0].url
i++
urls
A simple dictionary with 2 methods.
client/startup/famous.coffee to load the polyfills and to create the Famo.us's singleton so that if I enhance this WebApp with multiple page loaded with a router, there will be no additional loadings or instantiations.
# Import famous.css require 'famous/core/famous' # Adds the famo.us dependencies require 'famous-polyfills' # Wait for document ready $(document).ready -> # Load Famo.us libraries Famous.Engine = require 'famous/core/Engine' Famous.View = require 'famous/core/View' Famous.Transform = require 'famous/core/Transform' Famous.Surface = require 'famous/core/Surface' Famous.StateModifier = require 'famous/modifiers/StateModifier' Famous.Timer = require 'famous/utilities/Timer' Famous.ImageSurface = require 'famous/surfaces/ImageSurface' Famous.ContainerSurface = require 'famous/surfaces/ContainerSurface' Famous.Lightbox = require 'famous/views/Lightbox' Famous.Utility = require 'famous/utilities/Utility' Famous.Easing = require 'famous/transitions/Easing' Famous.ContainerSurface = require 'famous/surfaces/ContainerSurface' Famous.Transitionable = require 'famous/transitions/Transitionable' Famous.SpringTransition = require 'famous/transitions/SpringTransition' # Register transitions Famous.Transitionable.registerMethod 'spring', Famous.SpringTransition # Create main context Polaroid.mainCtx = Famous.Engine.createContext()
client/index.coffee that goes along with our Jade file:Template.index.rendered = ->
# Get request to Picasa API
Famous.Utility.loadURL Polaroid.SlideData.getUrl(), (data) ->
data = Polaroid.SlideData.parse data
# Instantiate the AppView with our URL's data
Polaroid.appView = new Polaroid.AppView data: data
Polaroid.mainCtx.add Polaroid.appView
client/views/appview.coffee$(document).ready ->
class Polaroid.AppView extends Famous.View
DEFAULT_OPTIONS:
data: undefined
cameraWidth: 0.6 * window.innerHeight
constructor: (@options) ->
@DEFAULT_OPTIONS.slideWidth = 0.8 * @DEFAULT_OPTIONS.cameraWidth
@DEFAULT_OPTIONS.slideHeight = @DEFAULT_OPTIONS.slideWidth + 40
@DEFAULT_OPTIONS.slidePosition = 0.77 * @DEFAULT_OPTIONS.cameraWidth
@constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
super @options
@createCamera()
@createSlideshow()
createCamera: ->
camera = new Famous.ImageSurface
size: [@options.cameraWidth, true]
content: 'img/camera.png'
properties:
width: '100%'
cameraModifier = new Famous.StateModifier
origin: [0.5, 0]
align: [0.5, 0]
transform: Famous.Transform.behind
@add(cameraModifier).add camera
createSlideshow: ->
slideshowView = new Polaroid.SlideshowView
size: [@options.slideWidth, @options.slideHeight]
data: @options.data
slideshowModifier = new Famous.StateModifier
origin: [0.5, 0]
align: [0.5, 0]
transform: Famous.Transform.translate 0, @options.slidePosition, 0
slideshowContainer = new Famous.ContainerSurface
properties:
overflow: 'hidden'
@add(slideshowModifier).add slideshowContainer
slideshowContainer.add slideshowView
slideshowContainer.context.setPerspective 1000
client/views/slideshowview.coffee$(document).ready ->
class Polaroid.SlideshowView extends Famous.View
DEFAULT_OPTIONS:
size: [450, 500]
data: undefined
lightboxOpts:
inOpacity: 1
outOpacity: 0
inOrigin: [0, 0]
outOrigin: [0, 0]
showOrigin: [0, 0]
inTransform: Famous.Transform.thenMove Famous.Transform.rotateX(0.9), [0, -300, -300]
outTransform: Famous.Transform.thenMove Famous.Transform.rotateZ(0.7), [0, window.innerHeight, -1000]
inTransition: duration: 500, curve: Famous.Easing.outBack
outTransition: duration: 350, curve: Famous.Easing.inQuad
constructor: (@options) ->
@constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
super @options
@rootModifier = new Famous.StateModifier
size: @options.size
origin: [0.5, 0]
align: [0.5, 0]
@mainNode = @add @rootModifier
@createLightbox()
@createSlides()
createLightbox: ->
@lightbox = new Famous.Lightbox @options.lightboxOpts
@mainNode.add @lightbox
createSlides: =>
@slides = []
@currentIndex = 0
console.log @options.data
for url in @options.data
slide = new Polaroid.SlideView
size: @options.size
photoUrl: url
@slides.push slide
slide.on 'click', @showNexSlide
@showCurrentSlide()
showCurrentSlide: ->
@ready = false
slide = @slides[@currentIndex]
@lightbox.show slide, =>
@ready = true
slide.fadeIn()
showNexSlide: =>
return if @ready isnt true
@currentIndex++
if @currentIndex is @slides.length
@currentIndex = 0
@showCurrentSlide()
client/views/slideview.coffee$(document).ready ->
class Polaroid.SlideView extends Famous.View
DEFAULT_OPTIONS:
size: [400, 450]
filmBorder: 15
photoBorder: 3
photoUrl: Polaroid.SlideData.defaultImage
angle: -0.5
constructor: (@options) ->
@constructor.DEFAULT_OPTIONS = @DEFAULT_OPTIONS
super @options
@rootModifier = new Famous.StateModifier
size: @options.size
@mainNode = @add @rootModifier
@createBackground()
@createFilm()
@createPhoto()
createBackground: ->
background = new Famous.Surface
properties:
backgroundColor: '#fffff5'
boxShadow: '0 10px 20px -5px rgba(0, 0, 0, 0.5)'
cursor: 'pointer'
@mainNode.add background
background.on 'click', =>
@_eventOutput.emit 'click'
createFilm: ->
@options.filmSize = @options.size[0] - 2 * @options.filmBorder
film = new Famous.Surface
size: [@options.filmSize, @options.filmSize]
properties:
backgroundColor: '#222'
zIndex: 1
# Make surface invisible to pointer events
pointerEvents: 'none'
filmModifier = new Famous.StateModifier
origin: [0.5, 0]
align: [0.5, 0]
transform: Famous.Transform.translate 0, @options.filmBorder, 1
@mainNode
.add filmModifier
.add film
createPhoto: ->
photoSize = @options.filmSize - 2 * @options.photoBorder
photo = new Famous.ImageSurface
size: [photoSize, photoSize]
content: @options.photoUrl
properties:
zIndex: 2
# Make surface invisible to pointer events
pointerEvents: 'none'
@photoModifier = new Famous.StateModifier
origin: [0.5, 0]
align: [0.5, 0]
transform: Famous.Transform.translate 0, @options.filmBorder + @options.photoBorder, 2
opacity: 0.01
@mainNode
.add @photoModifier
.add photo
fadeIn: =>
@photoModifier.setOpacity 1, {duration: 1500, curve: 'easeIn'}
@shake()
shake: ->
@rootModifier.halt()
@rootModifier.setTransform Famous.Transform.rotateX(@options.angle), {duration: 200, curve: 'easeOut'}
@rootModifier.setTransform Famous.Transform.identity, {method: 'spring', period: 600, dampingRatio: 0.15}
brew cask install qlcolorcode qlstephen qlmarkdown quicklook-json qlprettypatch quicklook-csv betterzipql webp-quicklook suspicious-package
rm command, it simplifies it when you are removing a tree of files. Super nice.HeaderFooterLayout to layout the basis of your SPA:HeaderFooterLayout = require 'famous/views/HeaderFooterLayout'
layout = new HeaderFooterLayout
headerSize: 100
footerSize: 50
mainContext.add layout
layout.header.add new Surface
content: 'Header'
size: [undefined, 100]
classes: ['header-surface']
properties:
lineHeight: '100px'
textAlign: 'center'
layout.content.add new Surface
content: 'Content'
size: [undefined, undefined]
properties:
lineHeight: '300px'
textAlign: 'center'
layout.footer.add new Surface
content: 'Footer'
size: [undefined, 50]
classes: ['footer-surface']
properties:
lineHeight: '50px'
textAlign: 'center'
pretty function to prettify your JSON documents or collections within the Mongo's shell:
db.find({}).pretty()
Here's the difference with a simple example:~/.mongorc.js using this command:
echo "DBQuery.prototype._prettyShell = true" >> ~/.mongorc.js
Thanks to Lee Machin for this tip: https://coderwall.com/p/3vfw9a
npm -g install mongo-hackerNow, here is the same example with some nice hacking:
ssh-copy-id is a simple tool that send your public SSH key to a remote server. Installing it on OSX:
brew install ssh-copy-id
192.168.1.32:
ssh-copy-id root@192.168.1.32Note: If you have never generated your SSH key pair, simply issue the following command:
ssh-keygen -t rsa -C
brew install saltstackNow, we are going to increase the opened sockets capacity of OSX:
sudo launchctl limit maxfiles 4096 8192When installed from Homebrew, Saltstack doesn't come with the default configuration files. Theses files are described in the Saltstack documentation pages: 21.6. Configuration file examples. Saltstack expects to see at least 2 files,
master and minion into the uncreated /etc/salt directory. Let's fix that:
sudo mkdir /etc/saltAnd copy the content of
master and minion into this freshly created directory.ifconfig -a | perl -nle'/(\d+\.\d+\.\d+\.\d+)/ && print $1'Now edit the /etc/master file to reflects the opened sockets capacity and as I dont' like sudoing each time I have to launch a command, add your username to the allowed users (here it's PEM, of course):
max_open_files: 8192
user: PEM
interface: 192.168.1.30
file_roots:
base:
- /Users/PEM/Projects/SolutionsM3/DevOps/states
pillar_roots:
base:
- /Users/PEM/Projects/SolutionsM3/DevOps/pillar
Note that I've setup my Saltstack master so that its all the formulas that I deploy are stored in my personal directory. This allows me to modify every deployed configuration and save them with Git once I've finished working on them. This is what DevOps is for: your infrastructure and administration as simple script files with formulas reproducible, idempotent, evolving, without connecting manually to every servers each time you need to adjust a simple variable.ssh-keygenThis command generate the following files in your home directory:
/Users/PEM/.ssh ├── id_rsa ├── id_rsa.pub └── known_hostsWe are going to authorize ourselves on our VPS with your public key:
cat ~/.ssh/id_rsa.pub | ssh root@vpsXXXXX.ovh.neta 'cat >> .ssh/authorized_keys'Where
XXXXX is the VPS's number that OVH has provided you.ssh root@vpsXXXXX.ovh.net
/etc/salt/roster file with this info:
vpsXXXXX: host: vpsXXXXX.ovh.netNow, whenever I want to check by a ping all my servers, I use a single command:
salt-ssh '*' test.pingIf I want to target a specific one:
salt-ssh 'vpsXXXXX' test.pingWith simple naming scheme, I'm able to achieve deployment of a specific package on a specific group of servers. Nifty.
salt-ssh '*' -r 'apt-get install -y salt-minion'
tree command on all my servers or checking that it has already been deployed from the comfort of my coach is done like this. In my DevOps project, I've set up 2 files:
├── pillar
└── states
├── top.sls
└── tree.sls
The states/top.sls file declare all the available formulas that I want to apply on every servers. In this simple example it contains only a basic rule to install the tree command:
base:
'*':
- tree
And for the states/tree.sls file, just a simple call to the Saltstack's module pkg, which is able to handle almost every Linux packaging tools that I've been playing with:
tree:
pkg:
- installed
Time for the installation. As the Saltstack's state are idempotent, I can run this command every time I want. It will only execute it where it is required:
tree: salt-ssh '*' -c /etc/salt state.highstateWith this installation, I'm capable of checking the tree of files exposed by NGINX on all my servers with a single command:
salt-ssh '*' -r 'tree /var/www'