text:
Your code doesn't have to look so sour. I've collected a list of Xcode themes (and fonts) a while ago. Many more themes have been submitted in the meanwhile so if you have a theme you'd like to add to the list, just let me know!

<hr>

## Xcode Themes

> 👨🏻💻 Personal themes for [Xcode](http://developer.apple.com/xcode).

### Tokyo
![Tokyo](Tokyo.png)

### Aqua
![Aqua](Aqua.png)

## Installation
1. Copy the theme(s) to the Xcode's `FontAndColorThemes` folder (`~/Library/Developer/Xcode/UserData/FontAndColorThemes/`).
2. Restart Xcode.
3. Go to `Xcode > Preferences > Fonts & Colors`.
4. Select your favorite theme.

## License

This project is available under the [MIT](http://opensource.org/licenses/MIT) license. See the LICENSE file for more info.

repository: zrkb/xcode-themes

repo_name: zrkb/xcode-themes


text:
---
layout: post
title: Creating a Responsive Image Gallery with 19 Lines of CSS (and Flexbox)
excerpt: We've all taken cool, brooding, black & white photos. But how do you make them brood even when they're viewed on mobile?  Unlike beautiful, reflowable text, you can't just get part of your picture to move to the next line. Instead you have to write a bunch of weird rules that can result in having images stretched beyond their means, or shrunken in to obscurity.

Fear not.

By the end of this (shortish) blog post, you'll have the means to create a image gallery that can handle any device size and images of any dimension.  Use Flexbox to control the flow of your content. It's awesome. And no one uses IE8 anyway right?
2. Set a `max-height` property for your images, else they can take up some serious real-estate
    * Use `vh` to do this. It scales better than other units.
3. `object-fit: cover;` helps your image scale nicely, no matter what size box it's in. You may lose some content around the edges though.

Without further ado let's get on.

## Writing Your Markup
You have three major components in an image gallery:
* The gallery container
    * The container the image sits in (also known as the frame)
        * The image itself

This allows you to control each of the components individually if required. Here's how I wrote the markup.

<script src="https://gist.github.com/edwardcgordon/d2eb9b07b51b0a93734bb02019524e34.js"></script>

Here you've got `gallery` which is the whole gallery content. Then `gallery-block` which controls each element (looking back, should have called this "frame"). Then the image which has the class `gallery-image`.

Because I used massive images, mine looked like this. But you may have used smaller pictures. Fair play.

![gallery-without-styles](/images/gallery-no-style.jpg)

## CSyeS! Or; Flexbox, how I love thee.
Flexbox is a CSS layout engine for those of us who don't need to worry about Internet Explorer 8 (so, anyone outside the NHS...). It's great because it takes away a lot of the pain of alignment, overspill, wrapping and so on. There's a great chapter in [*Responsive Web Design with HTML5 and CSS3, Second Edition*](https://www.amazon.co.uk/Responsive-Web-Design-HTML5-CSS3/dp/1784398934/) that deals with Flexbox in detail or you can try the [w3schools.com site](https://www.w3schools.com/css/css3_flexbox.asp) for more info. For now, you're just going to use it and see what happens.

### Styling the White Cube
Art galleries used to be absolutely *full* of [images on every wall](https://commons.wikimedia.org/wiki/File:Fran%C3%A7ois-Joseph_Heim_-_Charles_V_Distributing_Awards_to_the_Artists_at_the_Close_of_the_Salon_of_1824_-_WGA11328.jpg). That changed in the 20th century, when galleries started to use white space to create a focus on fewer images. These galleries are known as the "White Cubes".

Now that I've explained how clever my heading is, let's see Flexbox in action. Rather than explaining it in text, the comments will help you out.

<script src="https://gist.github.com/edwardcgordon/ce72496204cda95fc3d04b862203bfe8.js"></script>

That's the first step done.

### Styling the Frame
This is nice and simple. You just have to tell your frames that they need to have a little margin between each one, and that they should take up a maximum of 100% of their available space. In fact, this bit is so small I won't use a Gist

```css
.gallery-block {
	margin: 1%;
	max-width: 100%;
	display: flex;
}
```

The `display: flex;` here is probably not strictly necessary. But it does tweak something, for certain, so I left it in!

### Styling Your Image
Lastly, you need to style your image. Paint your canvas. You know. Make your pictures look good.

<script src="https://gist.github.com/edwardcgordon/6068a26d26292730844c9d95e5dc71e5.js"></script>

The key thing here is the height. You can use any unit to control height. I like `vh` because it's linked to the height of the device accessing your site. I used a unit rather than `height: auto` because working with huge photographs on a big desktop screen makes them uncomfortably large. Also, I wasn't convinced that I was doing it properly, so I chose to tactically ignore it.

Combined with your other styles, eventually you get images that look like this:

![final-image-gallery](/images/styled-photos.png)

## Final Flourish
That's really all that there is to it. For my final site that you saw in the first picture, I added some simple elements to my HTML. The full site is here: [Framed](https://edwardcgordon.github.io/framed).

One thing that I also added was a mobile rule that forces a full width for mobile phones. This is because there was some really sad looking white space on my portrait-shaped images. You can do that as easy as

```css
@media (max-width: 740px) {
  .gallery-image {
    width: 100%;
  }
}
```

And now you have a full responsive image gallery ready for you to take ill-framed black and white pictures of your sleeping dog. You can use Flexbox for far more powerful solutions than I have here; we'll save that for another post though.

license: MIT

branch_name: refs/heads/master

extension: md

license_type: permissive


text:
---
layout: post
title: "Modelling Radiological Language with Bidirectional Long Short-Term Memory Networks"
date: 2016-09-27 13:25:10
categories: arXiv_CV
tags: arXiv_CV Embedding RNN Detection Relation Memory_Networks Recognition
author: Savelie Cornegruta, Robert Bakewell, Samuel Withey, Giovanni Montana
mathjax: true
---

* content
{:toc}

##### Abstract
Motivated by the need to automate medical information extraction from free-text radiological reports, we present a bi-directional long short-term memory (BiLSTM) neural network architecture for modelling radiological language. The model has been used to address two NLP tasks: medical named-entity recognition (NER) and negation detection. We investigate whether learning several types of word embeddings improves BiLSTM's performance on those tasks. Using a large dataset of chest x-ray reports, we compare the proposed model to a baseline dictionary-based NER system and a negation detection system that leverages the hand-crafted rules of the NegEx algorithm and the grammatical relations obtained from the Stanford Dependency Parser. Compared to these more traditional rule-based systems, we argue that BiLSTM offers a strong alternative for both our tasks.

##### Abstract (translated by Google)

##### URL
[https://arxiv.org/abs/1609.08409](https://arxiv.org/abs/1609.08409)

##### PDF
[https://arxiv.org/pdf/1609.08409](https://arxiv.org/pdf/1609.08409)


text:
---
title: "1. Welcome to Make School!"
slug: welcome
---

Welcome to the Make School family! We're absolutely thrilled to bring you on board!

![hello](https://media1.tenor.com/images/7579a792cffb3e35c5ae81669a8a3bb4/tenor.gif?itemid=12198352)
 Source: [Tenor](https://tenor.com/view/yay-bobs-burger-excited-happiness-hello-gif-12198352)

We'll see you in a few short weeks, but until then, we've prepared some tasks for you in this environment setup tutorial that will set you up for success at Make School. We'll cover how to set up your laptop so that you're ready to start coding.

> [action]
>
> **Watch the following video** by Dan, a Make School instructor, to get an overview of what you'll accomplish in this tutorial:
>
> ![ms-video-youtube](https://www.youtube.com/watch?v=S7eSqgI0Tyk)

Once you finish each section, click the "Mark as Complete" checkbox. If you've made it this far, go ahead and click the one below this box now!

# Learning Outcomes

During your time at Make School, you'll see **learning outcomes** throughout your tutorials, courses, and lessons. Think of these as the skills you are gaining that will allow you to excel in your software engineering career.

> [info]
>
> It's a great practice to _self reflect_ on these learning outcomes any time you complete a tutorial, lesson, or course, and see if you met the learning outcomes. If you didn't, talk to your peers, instructor, or coach to figure out what you can do to achieve these outcomes

By the end of this tutorial, you should be able to...

1. Set up your development environment to be coding ready
1. Describe Make School's academic policies

> [action]
>
> Reflect on these as you complete each chapter. Are you meeting these outcomes?

# Tell Us About Yourself

We have students from all different walks of life, and we'd love to learn about yours!

> [action]
>
> Take a few minutes to [fill out your student profile](https://forms.gle/h56BE7LxgbPBLs2X9). This will be available for all students/staff to see, so please fill it out appropriately.

Looking forward to learning more about you! Now, are you ready to get that development environment set up?

![lets-do-this](https://media.giphy.com/media/Cx0JktG3wBWvu/giphy.gif)

 Source: [Giphy](https://media.giphy.com/media/Cx0JktG3wBWvu/giphy.gif)

Onto the next chapter!

repository: KitsuneNoctus/makeschool

branch_name: refs/heads/main

gha_license_id: MIT

repo_name: KitsuneNoctus/makeschool


text:
# GenePattern Notebook Repository

This is a dockerized instance of the GenePattern Notebook Repository, a customized DockerHub deployment
running the GenePattern Notebook environment.

## Installing the Notebook Repository

To start an instance of the Notebook Repository, first pull both the Notebook Repository and the
GenePattern Notebook docker containers:

> docker pull genepattern/notebook-repository
> docker pull genepattern/genepattern-notebook

Next, make sure you have a directory ready on the host file system that will store the persistent state of
the repository. By default this will be located at `/data`, but this can be overridden (see below).

## Starting the Notebook Repository

We recommend starting the Notebook Repository container using the `start-repository.py` script included in
this directory. This will start the container with all of the docker options needed to run. It will also
lazily set up your data directory, if necessary, and configure docker to launch single-user containers as
siblings of the Notebook Repository container.

You can override the location of your data directory by passing in the `--DATA` parameter. If you do not,
the container will assume that it lives at `/data` on the host file system. See the example below.

> ./start-repository.py --data=/path/to/data

You can also override the default port number (port 80) by setting `--port` or the default Docker network
name (repo) by setting `--network`.

The `stop-repository.py` script can be used to stop the repository.

## Configuring the Notebook Repository

The Notebook Repository can be configured by tweaking the `jupyterhub_config.py` and `settings.py` files
in the `/data` directory. The former file configures JupyterHub, while the latter file configures the
notebook repository's publishing and sharing webservice. At very minimum, we recommend that you change the
secret key in `settings.py` from its default to a value of your choosing.

## Issues with Docker Swarm

We've run into issues configuring the repository to run with SwarmSpawner because of a bug mounting the
shared volume. Below is a hack to get around that bug. We'd welcome a better solution, but in the
meantime thought it would be useful to share this with the community.

```python
from dockerspawner import SwarmSpawner
from docker.types import Mount
from tornado import gen

class FixedSwarmSpawner(SwarmSpawner):

   @gen.coroutine
    def start_object(self):
        """Not actually starting anything
        but use this to wait for the container to be running.
        Spawner.start shouldn't return until the Spawner
        believes a server is *running* somewhere,
        not just requested.
        """

        dt = 1.0

        while True:
            yield gen.sleep(dt)
            service = yield self.get_task()
            if not service:
                raise RuntimeError("Service %s not found" % self.service_name)

            status = service["Status"]
            state = status["State"].lower()
            self.log.debug("Service %s state: %s", self.service_id[:7], state)
            if state in {"new", "assigned", "accepted", "starting", "pending", "preparing"}:
                # not ready yet, wait before checking again
                yield gen.sleep(dt)
                # exponential backoff
                dt = min(dt * 1.5, 11)
            else:
                break
        if state != "running":
            raise RuntimeError(
                "Service %s not running: %s" % (self.service_name, pformat(status))
            )

    @property
    def mounts(self):
        if len(self.volume_binds):
            driver = self.mount_driver_config
            return [
                Mount(
                    target=vol["bind"],
                    source=host_loc,
                    type="bind",
                    read_only=vol["mode"] == "ro",
                    driver_config=None,  # This needs to be None or the spawner throws an error
                )
                for host_loc, vol in self.volume_binds.items()
            ]

        else:
            return []

c.JupyterHub.spawner_class = FixedSwarmSpawner

# Configure DockerSpawner
c.FixedSwarmSpawner.image = 'genepattern/genepattern-notebook'
c.FixedSwarmSpawner.network_name = 'repo'
c.FixedSwarmSpawner.extra_host_config = { 'network_mode': 'repo' }
c.FixedSwarmSpawner.remove_containers = True
c.FixedSwarmSpawner.debug = True

# Mount the user's directory in the singleuser containers
if 'DATA_DIR' in os.environ:
    c.FixedSwarmSpawner.volumes = {
        os.environ['DATA_DIR'] + '/users/{raw_username}': '/home/jovyan',    # Mount users directory
    }
```

repository: genepattern/notebook-docker

repo_name: genepattern/notebook-docker


text:
## Appsmith EE

We use the `@appsmith` alias to switch files between CE and EE to avoid conflicts
during regular merging.

Steps to change something for the EE version of app

- For the functionality you want to change the import statement in its consumers
to include the `@appsmith` import in the *CE repo*. For eg if you want to update the ApplicationCard
 component will update this file of ApplicationList component.

  *FROM*
  ```typescript
  // ApplicationList.tsx

  import ApplicationCard from "./ApplicationCard";

  // OR

  import ApplicationCard from "pages/Applications/ApplicationCard";
  ```

  *TO*
  ```typescript
  // ApplicationList.tsx

  import ApplicationCard from "@appsmith/pages/Applications/ApplicationCard";
  ```

- Create a new file inside the *EE repo* called ApplicationCard with the same path
    ```shell script
    $ touch app/client/src/enterprise/pages/Applications/ApplicationCard
    ```
- EE will now use this file, so you can export a custom ApplicationCard component for EE.

The goal is to reduce conflicts and have EE extend virtually any part of CE so selecting files to
 update will be crucial. You should keep the following points in mind:

 - NEVER update the CE file in the EE repo
 - All the consumers of the file will need it's expected exports.
 - You can import from the CE file and reexport from your EE if no changes are expected.
 - The types of component props if different will cause problems in the component declaration and use.
 You can export that out these props into the `@appsmith` space to avoid this problem by reimplementing them in EE.

repository: Nikhil-Nandagopal/appsmith

branch_name: refs/heads/release

gha_language: TypeScript

repo_name: Nikhil-Nandagopal/appsmith


text:
Namespaced Jasmine Suites
=========================

Overview
--------

This extends [Jasmine](http://pivotal.github.io/jasmine/) 4.6+ by making it
easy to create nested, reusable namespaces for test suites.

Typically, a large codebase using Jasmine will split tests into multiple files,
each with a `describe()` call wrapping the file's tests. This works fine for
small sets of tests, but on a larger codebase, it leaves much to be desired.
There's no way to organize tests across files under a common suite, or to
limit the test run to those tests.

Namespaced suites solve this by taking a namespaced path (something like
`projectname/mysuite/component`) and automatically generating test suites for
each component of the namespace.

It will also merge any tests in that refer to the same parts of the namespace
from other files.

Usage
-----

Switching to namespaced suites is really easy. Instead of doing this:

```javascript
describe('projectname/mysuite/component', function() {
    ...
});
```

or:

```javascript
describe('projectname', function() {
    describe('mysuite', function() {
        describe('component', function() {
           ...
        });
    });
});
```

You can instead do:

```javascript
suite('projectname/mysuite/component', function() {
   ...
});
```

You can reuse any part of that namespace in as many files as you like. Their
tests will be combined into the suites.

For example, say you have the following:

```javascript
// tests1.js
suite('projectname/models/MyModel', function() {
   ...
});

suite('projectname/views/MyView', function() {
   ...
});

// tests2.js
suite('projectname/views/AnotherView', function() {
   ...
});
```

Jasmine will end up laying out the tests like:

    projectname

        models

        views

            MyView

            AnotherView

Where is this used?
-------------------

We use jasmine-suites at [Beanbag](https://www.beanbaginc.com/) for our
[Review Board](https://www.reviewboard.org/) and
[RBCommons](https://rbcommons.com/) products.

If you use jasmine-suites, let us know and we'll add you to a shiny new list on
this page.

License
-------

Jasmine Suites is under the MIT license.

repository: beanbaginc/jasmine-suites

gha_language: JavaScript

repo_name: beanbaginc/jasmine-suites


text:
---
hrs_structure:
  division: '2'
  volume: '10'
  title: '25'
  chapter: 461J
  section: 461J-9
type: hrs_section
tags:
  - Business
menu:
  hrs:
    identifier: HRS_0461J-0009
    parent: HRS0461J
    name: 461J-9 Temporary license
weight: 71060
title: Temporary license
full_title: 461J-9 Temporary license
---
**[§461J-9] Temporary license.** The board shall establish rules for issuing temporary licenses to applicants for permanent licenses either under section 461J-6 or 461J-7\. The rules adopted by the board shall include provisions concerning the length of time for which temporary licenses are valid, the renewal of such licenses, and the need for supervision by a physical therapist holding a permanent license. [L 1985, c 276, pt of §1]

repository: SamMade/BlueAndKrabby

repo_name: SamMade/BlueAndKrabby


text:
## What is ansible-sshd?

It is an [ansible](http://www.ansible.com/home) role to install openssh-server and configure it.

### What problem does it solve and why is it useful?

Often times you want to disable root logins and password based logins. This role sets those options by default but it also exposes every config value found in the default ubuntu 14.04 `sshd_config` file.

## Role variables

Below is a list of default values along with a description of what they do.

```
# To view what these commands do, check out:
# http://www.openssh.com/cgi-bin/man.cgi?query=sshd_config

sshd_port: "22"
sshd_listen_address: "<IP_ADDRESS>"
sshd_protocol: "2"
sshd_host_rsa_key: "/etc/ssh/ssh_host_rsa_key"
sshd_host_dsa_key: "/etc/ssh/ssh_host_dsa_key"
sshd_host_ecdsa_key: "/etc/ssh/ssh_host_ecdsa_key"
sshd_use_privilege_separation: "yes"
sshd_key_regeneration_interval: "3600"
sshd_server_key_bits: "768"
sshd_syslog_facility: "AUTH"
sshd_log_level: "INFO"
sshd_login_grace_time: "120"
sshd_permit_root_login: "no"
sshd_strict_modes: "yes"
sshd_rsa_authentication: "yes"
sshd_pubkey_authentication: "yes"
sshd_authorized_keys_file: "%h/.ssh/authorized_keys"
sshd_ignore_rhosts: "yes"
sshd_rhosts_rsa_authentication: "no"
sshd_host_based_authentication: "no"
sshd_ignore_user_known_hosts: "no"
sshd_permit_empty_passwords: "no"
sshd_challenge_response_authentication: "no"
sshd_password_authentication: "no"
sshd_gss_api_authentication: "no"
sshd_gss_api_cleanup_credentials: "yes"
sshd_x11_forwarding: "yes"
sshd_x11_display_offset: "10"
sshd_print_motd: "no"
sshd_print_last_log: "yes"
sshd_tcp_keep_alive: "yes"
sshd_max_startups: "10:30:100"
sshd_banner: "none"
sshd_accept_env: "LANG LC_*"
sshd_subsystem: "sftp /usr/lib/openssh/sftp-server"
sshd_use_pam: "yes"
```

## Attribution

Many thanks to [nickjj](https://github.com/nickjj/) for creating the [original version](https://github.com/nickjj/ansible-sshd/) of this role.

repository: afonsoduarte/ansible-stacey

repo_name: afonsoduarte/ansible-stacey


text:
# Welcome

Welcome to the FamiStudio documentation. Please use the __User Guide__ menu above to navigate the the various sections or use the Table of Contents below. Also, you can use the __Search__ button to search for a specific topic.

# Table of Contents

* [Installation Procedure & Troubleshooting](install.md)
* [FamiStudio Basics](basics.md)
* [Editing Notes](pianoroll.md)
* [Editing Patterns](sequencer.md)
* [Editing Instruments & Arpeggios](instruments.md)
* [Editing Songs & Project](song.md)
* [Editing DPCM Samples](dpcm.md)
* [Importing Songs](import.md)
* [Exporting Songs](export.md)
* [Using Expansion Audio](expansion.md)
* [Cleaning-up your Project](cleanup.md)
* [Configuring FamiStudio]( config.md)
* [Command-line Processing](cmdline.md)
* [NES/Famicom Sound Engine](soundengine.md)
* [Acknowledgements](thanks.md)
* [Troubleshooting](troubleshooting.md)
* [Change Log](changelog.md)

# Tutorial for FamiStudio desktop

The quickest way of getting started with FamiStudio is simply to follow this tutorial video step by step. It will walk you through the creation a simple song, from beginning to end.

# Tutorial for FamiStudio mobile

If you are using the mobile version of FamiStudio, please check out this tutorial to get you started!

# Discord Server

If you need to talk other users or have a casual conversation with the developer, please come see us on [Discord](https://discord.gg/88UPmxh)!

[![](images/Discord.png#center)](https://discord.gg/88UPmxh)

repository: BleuBleu/FamiStudio

gha_language: C#

repo_name: BleuBleu/FamiStudio


text:
LSCheckCamera

**Password authentication is performed when opening the lock screen camera.**

## LSCheckCamera
Have you ever wondered why there is no password authentication when opening the camera app from the lock screen?  LSCheckCamera makes that possible.

## Compatibility
- iOS13 ~ 13.5
- arm64 & arm64e (iPhoneX or later)

## Known Issues
- Touch ID cannot be used

## Copyright
[@Minazuki_dev](https://twitter.com/Minazuki_dev) 2020

repository: niuzai-png/LSCheckCamera

repo_name: niuzai-png/LSCheckCamera


text:
# Project Name

![GitHub repo size](https://img.shields.io/github/repo-size/milanpanchal/README-template.md)
![GitHub contributors](https://img.shields.io/github/contributors/milanpanchal/README-template.md)
![GitHub stars](https://img.shields.io/github/stars/milanpanchal/README-template.md?style=social)
![GitHub forks](https://img.shields.io/github/forks/milanpanchal/README-template.md?style=social)
![Twitter Follow](https://img.shields.io/twitter/follow/milan_panchal24?style=social)
![Platform](https://img.shields.io/badge/platform-ios-blue.svg?style=flat)
![Swift version](https://img.shields.io/badge/Swift-5-orange.svg?style=flat)
![License](https://img.shields.io/github/license/milanpanchal/README-template.md)

Write short description about the project.

### :gear: Prerequisites

Before you begin, ensure you have met the following requirements:

* iOS 13+
* Xcode 11+
* Mac OS
* Cocoa Pods/Carthage/Swift PM

### Installation

##### [CocoaPods](http://cocoapods.org)

`<project-name>` is available through CocoaPods. To install it, simply add the following line to your Podfile:
```ruby
pod "project-name"
```

##### [Carthage](https://github.com/Carthage/Carthage#if-youre-building-for-ios)

To integrate `<project-name>` into your Xcode project using Carthage, specify it in your Cartfile:
```ruby
github `<project-name>`
```

##### [Swift PM](https://swift.org/package-manager/)

Using Xcode's Swift Package Manager, it can be installed by going to `File -> Swift Packages -> Add Package Dependency` and pasting the URL of this repository.

```swift
dependencies: [
  .package(url: "https://github.com/milanpanchal/README-template.md.git", from: "1.0")
]
```

##### Manual Installation

Just drag and drop the `your-folder/` folder into your project

### :sparkles: Features

List down all your features here.

- [x] Feature 1
- [x] Feature 2
- [x] Feature 3 and so on.

### Preview

Add your preview images or videos here.

### Contributing to <project_name>

To contribute to `<project_name>`, follow these steps:

1. Fork this repository.
2. Create a branch: `git checkout -b <branch_name>`.
3. Make your changes and commit them: `git commit -m '<commit_message>'`
4. Push to the original branch: `git push origin <project_name>/<location>`
5. Create the pull request.

Alternatively see the GitHub documentation on [creating a pull request](https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request).

### Contributors

Thanks to the following people who have contributed to this project:

* [@milanpanchal](https://github.com/milanpanchal)

You might want to consider using something like the [All Contributors](https://github.com/all-contributors/all-contributors) specification and its [emoji key](https://allcontributors.org/docs/en/emoji-key).

### Author

**Milan Panchal**, follow me on:

1. **Twitter** ([@milan_panchal24](https://twitter.com/milan_panchal24))

2. **Github** ([/milanpanchal](https://github.com/milanpanchal/))

3. **Medium** ([https://medium.com/@milanpanchal24](https://medium.com/@milanpanchal24))

4. **LinkedIn** ([/in/milanpanchal/](https://www.linkedin.com/in/milanpanchal/))

### License

`<project_name>` is under the MIT license. See the LICENSE file for more info.

**Free Software, Hell Yeah!**


text:
## Linux Virtual Networking
Linux virtual networking is made easy by libvirt and linux virtual bridge. See [libvirt Virtual Networking](http://wiki.libvirt.org/page/VirtualNetworking).

Install, start and enable the libvirt
```
# yum install libvirt
# systemctl start libvirtd
# systemctl enable libvirtd
```

The libvirt supports following type of virtual networking:

1. Network Address Translation mode
2. Routed mode
3. Isolated mode
4. Bridged Mode

#### Virtual Networking in NAT Mode
When the libvirt daemon is first installed on a server, it comes with an initial default virtual network switch configuration. This default virtual switch is in NAT mode, and is used by installed Virtual Machines for communication to the outside network through the host physical machine. The configuration is stored in the XML file ``/etc/libvirt/qemu/networks/default.xml``. A ``virbr0`` interface is also created on the host machine.
```
# cat /etc/libvirt/qemu/networks/default.xml
<network>
  <name>default</name>
  <uuid>f6514662-26e5-431e-8544-fd216bed9312</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:53:d4:ee'/>
  <ip address='<IP_ADDRESS>' netmask='<IP_ADDRESS>'>
    <dhcp>
      <range start='<IP_ADDRESS>' end='<IP_ADDRESS>'/>
    </dhcp>
  </ip>
</network>

# ifconfig virbr0
virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet <IP_ADDRESS>  netmask <IP_ADDRESS>  broadcast <IP_ADDRESS>
        ether 52:54:00:53:d4:ee  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# ping <IP_ADDRESS>
PING <IP_ADDRESS> (<IP_ADDRESS>) 56(84) bytes of data.
64 bytes from <IP_ADDRESS>: icmp_seq=1 ttl=64 time=0.044 ms
64 bytes from <IP_ADDRESS>: icmp_seq=2 ttl=64 time=0.035 ms
^C
```
The ``virsh`` command is used to configure and check the virtual networking
```
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes
```
If it is missing, then the example XML config can be reloaded & activated
```
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------

# virsh net-define /etc/libvirt/qemu/networks/default.xml
Network default defined from /etc/libvirt/qemu/networks/default.xml
# virsh net-start default
Network default started
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes
```

When the libvirt default network is running, you will see an isolated bridge device. This device explicitly does *NOT* have any physical interfaces added, since it uses NAT + forwarding to connect to outside world. Do not add interfaces to this bridge
```
# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.52540053d4ee       yes             virbr0-nic
```

The libvirt will add iptables rules to allow traffic to/from guests attached to the virtual interface. It will also attempt to enable ip_forward. Some other applications may disable it, so the best option is to add the following to check before to procede
```
# cat /etc/sysctl.conf
...
net.ipv4.ip_forward=1
...
```

Create a Virtual Machine (KVM) and attach it to the virtual network
```
# yum install virt-install
# virt-install \
--name VM1 \
--ram 2048 \
--vcpu 2 \
--network network=default \
--graphics none \
--os-type linux \
--disk path=/data/vm-images/vm1.img,size=10 \
--location /tmp/ubuntu-14.04.1-server-amd64.iso \
--extra-args 'console=ttyS0,115200n8 serial'
```

On the host machine, check that a new interface ``vnet0`` has been set and this interface is part of the linux bridge previously defined
```
#ifconfig vnet0
vnet0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::fc54:ff:fe6d:3355  prefixlen 64  scopeid 0x20<link>
        ether fe:54:00:6d:33:55  txqueuelen 500  (Ethernet)
        RX packets 117  bytes 55089 (53.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6958  bytes 372399 (363.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.52540053d4ee       yes             virbr0-nic
                                                        vnet0

```

Login to the VM machine and check the network access to external networks
```
# virsh list --all
 Id    Name                           State
----------------------------------------------------
 4     VM1                            running

# virsh console VM1
Connected to domain VM1
Ubuntu 14.04.2 LTS VM1 ttyS0
VM1 login: caldera
Password:

caldera@VM1:~$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 52:54:00:6d:33:55
          inet addr:<IP_ADDRESS>  Bcast:<IP_ADDRESS>  Mask:<IP_ADDRESS>
          inet6 addr: fe80::5054:ff:fe6d:3355/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:94 errors:0 dropped:0 overruns:0 frame:0
          TX packets:119 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:14491 (14.4 KB)  TX bytes:55473 (55.4 KB)

caldera@VM1:~$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
<IP_ADDRESS>         <IP_ADDRESS>   <IP_ADDRESS>         UG        0 0          0 eth0
<IP_ADDRESS>   <IP_ADDRESS>         <IP_ADDRESS>   U         0 0          0 eth0
caldera@VM1:~$

caldera@VM1:~$ ping github.com
PING github.com (<IP_ADDRESS>) 56(84) bytes of data.
64 bytes from github.com (<IP_ADDRESS>): icmp_seq=1 ttl=50 time=100 ms
64 bytes from github.com (<IP_ADDRESS>): icmp_seq=1 ttl=50 time=100 ms
...
```

Create a second VM and check the second interface ``vnet1`` has been set and this interface is part of the linux bridge previously defined

```
# virt-install \
--name VM2 \
--ram 2048 \
--vcpu 2 \
--network network=default \
--graphics none \
--os-type linux \
--disk path=/data/vm-images/vm1.img,size=10 \
--location /tmp/ubuntu-14.04.1-server-amd64.iso \
--extra-args 'console=ttyS0,115200n8 serial'

# virsh list --all
 Id    Name                           State
----------------------------------------------------
 2     VM1                            running
 3     VM2                            running

# ifconfig vnet1
vnet1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::fc54:ff:feb7:1ab9  prefixlen 64  scopeid 0x20<link>
        ether fe:54:00:b7:1a:b9  txqueuelen 500  (Ethernet)
        RX packets 48  bytes 7264 (7.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 367  bytes 22146 (21.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.52540053d4ee       yes             virbr0-nic
                                                        vnet0
                                                        vnet1

```

Login to the VM2 and check the network communication between the VMs and outwards
```
# virsh console VM2
Connected to domain VM2
VM1 login: caldera
caldera@VM2:~$
caldera@VM2:~$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
<IP_ADDRESS>         <IP_ADDRESS>   <IP_ADDRESS>         UG        0 0          0 eth0
<IP_ADDRESS>   <IP_ADDRESS>         <IP_ADDRESS>   U         0 0          0 eth0
caldera@VM2:~$ tracepath cisco.com
 1?: [LOCALHOST]                                         pmtu 1500
 1:  <IP_ADDRESS>                                         0.265ms
 1:  <IP_ADDRESS>                                         0.255ms
 2:  <IP_ADDRESS>                                            1.952ms
     ...

caldera@VM2:~$ tracepath  <IP_ADDRESS> (VM1)
 1?: [LOCALHOST]                                         pmtu 1500
 1:  VM1                                                   0.660ms reached
 1:  VM1                                                   0.396ms reached
     Resume: pmtu 1500 hops 1 back 1
caldera@VM2:~$

```

On the host machine, check the bridge status

```
# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.52540053d4ee       yes             virbr0-nic
                                                        vnet0
                                                        vnet1
```

### Virtual Networking in Bridged Mode
Now let to implement the Bridge mode as a custom configuration of the virtual networking based on ``libvirt``.
First of all, disable the default network based on NAT model
```
# virsh net-destroy default
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
```

Create an XML file for the new custom bridge network with the bridge name set to mybridge0
```
# cp /etc/libvirt/qemu/networks/default.xml /etc/libvirt/qemu/networks/bridged_network.xml
# virsh net-define /etc/libvirt/qemu/networks/bridged_network.xml
Network bridged_network defined from /etc/libvirt/qemu/networks/bridged_network.xml
# virsh net-edit bridged_network
# cat /etc/libvirt/qemu/networks/bridged_network.xml
<network>
  <name>bridged_network</name>
  <uuid>6579db1f-ca49-4e51-a116-c1342cd5d47a</uuid>
  <forward mode='bridge'/>
  <bridge name='mybridge0'/>
</network>

# virsh net-start bridged_network
Network bridged_network started

# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 bridged_network      active     yes           yes
```

Create a new bridge called mybridge0
```
# brctl addbr mybridge0
# brctl show
bridge name     bridge id               STP enabled     interfaces
mybridge0       8000.0024810d318d       no
```

Create a network interface file script for the bridge above. The IP Address and the other network parameters are, usually, taken from the real network interface.
```
# vi /etc/sysconfig/network-scripts/ifcfg-mybridge0
DEVICE=mybridge0
TYPE=Bridge
BOOTPROTO=none
IPADDR=<IP_ADDRESS>
PREFIX=24
GATEWAY=<IP_ADDRESS>
DNS1=<IP_ADDRESS>
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
ONBOOT=yes
DELAY=0
NM_CONTROLLED=no
```

Change the real network interface parameters, in order to be an unnumbered interface
```
# vi /etc/sysconfig/network-scripts/ifcfg-enp0s25
TYPE=Ethernet
BOOTPROTO=none
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME=enp0s25
UUID=48d129a3-89df-4f8b-9b99-5e3518edc111
ONBOOT=yes
HWADDR=00:24:81:0D:3F:8D
BRIDGE=mybridge0
NM_CONTROLLED=no
IPV4_FAILURE_FATAL=no
```

Then, assign the real network card to the bridge and restart the network service
```
# brctl addif mybridge0 enp0s25
# brctl show
bridge name     bridge id               STP enabled     interfaces
mybridge0       8000.0024810d318d       no              enp0s25

# systemctl restart network
# ifconfig mybridge0
mybridge0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet <IP_ADDRESS>  netmask <IP_ADDRESS>  broadcast <IP_ADDRESS>
        inet6 fe80::224:81ff:fe0d:318d  prefixlen 64  scopeid 0x20<link>
        ether 00:24:81:0d:3f:8d  txqueuelen 0  (Ethernet)
        RX packets 232483  bytes 612684572 (584.3 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 212561  bytes 17767763 (16.9 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

```

Create a new virtual machine to use the bridged network

```
# virt-install \
--name VM3 \
--ram 2048 \
--vcpu 2 \
--network network=bridged_network \
--graphics none \
--os-type linux \
--disk path=/data/vm-images/vm3.img,size=10 \
--location /tmp/ubuntu-14.04.1-server-amd64.iso \
--extra-args 'console=ttyS0,115200n8 serial'

# virsh list-all
 Id    Name                           State
----------------------------------------------------
 6     VM3                            running
 -     VM1                            shut off
 -     VM2                            shut off

```

Login to the new VM and check that it is getting connectivity by the same network infrastructure as the host
```
ubuntu login: caldera
Password:
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-55-generic x86_64)
...
caldera@ubuntu:~$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 52:54:00:33:cc:01
          inet addr:<IP_ADDRESS>  Bcast:<IP_ADDRESS>  Mask:<IP_ADDRESS>
          inet6 addr: fe80::5054:ff:fe33:cc01/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:81 errors:0 dropped:0 overruns:0 frame:0
          TX packets:30 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:8247 (8.2 KB)  TX bytes:3057 (3.0 KB)

caldera@ubuntu:~$ ping github.com
PING github.com (<IP_ADDRESS>) 56(84) bytes of data.
64 bytes from github.com (<IP_ADDRESS>): icmp_seq=1 ttl=50 time=101 ms
64 bytes from github.com (<IP_ADDRESS>): icmp_seq=2 ttl=50 time=100 ms
^C
caldera@ubuntu:~$ netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
<IP_ADDRESS>         <IP_ADDRESS>      <IP_ADDRESS>         UG        0 0          0 eth0
<IP_ADDRESS>      <IP_ADDRESS>         <IP_ADDRESS>   U         0 0          0 eth0
```

Finally, check that a new host interface called ``vnet0`` is present and is part of the bridge
```
# ifconfig vnet0
vnet0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet6 fe80::fc54:ff:fe33:cc01  prefixlen 64  scopeid 0x20<link>
        ether fe:54:00:33:cc:01  txqueuelen 500  (Ethernet)
        RX packets 1556  bytes 147144 (143.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3892  bytes 3763246 (3.5 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# brctl show
bridge name     bridge id               STP enabled     interfaces
mybridge0       8000.0024810d318d       no              enp0s25
                                                        vnet0
```

Please, note that different virtual networks types can be share the same physical host, e.g. NAT and Bridged mode.
Enable the default virtual network as defined previously in NAT mode

```
# virsh net-start default
Network default started
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 bridged_network      active     yes           yes
 default              active     yes           yes

# virsh start VM1
Domain VM1 started

# virsh start VM2
Domain VM2 started

# virsh list --all
 Id    Name                           State
----------------------------------------------------
 6     VM3                            running
 7     VM1                            running
 8     VM2                            running
```

### Virtual Networking in Routed Mode
Routed mode is a variation of the virtual networking with NAT mode. In routing mode, the ``virbr0`` interface acts as routing interface without NAT. The DHCP can be enabled or not, depending on the requirements.

Create the envinronment for the routed virtual networking

```
# cat /etc/libvirt/qemu/networks/router.xml
<network>
  <name>router</name>
  <uuid>186ffd11-ce2d-452a-9970-baf07b723de8</uuid>
  <forward mode='route'/>
  <bridge name='virbr1' stp='on' delay='0'/>
  <mac address='52:54:00:56:e6:21'/>
  <ip address='<IP_ADDRESS>' netmask='<IP_ADDRESS>'>
  </ip>
</network>

# virsh net-define /etc/libvirt/qemu/networks/router.xml
Network router defined from /etc/libvirt/qemu/networks/router.xml

# virsh net-edit router
Network router XML configuration not changed.

# virsh net-start router
Network router started

# virsh net-autostart router
Network router marked as autostarted

# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes
 router               active     yes           yes

# ifconfig virbr1
virbr1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet <IP_ADDRESS>  netmask <IP_ADDRESS>  broadcast <IP_ADDRESS>
        ether 52:54:00:46:e6:21  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

# brctl show virbr1
bridge name     bridge id               STP enabled     interfaces
virbr1          8000.52540046e621       yes             virbr1-nic

# netstat -nr
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
<IP_ADDRESS>         <IP_ADDRESS>      <IP_ADDRESS>         UG        0 0          0 enp0s25
<IP_ADDRESS>      <IP_ADDRESS>         <IP_ADDRESS>   U         0 0          0 enp0s25
<IP_ADDRESS>   <IP_ADDRESS>         <IP_ADDRESS>   U         0 0          0 virbr0
<IP_ADDRESS>   <IP_ADDRESS>         <IP_ADDRESS>   U         0 0          0 virbr1
```

The VMs must be created with static IP address in the same network of the ``virbr1`` and default gateway the same interface. Since no NAT is performed by the virtual networking, make sure the network env is aware of the new network (e.g. put static routes).

### Spawning multiple hosts
Linux virtual networking can spawn multiple hosts. Let to build a virtual networking setup of two hosts whith several VMs running on both. Only one host has a network interface connected to internet, and so it acts as a NAT gateway for both the hosts. The two hosts are bridged togeter using a secondary network interface.

```
 caldera02            caldera03
----------            ----------
|   VM1  |            |   VM1  |
|   VM2  |============|   VM2  |
----------            ----------
    ||
 Internet
```

On the gateway host, caldera02, enable the default virtual networking in NAT mode
```
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

# cat /etc/libvirt/qemu/networks/default.xml
<network>
  <name>default</name>
  <uuid>f6514662-26e5-431e-8544-fd216bed9312</uuid>
  <forward mode='nat'/>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:53:d4:ee'/>
  <ip address='<IP_ADDRESS>' netmask='<IP_ADDRESS>'>
    <dhcp>
      <range start='<IP_ADDRESS>' end='<IP_ADDRESS>'/>
    </dhcp>
  </ip>
</network>
```

Create and start two VMs and check the bridge status
```
# virsh start VM1
# virsh start VM2
# virsh list --all
 Id    Name                           State
----------------------------------------------------
 16    VM1                            running
 17    VM2                            running

# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.52540053d4ee       yes             virbr0-nic
                                                        vnet2
                                                        vnet3
```

This is a simple virtual networking in NAT mode where virtual interfaces of the virtual machines, ``vnet2`` and ``vnet3`` are bridged togeter with the bridge interface ``virbr0-nic``.

On the second host, caldera03, enable the default virtual networking in isolated mode, i.e. the virtual machines can only talk to each other.

```
# virsh net-list
 Name                 State      Autostart     Persistent
----------------------------------------------------------
 default              active     yes           yes

cat /etc/libvirt/qemu/networks/default.xml
<network>
  <name>default</name>
  <uuid>e8849d67-243a-4b0f-83ea-bc2b447580cf</uuid>
  <bridge name='virbr0' stp='on' delay='0'/>
  <mac address='52:54:00:22:1b:5f'/>
</network>
```

The missing ``<forward mode=''/>`` tag means the virtual networking is in isolated mode. Also, the missing ``<ip address='' netmask=''>`` tag means the virtual networking interface is unnumbered and the VMs will not receive any IP address.

Create and start two VMs and check the bridge
```
# virsh start VM1
# virsh start VM2
# virsh list --all
 Id    Name                           State
----------------------------------------------------
 16    VM1                            running
 17    VM2                            running

# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.c46e1f0099cd       yes             virbr0-nic
                                                        vnet0
                                                        vnet1

```

Now we have to bridge the two hosts with a dedicated network interface ``ens2``.
On the gateway host, caldera02, make ``ens2`` interface unnumbered and add it to the bridge
```
# cat /etc/sysconfig/network-scripts/ifcfg-ens2
TYPE=Ethernet
BOOTPROTO=none
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME=ens2
UUID=452ee132-35a6-4c36-915b-91b85902f2b9
ONBOOT=yes
NM_CONTROLLED=no

#  brctl addif virbr0 ens2
#  brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.52540053d4ee       yes             ens2
                                                        virbr0-nic
                                                        vnet2
                                                        vnet3
```

Do the same on the second host, caldera03
```
# cat /etc/sysconfig/network-scripts/ifcfg-ens2
TYPE=Ethernet
BOOTPROTO=none
IPV4_FAILURE_FATAL=no
IPV6INIT=no
NAME=ens2
UUID=1de92d8b-1c83-4bf5-be22-171f65b1b66b
ONBOOT=yes
NM_CONTROLLED=no

#  brctl addif virbr0 ens2
# brctl show
bridge name     bridge id               STP enabled     interfaces
virbr0          8000.c46e1f0099cd       yes             ens2
                                                        vnet0
                                                        vnet1
```

On the host caldera03, login to VM and check the virtual machine is getting the IP address from the gateway host, caldera02. Then check the tracepath to the internet
```
# virsh console VM1
Connected to domain VM1
Escape character is ^]

caldera@ubuntu:~$ ifconfig eth0
eth0      Link encap:Ethernet  HWaddr 52:54:00:36:5a:aa
          inet addr:<IP_ADDRESS>  Bcast:<IP_ADDRESS>  Mask:<IP_ADDRESS>
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:4975 errors:0 dropped:0 overruns:0 frame:0
          TX packets:3031 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:6741689 (6.7 MB)  TX bytes:368948 (368.9 KB)

caldera@ubuntu:~$ tracepath cisco.com
 1?: [LOCALHOST]                                         pmtu 1500
 1:  <IP_ADDRESS>                                         0.686ms
 1:  <IP_ADDRESS>                                         0.670ms
 2:  <IP_ADDRESS>                                            4.425ms

```


text:
# Lesson 4!

Please go to this link in order to render the exercise:

[Render exercise!](http://github.ekorre.org/2017-Google-Developer-Challenge/Lesson-4/index.html)

[You can access the file in **codepen.io** here!](https://codepen.io/jaimeandrescatano/pen/yPqova)

### [](#header-3)Changed

* 2017-12-09 Change figure tag for img tag according to [comment of one of the mentors](https://discussions.udacity.com/t/share-your-project-mentor-feedback/412844/657)

**Jaime Andres**

repository: jaimeandrescatano/ekorre

repo_name: jaimeandrescatano/ekorre


text:
# Liu (流)

Liu is a data flow analysis framework for fun.

Liu means flow in Chinese.

## License

This project is MIT-licensed.

repository: kavinyao/Liu

repo_name: kavinyao/Liu


text:
# Change Log

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

# [1.1.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v1.0.0...v1.1.0) (2017-06-09)

### Bug Fixes

* Fix miss .env error if .env not exists ([020432c](https://github.com/zhongzhi107/universal-react-starter-kit/commit/020432c))
* Fix unknown plugin "react-hot-loader/babel" ([ccc8ec5](https://github.com/zhongzhi107/universal-react-starter-kit/commit/ccc8ec5))
* Fixed New Deprecation Warnings where react version >= 15.5 ([c53a97f](https://github.com/zhongzhi107/universal-react-starter-kit/commit/c53a97f))
* Fixed not found favicon_16.png ([5945b4d](https://github.com/zhongzhi107/universal-react-starter-kit/commit/5945b4d))
* Move NODE_PATH from .env to package.json ([baa6f87](https://github.com/zhongzhi107/universal-react-starter-kit/commit/baa6f87))

### Features

* Add socket support ([7624515](https://github.com/zhongzhi107/universal-react-starter-kit/commit/7624515))
* Added all bootstrap styles into web page header,  it can smoothen the initial style flash on page load in development mode ([965dfcc](https://github.com/zhongzhi107/universal-react-starter-kit/commit/965dfcc))
* Added config option  `__DISABLE_HMR__`, which can disable hot-module-replace ([0448eb3](https://github.com/zhongzhi107/universal-react-starter-kit/commit/0448eb3))
* Added fontOutputDirectory build option ([ccdf5bf](https://github.com/zhongzhi107/universal-react-starter-kit/commit/ccdf5bf))
* Compress middleware for Koa ([4a891e3](https://github.com/zhongzhi107/universal-react-starter-kit/commit/4a891e3))
* Disabled file-loader date-url function ([5d901c1](https://github.com/zhongzhi107/universal-react-starter-kit/commit/5d901c1))
* Disabled source map ([5cb6fd9](https://github.com/zhongzhi107/universal-react-starter-kit/commit/5cb6fd9))
* react-hot-loader ([b5cd749](https://github.com/zhongzhi107/universal-react-starter-kit/commit/b5cd749))
* **i18n:** Added react-intl to dependencies, which support ([d3eff91](https://github.com/zhongzhi107/universal-react-starter-kit/commit/d3eff91))
* **styleLint:** Ignore Pseudo Classes : global which uses by CSS Module ([96e1cae](https://github.com/zhongzhi107/universal-react-starter-kit/commit/96e1cae))
* Replaced webpack-hot-middleware & webpack-dev-middleware with koa-webpack, which has better compatibility ([38c9cf6](https://github.com/zhongzhi107/universal-react-starter-kit/commit/38c9cf6))
* Rule.query only exists for compatibility reasons. Use Rule.options instead. ([661a1dc](https://github.com/zhongzhi107/universal-react-starter-kit/commit/661a1dc))
* Updated manifest.json when it's content be changed ([ca7a63a](https://github.com/zhongzhi107/universal-react-starter-kit/commit/ca7a63a))

# [1.0.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.6.0...v1.0.0) (2017-03-08)

### Bug Fixes

* **build:** Fix chunk file name output path ([145e039](https://github.com/zhongzhi107/universal-react-starter-kit/commit/145e039))
* **build:** os.hostname syntax error ([89193dd](https://github.com/zhongzhi107/universal-react-starter-kit/commit/89193dd))
* Enable dll plugin and check manifest file when yarn run serve ([07cf0aa](https://github.com/zhongzhi107/universal-react-starter-kit/commit/07cf0aa))
* NPM install ([535c45a](https://github.com/zhongzhi107/universal-react-starter-kit/commit/535c45a))
* Remove OfflinePlugin warning ([56ad7ce](https://github.com/zhongzhi107/universal-react-starter-kit/commit/56ad7ce))
* Skip `npm run dll` on APPVYR-WIN ([1190d82](https://github.com/zhongzhi107/universal-react-starter-kit/commit/1190d82))
* syntax error ([b44ae49](https://github.com/zhongzhi107/universal-react-starter-kit/commit/b44ae49))

### Features

* **build:** Add CDN_root environment variables for front-end and back-end resource deployment ([297b6c5](https://github.com/zhongzhi107/universal-react-starter-kit/commit/297b6c5))
* Loads environment variables from .env for nodejs projects ([3abde65](https://github.com/zhongzhi107/universal-react-starter-kit/commit/3abde65))
* Set proxy rules in config files ([0851a16](https://github.com/zhongzhi107/universal-react-starter-kit/commit/0851a16))

# [0.6.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.5.1...v0.6.0) (2017-02-22)

### Bug Fixes

* **build:** Fixed path error when copy static files to dist directory ([478fbfe](https://github.com/zhongzhi107/universal-react-starter-kit/commit/478fbfe))

### Features

* **eslint:** Enable require-jsdoc option to make sure that the comments conform to the JSDoc specification ([d73854a](https://github.com/zhongzhi107/universal-react-starter-kit/commit/d73854a))

### Performance Improvements

* **build:** Using DllPlugin to improve compiler performance ([ba0b4f8](https://github.com/zhongzhi107/universal-react-starter-kit/commit/ba0b4f8))

## [0.5.1](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.5.0...v0.5.1) (2017-02-22)

# [0.5.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.4.1...v0.5.0) (2017-02-21)

### Bug Fixes

* **config:** Enable CSS Modules when webpack build ([9cda8ad](https://github.com/zhongzhi107/universal-react-starter-kit/commit/9cda8ad))

### Features

* **logs:** Morgan the HTTP request logger for server side debugging ([9d64a75](https://github.com/zhongzhi107/universal-react-starter-kit/commit/9d64a75))

## [0.4.1](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.4.0...v0.4.1) (2017-02-20)

# [0.4.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.3.0...v0.4.0) (2017-02-16)

### Features

* Add manifest.json from PWA ([d202a5c](https://github.com/zhongzhi107/universal-react-starter-kit/commit/d202a5c))
* Add some meta elements for PWA ([e029810](https://github.com/zhongzhi107/universal-react-starter-kit/commit/e029810))

# [0.3.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.2.0...v0.3.0) (2017-02-09)

### Features

* StyleLint to maintain a consistent css/less code style ([d3acb35](https://github.com/zhongzhi107/universal-react-starter-kit/commit/d3acb35))
* Use koa-favicon for serving a favicon ([93f2f57](https://github.com/zhongzhi107/universal-react-starter-kit/commit/93f2f57))

### Performance Improvements

* Added koa-json to make response more concise ([77a2ae9](https://github.com/zhongzhi107/universal-react-starter-kit/commit/77a2ae9))

# [0.2.0](https://github.com/zhongzhi107/universal-react-starter-kit/compare/v0.1.2...v0.2.0) (2017-02-07)

### Features

* Replace express with koa2 ([d8707a0](https://github.com/zhongzhi107/universal-react-starter-kit/commit/d8707a0))
* Replace express with koa2 ([0d4c73d](https://github.com/zhongzhi107/universal-react-starter-kit/commit/0d4c73d))

## [0.1.2](https://github.com/zhongzhi107/react-universal-starter-kit/compare/v0.1.1...v0.1.2) (2017-02-06)

## [0.1.1](https://github.com/zhongzhi107/react-universal-starter-kit/compare/v0.1.0...v0.1.1) (2017-02-06)

# [0.1.0](https://github.com/zhongzhi107/react-universal-starter-kit/compare/v0.0.2...v0.1.0) (2017-02-06)

### Bug Fixes

* Each child in an array or iterator should have a unique "key" prop ([95e0d29](https://github.com/zhongzhi107/react-universal-starter-kit/commit/95e0d29))
* titleTemplate ([9bc24df](https://github.com/zhongzhi107/react-universal-starter-kit/commit/9bc24df))

### Features

* Add urlStrictEqual parameter to set url match type ([d5b9787](https://github.com/zhongzhi107/react-universal-starter-kit/commit/d5b9787))
* auto open Chrome window when service start ([ab8afa1](https://github.com/zhongzhi107/react-universal-starter-kit/commit/ab8afa1))
* Config files support ES6 syntax ([edf7685](https://github.com/zhongzhi107/react-universal-starter-kit/commit/edf7685))
* Optimize image with image-webpack-loader ([16decde](https://github.com/zhongzhi107/react-universal-starter-kit/commit/16decde))
* PWA support ([54edfe5](https://github.com/zhongzhi107/react-universal-starter-kit/commit/54edfe5))
* Replace Expressjs with Koajs in watch-client script ([04cb378](https://github.com/zhongzhi107/react-universal-starter-kit/commit/04cb378))
* Split vendor's libraries from client bundle ([905d6c1](https://github.com/zhongzhi107/react-universal-starter-kit/commit/905d6c1))

### Performance Improvements

* Update import order ([7d2bb01](https://github.com/zhongzhi107/react-universal-starter-kit/commit/7d2bb01))


text:
---
title: Center
category: Layout
source: https://github.com/crinklesio/feo-css/blob/main/src/layout/_center.scss
---

The `.center` class allows you to center elements on the screen. It is responsive by nature, as it allows you to set a max-width and side-paddings through utilities. It sets itself apart by allowing specific elements to break from the set max-width and (for instance) take the entire width of the page (e.g. hero images).

![](/img/center.png)

## Utility classes

The available utility classes to alter the settings for `.center` are listed below.

- `.center-w-<name>`: set the max-width of the layout, including any potential side-padding. Based on `$feo-breakpoints`.
- `.center-g-<name>`: set the padding on each of the sides. The padding is applied to all direct children of the parent. Based on `$feo-sizes`.
- `.center-exception`: allows children to flow outside the max-width set in the parent.

> If the utility classes are not flexible enough and you want to adjust the way the layout pattern behaves, adjust the `--center-spacing`, and/or `--center-width` custom properties on the element you are applying this pattern to.

repository: alolalo/feo-css

repo_name: alolalo/feo-css


text:
# Image classification via fine-tuning with EfficientNet

**Author:** [Yixing Fu](https://github.com/yixingfu)

**Date created:** 2020/06/30

**Last modified:** 2020/07/16

**Description:** Use EfficientNet with weights pre-trained on imagenet for Stanford Dogs classification.

 [**View in Colab**](https://colab.research.google.com/github/keras-team/keras-io/blob/master/examples/vision/ipynb/image_classification_efficientnet_fine_tuning.ipynb)  • [**GitHub source**](https://github.com/keras-team/keras-io/blob/master/examples/vision/image_classification_efficientnet_fine_tuning.py)

---
## Introduction: what is EfficientNet

EfficientNet, first introduced in [Tan and Le, 2019](https://arxiv.org/abs/1905.11946)
is among the most efficient models (i.e. requiring least FLOPS for inference)
that reaches State-of-the-Art accuracy on both
imagenet and common image classification transfer learning tasks.

The smallest base model is similar to [MnasNet](https://arxiv.org/abs/1807.11626), which
reached near-SOTA with a significantly smaller model. By introducing a heuristic way to
scale the model, EfficientNet provides a family of models (B0 to B7) that represents a
good combination of efficiency and accuracy on a variety of scales. Such a scaling
heuristics (compound-scaling, details see
[Tan and Le, 2019](https://arxiv.org/abs/1905.11946)) allows the
efficiency-oriented base model (B0) to surpass models at every scale, while avoiding
extensive grid-search of hyperparameters.

A summary of the latest updates on the model is available at
[here](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet), where various
augmentation schemes and semi-supervised learning approaches are applied to further
improve the imagenet performance of the models. These extensions of the model can be used
by updating weights without changing model architecture.

---
## B0 to B7 variants of EfficientNet

*(This section provides some details on "compound scaling", and can be skipped
if you're only interested in using the models)*

Based on the [original paper](https://arxiv.org/abs/1905.11946) people may have the
impression that EfficientNet is a continuous family of models created by arbitrarily
choosing scaling factor in as Eq.(3) of the paper.  However, choice of resolution,
depth and width are also restricted by many factors:

- Resolution: Resolutions not divisible by 8, 16, etc. cause zero-padding near boundaries
of some layers which wastes computational resources. This especially applies to smaller
variants of the model, hence the input resolution for B0 and B1 are chosen as 224 and
240.

- Depth and width: The building blocks of EfficientNet demands channel size to be
multiples of 8.

- Resource limit: Memory limitation may bottleneck resolution when depth
and width can still increase. In such a situation, increasing depth and/or
width but keep resolution can still improve performance.

As a result, the depth, width and resolution of each variant of the EfficientNet models
are hand-picked and proven to produce good results, though they may be significantly
off from the compound scaling formula.
Therefore, the keras implementation (detailed below) only provide these 8 models, B0 to B7,
instead of allowing arbitray choice of width / depth / resolution parameters.

---
## Keras implementation of EfficientNet

An implementation of EfficientNet B0 to B7 has been shipped with tf.keras since TF2.3. To
use EfficientNetB0 for classifying 1000 classes of images from imagenet, run:

```python
from tensorflow.keras.applications import EfficientNetB0
model = EfficientNetB0(weights='imagenet')
```

This model takes input images of shape (224, 224, 3), and the input data should range
[0, 255]. Normalization is included as part of the model.

Because training EfficientNet on ImageNet takes a tremendous amount of resources and
several techniques that are not a part of the model architecture itself. Hence the Keras
implementation by default loads pre-trained weights obtained via training with
[AutoAugment](https://arxiv.org/abs/1805.09501).

For B0 to B7 base models, the input shapes are different. Here is a list of input shape
expected for each model:

| Base model | resolution|
|----------------|-----|
| EfficientNetB0 | 224 |
| EfficientNetB1 | 240 |
| EfficientNetB2 | 260 |
| EfficientNetB3 | 300 |
| EfficientNetB4 | 380 |
| EfficientNetB5 | 456 |
| EfficientNetB6 | 528 |
| EfficientNetB7 | 600 |

When the model is intended for transfer learning, the Keras implementation
provides a option to remove the top layers:
```
model = EfficientNetB0(include_top=False, weights='imagenet')
```
This option excludes the final `Dense` layer that turns 1280 features on the penultimate
layer into prediction of the 1000 ImageNet classes. Replacing the top layer with custom
layers allows using EfficientNet as a feature extractor in a transfer learning workflow.

Another argument in the model constructor worth noticing is `drop_connect_rate` which controls
the dropout rate responsible for [stochastic depth](https://arxiv.org/abs/1603.09382).
This parameter serves as a toggle for extra regularization in finetuning, but does not
affect loaded weights. For example, when stronger regularization is desired, try:

```python
model = EfficientNetB0(weights='imagenet', drop_connect_rate=0.4)
```
The default value is 0.2.

---
## Example: EfficientNetB0 for Stanford Dogs.

EfficientNet is capable of a wide range of image classification tasks.
This makes it a good model for transfer learning.
As an end-to-end example, we will show using pre-trained EfficientNetB0 on
[Stanford Dogs](http://vision.stanford.edu/aditya86/ImageNetDogs/main.html) dataset.

```python
# IMG_SIZE is determined by EfficientNet model choice
IMG_SIZE = 224
```

---
## Setup and data loading

This example requires TensorFlow 2.3 or above.

To use TPU, the TPU runtime must match current running TensorFlow
version. If there is a mismatch, try:

```python
from cloud_tpu_client import Client
c = Client()
c.configure_tpu_version(tf.__version__, restart_type="always")
```

```python
import tensorflow as tf

try:
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()  # TPU detection
    print("Running on TPU ", tpu.cluster_spec().as_dict()["worker"])
    tf.config.experimental_connect_to_cluster(tpu)
    tf.tpu.experimental.initialize_tpu_system(tpu)
    strategy = tf.distribute.experimental.TPUStrategy(tpu)
except ValueError:
    print("Not connected to a TPU runtime. Using CPU/GPU strategy")
    strategy = tf.distribute.MirroredStrategy()

```

```
Not connected to a TPU runtime. Using CPU/GPU strategy
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

```

### Loading data

Here we load data from [tensorflow_datasets](https://www.tensorflow.org/datasets)
(hereafter TFDS).
Stanford Dogs dataset is provided in
TFDS as [stanford_dogs](https://www.tensorflow.org/datasets/catalog/stanford_dogs).
It features 20,580 images that belong to 120 classes of dog breeds
(12,000 for training and 8,580 for testing).

By simply changing `dataset_name` below, you may also try this notebook for
other datasets in TFDS such as
[cifar10](https://www.tensorflow.org/datasets/catalog/cifar10),
[cifar100](https://www.tensorflow.org/datasets/catalog/cifar100),
[food101](https://www.tensorflow.org/datasets/catalog/food101),
etc. When the images are much smaller than the size of EfficientNet input,
we can simply upsample the input images. It has been shown in
[Tan and Le, 2019](https://arxiv.org/abs/1905.11946) that transfer learning
result is better for increased resolution even if input images remain small.

For TPU: if using TFDS datasets,
a [GCS bucket](https://cloud.google.com/storage/docs/key-terms#buckets)
location is required to save the datasets. For example:

```python
tfds.load(dataset_name, data_dir="gs://example-bucket/datapath")
```

Also, both the current environment and the TPU service account have
proper [access](https://cloud.google.com/tpu/docs/storage-buckets#authorize_the_service_account)
to the bucket. Alternatively, for small datasets you may try loading data
into the memory and use `tf.data.Dataset.from_tensor_slices()`.

```python
import tensorflow_datasets as tfds

batch_size = 64

dataset_name = "stanford_dogs"
(ds_train, ds_test), ds_info = tfds.load(
    dataset_name, split=["train", "test"], with_info=True, as_supervised=True
)
NUM_CLASSES = ds_info.features["label"].num_classes

```

When the dataset include images with various size, we need to resize them into a
shared size. The Stanford Dogs dataset includes only images at least 200x200
pixels in size. Here we resize the images to the input size needed for EfficientNet.

```python
size = (IMG_SIZE, IMG_SIZE)
ds_train = ds_train.map(lambda image, label: (tf.image.resize(image, size), label))
ds_test = ds_test.map(lambda image, label: (tf.image.resize(image, size), label))
```

### Visualizing the data

The following code shows the first 9 images with their labels.

```python
import matplotlib.pyplot as plt

def format_label(label):
    string_label = label_info.int2str(label)
    return string_label.split("-")[1]

label_info = ds_info.features["label"]
for i, (image, label) in enumerate(ds_train.take(9)):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(image.numpy().astype("uint8"))
    plt.title("{}".format(format_label(label)))
    plt.axis("off")

```

![png](/img/examples/vision/image_classification_efficientnet_fine_tuning/image_classification_efficientnet_fine_tuning_10_0.png)

### Data augmentation

We can use preprocessing layers APIs for image augmentation.

```python
from tensorflow.keras.layers.experimental import preprocessing
from tensorflow.keras.models import Sequential
from tensorflow.keras import layers

img_augmentation = Sequential(
    [
        preprocessing.RandomRotation(factor=0.15),
        preprocessing.RandomTranslation(height_factor=0.1, width_factor=0.1),
        preprocessing.RandomFlip(),
        preprocessing.RandomContrast(factor=0.1),
    ],
    name="img_augmentation",
)
```

This `Sequential` model object can be used both as a part of
the model we later build, and as a function to preprocess
data before feeding into the model. Using them as function makes
it easy to visualize the augmented images. Here we plot 9 examples
of augmentation result of a given figure.

```python
for image, label in ds_train.take(1):
    for i in range(9):
        ax = plt.subplot(3, 3, i + 1)
        aug_img = img_augmentation(tf.expand_dims(image, axis=0))
        plt.imshow(aug_img[0].numpy().astype("uint8"))
        plt.title("{}".format(format_label(label)))
        plt.axis("off")

```

![png](/img/examples/vision/image_classification_efficientnet_fine_tuning/image_classification_efficientnet_fine_tuning_14_0.png)

### Prepare inputs

Once we verify the input data and augmentation are working correctly,
we prepare dataset for training. The input data are resized to uniform
`IMG_SIZE`. The labels are put into one-hot
(a.k.a. categorical) encoding. The dataset is batched.

Note: `prefetch` and `AUTOTUNE` may in some situation improve
performance, but depends on environment and the specific dataset used.
See this [guide](https://www.tensorflow.org/guide/data_performance)
for more information on data pipeline performance.

```python
# One-hot / categorical encoding
def input_preprocess(image, label):
    label = tf.one_hot(label, NUM_CLASSES)
    return image, label

ds_train = ds_train.map(
    input_preprocess, num_parallel_calls=tf.data.experimental.AUTOTUNE
)
ds_train = ds_train.batch(batch_size=batch_size, drop_remainder=True)
ds_train = ds_train.prefetch(tf.data.experimental.AUTOTUNE)

ds_test = ds_test.map(input_preprocess)
ds_test = ds_test.batch(batch_size=batch_size, drop_remainder=True)

```

---
## Training a model from scratch

We build an EfficientNetB0 with 120 output classes, that is initialized from scratch:

Note: the accuracy will increase very slowly and may overfit.

```python
from tensorflow.keras.applications import EfficientNetB0

with strategy.scope():
    inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3))
    x = img_augmentation(inputs)
    outputs = EfficientNetB0(include_top=True, weights=None, classes=NUM_CLASSES)(x)

    model = tf.keras.Model(inputs, outputs)
    model.compile(
        optimizer="adam", loss="categorical_crossentropy", metrics=["accuracy"]
    )

model.summary()

epochs = 40  # @param {type: "slider", min:10, max:100}
hist = model.fit(ds_train, epochs=epochs, validation_data=ds_test, verbose=2)

```

```
Model: "functional_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
input_1 (InputLayer)         [(None, 224, 224, 3)]     0
_________________________________________________________________
img_augmentation (Sequential (None, 224, 224, 3)       0
_________________________________________________________________
efficientnetb0 (Functional)  (None,<PHONE_NUMBER>
=================================================================
Total params: 4,203,291
Trainable params: 4,161,268
Non-trainable params: 42,023
_________________________________________________________________
Epoch 1/40
187/187 - 66s - loss: 4.9221 - accuracy: 0.0119 - val_loss: 4.9835 - val_accuracy: 0.0104
Epoch 2/40
187/187 - 63s - loss: 4.5652 - accuracy: 0.0243 - val_loss: 5.1626 - val_accuracy: 0.0145
Epoch 3/40
187/187 - 63s - loss: 4.4179 - accuracy: 0.0337 - val_loss: 4.7597 - val_accuracy: 0.0237
Epoch 4/40
187/187 - 63s - loss: 4.2964 - accuracy: 0.0421 - val_loss: 4.4028 - val_accuracy: 0.0378
Epoch 5/40
187/187 - 63s - loss: 4.1951 - accuracy: 0.0540 - val_loss: 4.3048 - val_accuracy: 0.0443
Epoch 6/40
187/187 - 63s - loss: 4.1025 - accuracy: 0.0596 - val_loss: 4.1918 - val_accuracy: 0.0526
Epoch 7/40
187/187 - 63s - loss: 4.0157 - accuracy: 0.0728 - val_loss: 4.1482 - val_accuracy: 0.0591
Epoch 8/40
187/187 - 62s - loss: 3.9344 - accuracy: 0.0844 - val_loss: 4.1088 - val_accuracy: 0.0638
Epoch 9/40
187/187 - 63s - loss: 3.8529 - accuracy: 0.0951 - val_loss: 4.0692 - val_accuracy: 0.0770
Epoch 10/40
187/187 - 63s - loss: 3.7650 - accuracy: 0.1040 - val_loss: 4.1468 - val_accuracy: 0.0719
Epoch 11/40
187/187 - 63s - loss: 3.6858 - accuracy: 0.1185 - val_loss: 4.0484 - val_accuracy: 0.0913
Epoch 12/40
187/187 - 63s - loss: 3.5942 - accuracy: 0.1326 - val_loss: 3.8047 - val_accuracy: 0.1072
Epoch 13/40
187/187 - 63s - loss: 3.5028 - accuracy: 0.1447 - val_loss: 3.9513 - val_accuracy: 0.0933
Epoch 14/40
187/187 - 63s - loss: 3.4295 - accuracy: 0.1604 - val_loss: 3.7738 - val_accuracy: 0.1220
Epoch 15/40
187/187 - 63s - loss: 3.3410 - accuracy: 0.1735 - val_loss: 3.9104 - val_accuracy: 0.1104
Epoch 16/40
187/187 - 63s - loss: 3.2511 - accuracy: 0.1890 - val_loss: 3.6904 - val_accuracy: 0.1264
Epoch 17/40
187/187 - 63s - loss: 3.1624 - accuracy: 0.2076 - val_loss: 3.4026 - val_accuracy: 0.1769
Epoch 18/40
187/187 - 63s - loss: 3.0825 - accuracy: 0.2229 - val_loss: 3.4627 - val_accuracy: 0.1744
Epoch 19/40
187/187 - 63s - loss: 3.0041 - accuracy: 0.2355 - val_loss: 3.6061 - val_accuracy: 0.1542
Epoch 20/40
187/187 - 64s - loss: 2.8945 - accuracy: 0.2552 - val_loss: 3.2769 - val_accuracy: 0.2036
Epoch 21/40
187/187 - 63s - loss: 2.8054 - accuracy: 0.2710 - val_loss: 3.5355 - val_accuracy: 0.1834
Epoch 22/40
187/187 - 63s - loss: 2.7342 - accuracy: 0.2904 - val_loss: 3.3540 - val_accuracy: 0.1973
Epoch 23/40
187/187 - 62s - loss: 2.6258 - accuracy: 0.3042 - val_loss: 3.2608 - val_accuracy: 0.2217
Epoch 24/40
187/187 - 62s - loss: 2.5453 - accuracy: 0.3218 - val_loss: 3.4611 - val_accuracy: 0.1941
Epoch 25/40
187/187 - 63s - loss: 2.4585 - accuracy: 0.3356 - val_loss: 3.4163 - val_accuracy: 0.2070
Epoch 26/40
187/187 - 62s - loss: 2.3606 - accuracy: 0.3647 - val_loss: 3.2558 - val_accuracy: 0.2392
Epoch 27/40
187/187 - 63s - loss: 2.2819 - accuracy: 0.3801 - val_loss: 3.3676 - val_accuracy: 0.2222
Epoch 28/40
187/187 - 62s - loss: 2.2114 - accuracy: 0.3933 - val_loss: 3.6578 - val_accuracy: 0.2022
Epoch 29/40
187/187 - 62s - loss: 2.0964 - accuracy: 0.4215 - val_loss: 3.5366 - val_accuracy: 0.2186
Epoch 30/40
187/187 - 63s - loss: 1.9931 - accuracy: 0.4459 - val_loss: 3.5612 - val_accuracy: 0.2310
Epoch 31/40
187/187 - 63s - loss: 1.8924 - accuracy: 0.4657 - val_loss: 3.4780 - val_accuracy: 0.2359
Epoch 32/40
187/187 - 63s - loss: 1.8095 - accuracy: 0.4874 - val_loss: 3.5776 - val_accuracy: 0.2403
Epoch 33/40
187/187 - 63s - loss: 1.7126 - accuracy: 0.5086 - val_loss: 3.6865 - val_accuracy: 0.2316
Epoch 34/40
187/187 - 63s - loss: 1.6117 - accuracy: 0.5373 - val_loss: 3.6419 - val_accuracy: 0.2513
Epoch 35/40
187/187 - 63s - loss: 1.5532 - accuracy: 0.5514 - val_loss: 3.8050 - val_accuracy: 0.2415
Epoch 36/40
187/187 - 63s - loss: 1.4479 - accuracy: 0.5809 - val_loss: 4.0113 - val_accuracy: 0.2299
Epoch 37/40
187/187 - 62s - loss: 1.3885 - accuracy: 0.5939 - val_loss: 4.1262 - val_accuracy: 0.2158
Epoch 38/40
187/187 - 63s - loss: 1.2979 - accuracy: 0.6217 - val_loss: 4.2519 - val_accuracy: 0.2344
Epoch 39/40
187/187 - 62s - loss: 1.2066 - accuracy: 0.6413 - val_loss: 4.3924 - val_accuracy: 0.2169
Epoch 40/40
187/187 - 62s - loss: 1.1348 - accuracy: 0.6618 - val_loss: 4.2216 - val_accuracy: 0.2374

```

Training the model is relatively fast (takes only 20 seconds per epoch on TPUv2 that is
available on Colab). This might make it sounds easy to simply train EfficientNet on any
dataset wanted from scratch. However, training EfficientNet on smaller datasets,
especially those with lower resolution like CIFAR-100, faces the significant challenge of
overfitting.

Hence training from scratch requires very careful choice of hyperparameters and is
difficult to find suitable regularization. It would also be much more demanding in resources.
Plotting the training and validation accuracy
makes it clear that validation accuracy stagnates at a low value.

```python
import matplotlib.pyplot as plt

def plot_hist(hist):
    plt.plot(hist.history["accuracy"])
    plt.plot(hist.history["val_accuracy"])
    plt.title("model accuracy")
    plt.ylabel("accuracy")
    plt.xlabel("epoch")
    plt.legend(["train", "validation"], loc="upper left")
    plt.show()

plot_hist(hist)
```

![png](/img/examples/vision/image_classification_efficientnet_fine_tuning/image_classification_efficientnet_fine_tuning_20_0.png)

---
## Transfer learning from pre-trained weights

Here we initialize the model with pre-trained ImageNet weights,
and we fine-tune it on our own dataset.

```python
from tensorflow.keras.layers.experimental import preprocessing

def build_model(num_classes):
    inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3))
    x = img_augmentation(inputs)
    model = EfficientNetB0(include_top=False, input_tensor=x, weights="imagenet")

    # Freeze the pretrained weights
    model.trainable = False

    # Rebuild top
    x = layers.GlobalAveragePooling2D(name="avg_pool")(model.output)
    x = layers.BatchNormalization()(x)

    top_dropout_rate = 0.2
    x = layers.Dropout(top_dropout_rate, name="top_dropout")(x)
    outputs = layers.Dense(NUM_CLASSES, activation="softmax", name="pred")(x)

    # Compile
    model = tf.keras.Model(inputs, outputs, name="EfficientNet")
    optimizer = tf.keras.optimizers.Adam(learning_rate=1e-2)
    model.compile(
        optimizer=optimizer, loss="categorical_crossentropy", metrics=["accuracy"]
    )
    return model

```

The first step to transfer learning is to freeze all layers and train only the top
layers. For this step, a relatively large learning rate (1e-2) can be used.
Note that validation accuracy and loss will usually be better than training
accuracy and loss. This is because the regularization is strong, which only
suppresses training-time metrics.

Note that the convergence may take up to 50 epochs depending on choice of learning rate.
If image augmentation layers were not
applied, the validation accuracy may only reach ~60%.

```python
with strategy.scope():
    model = build_model(num_classes=NUM_CLASSES)

epochs = 25  # @param {type: "slider", min:8, max:80}
hist = model.fit(ds_train, epochs=epochs, validation_data=ds_test, verbose=2)
plot_hist(hist)
```

```
Epoch 1/25
187/187 - 33s - loss: 3.5673 - accuracy: 0.3624 - val_loss: 1.0288 - val_accuracy: 0.6957
Epoch 2/25
187/187 - 31s - loss: 1.8503 - accuracy: 0.5232 - val_loss: 0.8439 - val_accuracy: 0.7484
Epoch 3/25
187/187 - 31s - loss: 1.5511 - accuracy: 0.5772 - val_loss: 0.7953 - val_accuracy: 0.7563
Epoch 4/25
187/187 - 31s - loss: 1.4660 - accuracy: 0.5878 - val_loss: 0.8061 - val_accuracy: 0.7535
Epoch 5/25
187/187 - 31s - loss: 1.4143 - accuracy: 0.6034 - val_loss: 0.7850 - val_accuracy: 0.7569
Epoch 6/25
187/187 - 31s - loss: 1.4000 - accuracy: 0.6054 - val_loss: 0.7846 - val_accuracy: 0.7646
Epoch 7/25
187/187 - 31s - loss: 1.3678 - accuracy: 0.6173 - val_loss: 0.7850 - val_accuracy: 0.7682
Epoch 8/25
187/187 - 31s - loss: 1.3286 - accuracy: 0.6222 - val_loss: 0.8142 - val_accuracy: 0.7608
Epoch 9/25
187/187 - 31s - loss: 1.3210 - accuracy: 0.6245 - val_loss: 0.7890 - val_accuracy: 0.7669
Epoch 10/25
187/187 - 31s - loss: 1.3086 - accuracy: 0.6278 - val_loss: 0.8368 - val_accuracy: 0.7575
Epoch 11/25
187/187 - 31s - loss: 1.2877 - accuracy: 0.6315 - val_loss: 0.8309 - val_accuracy: 0.7599
Epoch 12/25
187/187 - 31s - loss: 1.2918 - accuracy: 0.6308 - val_loss: 0.8319 - val_accuracy: 0.7535
Epoch 13/25
187/187 - 31s - loss: 1.2738 - accuracy: 0.6373 - val_loss: 0.8567 - val_accuracy: 0.7576
Epoch 14/25
187/187 - 31s - loss: 1.2837 - accuracy: 0.6410 - val_loss: 0.8004 - val_accuracy: 0.7697
Epoch 15/25
187/187 - 31s - loss: 1.2828 - accuracy: 0.6403 - val_loss: 0.8364 - val_accuracy: 0.7625
Epoch 16/25
187/187 - 31s - loss: 1.2749 - accuracy: 0.6405 - val_loss: 0.8558 - val_accuracy: 0.7565
Epoch 17/25
187/187 - 31s - loss: 1.3022 - accuracy: 0.6352 - val_loss: 0.8361 - val_accuracy: 0.7551
Epoch 18/25
187/187 - 31s - loss: 1.2848 - accuracy: 0.6394 - val_loss: 0.8958 - val_accuracy: 0.7479
Epoch 19/25
187/187 - 31s - loss: 1.2791 - accuracy: 0.6420 - val_loss: 0.8875 - val_accuracy: 0.7509
Epoch 20/25
187/187 - 30s - loss: 1.2834 - accuracy: 0.6416 - val_loss: 0.8653 - val_accuracy: 0.7607
Epoch 21/25
187/187 - 30s - loss: 1.2608 - accuracy: 0.6435 - val_loss: 0.8451 - val_accuracy: 0.7612
Epoch 22/25
187/187 - 30s - loss: 1.2780 - accuracy: 0.6390 - val_loss: 0.9035 - val_accuracy: 0.7486
Epoch 23/25
187/187 - 30s - loss: 1.2742 - accuracy: 0.6473 - val_loss: 0.8837 - val_accuracy: 0.7556
Epoch 24/25
187/187 - 30s - loss: 1.2609 - accuracy: 0.6434 - val_loss: 0.9233 - val_accuracy: 0.7524
Epoch 25/25
187/187 - 31s - loss: 1.2630 - accuracy: 0.6496 - val_loss: 0.9116 - val_accuracy: 0.7584

```

![png](/img/examples/vision/image_classification_efficientnet_fine_tuning/image_classification_efficientnet_fine_tuning_24_1.png)

The second step is to unfreeze a number of layers and fit the model using smaller
learning rate. In this example we show unfreezing all layers, but depending on
specific dataset it may be desireble to only unfreeze a fraction of all layers.

When the feature extraction with
pretrained model works good enough, this step would give a very limited gain on
validation accuracy. In our case we only see a small improvement,
as ImageNet pretraining already exposed the model to a good amount of dogs.

On the other hand, when we use pretrained weights on a dataset that is more different
from ImageNet, this fine-tuning step can be crucial as the feature extractor also
needs to be adjusted by a considerable amount. Such a situation can be demonstrated
if choosing CIFAR-100 dataset instead, where fine-tuning boosts validation accuracy
by about 10% to pass 80% on `EfficientNetB0`.
In such a case the convergence may take more than 50 epochs.

A side note on freezing/unfreezing models: setting `trainable` of a `Model` will
simultaneously set all layers belonging to the `Model` to the same `trainable`
attribute. Each layer is trainable only if both the layer itself and the model
containing it are trainable. Hence when we need to partially freeze/unfreeze
a model, we need to make sure the `trainable` attribute of the model is set
to `True`.

```python

def unfreeze_model(model):
    # We unfreeze the top 20 layers while leaving BatchNorm layers frozen
    for layer in model.layers[-20:]:
        if not isinstance(layer, layers.BatchNormalization):
            layer.trainable = True

    optimizer = tf.keras.optimizers.Adam(learning_rate=1e-4)
    model.compile(
        optimizer=optimizer, loss="categorical_crossentropy", metrics=["accuracy"]
    )

unfreeze_model(model)

epochs = 10  # @param {type: "slider", min:8, max:50}
hist = model.fit(ds_train, epochs=epochs, validation_data=ds_test, verbose=2)
plot_hist(hist)
```

```
Epoch 1/10
187/187 - 33s - loss: 0.9956 - accuracy: 0.7080 - val_loss: 0.7644 - val_accuracy: 0.7856
Epoch 2/10
187/187 - 31s - loss: 0.8885 - accuracy: 0.7352 - val_loss: 0.7696 - val_accuracy: 0.7866
Epoch 3/10
187/187 - 31s - loss: 0.8059 - accuracy: 0.7533 - val_loss: 0.7659 - val_accuracy: 0.7885
Epoch 4/10
187/187 - 32s - loss: 0.7648 - accuracy: 0.7675 - val_loss: 0.7730 - val_accuracy: 0.7866
Epoch 5/10
187/187 - 32s - loss: 0.6982 - accuracy: 0.7833 - val_loss: 0.7691 - val_accuracy: 0.7858
Epoch 6/10
187/187 - 31s - loss: 0.6823 - accuracy: 0.7880 - val_loss: 0.7814 - val_accuracy: 0.7872
Epoch 7/10
187/187 - 31s - loss: 0.6536 - accuracy: 0.7953 - val_loss: 0.7850 - val_accuracy: 0.7873
Epoch 8/10
187/187 - 31s - loss: 0.6104 - accuracy: 0.8111 - val_loss: 0.7774 - val_accuracy: 0.7879
Epoch 9/10
187/187 - 32s - loss: 0.5990 - accuracy: 0.8067 - val_loss: 0.7925 - val_accuracy: 0.7870
Epoch 10/10
187/187 - 31s - loss: 0.5531 - accuracy: 0.8239 - val_loss: 0.7870 - val_accuracy: 0.7836

```

![png](/img/examples/vision/image_classification_efficientnet_fine_tuning/image_classification_efficientnet_fine_tuning_26_1.png)

### Tips for fine tuning EfficientNet

On unfreezing layers:

- The `BathcNormalization` layers need to be kept frozen
([more details](https://keras.io/guides/transfer_learning/)).
If they are also turned to trainable, the
first epoch after unfreezing will significantly reduce accuracy.
- In some cases it may be beneficial to open up only a portion of layers instead of
unfreezing all. This will make fine tuning much faster when going to larger models like
B7.
 This is because the architecture includes
a shortcut from the first layer to the last layer for each block. Not respecting blocks
also significantly harms the final performance.

Some other tips for utilizing EfficientNet:

- Larger variants of EfficientNet do not guarantee improved performance, especially for
tasks with less data or fewer classes. In such a case, the larger variant of EfficientNet
chosen, the harder it is to tune hyperparameters.
- EMA (Exponential Moving Average) is very helpful in training EfficientNet from scratch,
but not so much for transfer learning.
- Do not use the RMSprop setup as in the original paper for transfer learning. The
momentum and learning rate are too high for transfer learning. It will easily corrupt the
pretrained weight and blow up the loss. A quick check is to see if loss (as categorical
cross entropy) is getting significantly larger than log(NUM_CLASSES) after the same
epoch. If so, the initial learning rate/momentum is too high.
- Smaller batch size benefit validation accuracy, possibly due to effectively providing
regularization.

---
## Using the latest EfficientNet weights

Since the initial paper, the EfficientNet has been improved by various methods for data
preprocessing and for using unlabelled data to enhance learning results. These
improvements are relatively hard and computationally costly to reproduce, and require
extra code; but the weights are readily available in the form of TF checkpoint files. The
model architecture has not changed, so loading the improved checkpoints is possible.

To use a checkpoint provided at
[the official model repository](https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet), first
download the checkpoint. As example, here we download noisy-student version of B1:

```
!wget https://storage.googleapis.com/cloud-tpu-checkpoints/efficientnet\
       /noisystudent/noisy_student_efficientnet-b1.tar.gz
!tar -xf noisy_student_efficientnet-b1.tar.gz
```

Then use the script efficientnet_weight_update_util.py to convert ckpt file to h5 file.

```
!python efficientnet_weight_update_util.py --model b1 --notop --ckpt \
        efficientnet-b1/model.ckpt --o efficientnetb1_notop.h5
```

When creating model, use the following to load new weight:

```python
model = EfficientNetB0(weights="efficientnetb1_notop.h5", include_top=False)
```


text:
---
layout: default
---

# 1996-10-18 - Re: YES OR NO?

## Header Data

From<EMAIL_ADDRESS>(Anonymous)

To<EMAIL_ADDRESS>Message Hash: 5b3281d53375e7d7d23f161ed428c46467e857d805f093b78fbf1e2a8bb5f6e8

Message ID<EMAIL_ADDRESS>Reply To: _N/A_

UTC Datetime: 1996-10-18 13:39:29 UTC

Raw Date: Fri, 18 Oct 1996 06:39:29 -0700 (PDT)

## Raw message

```
{% raw  %}From<EMAIL_ADDRESS>(Anonymous)
Date: Fri, 18 Oct 1996 06:39:29 -0700 (PDT)
To<EMAIL_ADDRESS>Subject: Re: YES OR NO?

Unless the "YES" was in private email to Sandy, he lies (again)
about ever having given any form of a straight answer.

>> Great.  So let's pick a date sufficiently in the future that you
>> can make a firm commitment.  For starters, our three winter
>> meetings are tentatively scheduled for December 14, January 11
>> and February 8.  Any of those sound good to you?
>
>Don't know yet.

Prediction/translation: "never"

Sandy, I am not even sure that this is such a good idea...
rewarding the annoying with a free, wintertime trip to CA
with free lodging seems to be a way of encouraging more of
the annoying... The last thing we need. Respected c-punks
are dropping like flies as it is. Perhaps you'll prove me
wrong and shut him up, if he proves me wrong by attending,
that is.

{% endraw %}
```

## Thread

+ Return to [October 1996](/archive/1996/10)

+ Return to<EMAIL_ADDRESS>(Anonymous)](/authors/nobody_at_zifi_genetics_utah_edu_anonymous_)"

+ 1996-10-18 (Fri, 18 Oct 1996 06:39:29 -0700 (PDT)) - Re: YES OR NO? -<EMAIL_ADDRESS>(Anonymous)_


text:
# ProjectTeam04-B
# SOLVING CODEFORCES PROBLEM 603A
This repository will solve Codeforces problem 603 B using Greedy approach and Dynamic Programming.
After that We will also compare which approach is better.

## TEAM MEMBER
1. [Andrew](https://github.com/ndrewwjy)

2. [Dave Joshua Marcellino Rumengan](https://github.com/djoshua449)

3. [David Immanuel Kase](https://github.com/dkase99)

4. [Nicholas](https://github.com/santosonicholas)

## REQUIREMENT
- [C++11](https://osdn.net/projects/mingw/releases/)

## HOW TO INSTALL C++11
[WATCH THIS](https://www.youtube.com/watch?v=1OsGXuNA5cc)

## PROBLEM LINK

[603A - Alternative Thinking](http://codeforces.com/problemset/problem/603/A)

## SUBMISSION LINK

[Greedy](https://codeforces.com/contest/603/submission/46122536)

[Dynamic Programming](https://codeforces.com/contest/603/submission/46122328)

## SAMPLE I/O
#### SAMPLE#1
*INPUT :*
```
8
10000011
```
*OUTPUT :*
```
5
```

-------------------------------------------------------

#### SAMPLE#2
*INPUT :*
```
2
01
```
*OUTPUT :*
```
2
```

-------------------------------------------------------

#### SAMPLE#3
*INPUT :*
```
5
10101
```
*OUTPUT :*
```
5
```

-------------------------------------------------------

#### SAMPLE#4
*INPUT :*
```
75
010101010101010101010101010101010101010101010101010101010101010101010101010
```
*OUTPUT :*
```
75
```

## EXPLANATION

#### GREEDY APPROACH

The greedy approach's "code" of this problem is quite easy to be understood. We only need to count how many "01" or "10" in the string.
But, the biggest question is lie on the 15th line of the code.

```c++
  cout << min(res + 2, N) << '\n';
  ```

why? The most simple explanation is: "Our best move will only add the length of the longest subsequence at most by two"

Of course that explanation gives us another why, "why at most two?"

It won't add more than two if the initial subsequence is n-1 or n, because it can't be more than n.

But why two? Because we can only change one substring and from that one substring "the effective flippable number" at most is only two numbers, more than that won't effect the longest subsequence. Changing a substring of same numbers (000... or 111...) won't help us.

There are two possibilities:
  1. (1/0)...(a subsequence begins with 1/0 respectively), then whatever we change between ... will make the first number is useful, so we will get another two numbers (the first number, and the number we flip)
  2. (10/01)...(a subsequence begins with 01/10 respectively), then we will flip the first two numbers, so we will get another two numbers, (the first two numbers will be useful).

  Note: ... is not part of the subsequence

#### DYNAMIC PROGRAMMING APPROACH

With dynamic programming, we'll use three variables to get what's the best choice until that point. Those three variables have different use:
  1. The first variable is to know how long the subsequence at a certain point of the string
  2. The second variable is to know when we'll start to "flip" the string
  3. The third variable is to check would it be better if we reflip the string (undo). We can say that the third variable is to know when will we stop the "flipping"

  Here is the code:

```c++
for(int i=1;i<s.length();i++){
        dp[i][0] = dp[i-1][0] + (s[i]!=s[i-1]); //first variable
        dp[i][1] = max (dp[i-1][0] + (s[i]==s[i-1]) , dp[i-1][1] + (s[i]!=s[i-1])); //second variable
        dp[i][2] = max(dp[i-1][1] + (s[i]==s[i-1]) , dp[i-1][2] + (s[i]!=s[i-1])); //third variable
    }
```

On the first variable, as explained before is to check how long the subsequence at a certain point. If (s[i]!=s[i-1]) is true, and the value will be one, so it will add the number of the subsequence by one.

On the second variable, we have to choose which is higher between two things:
  1. The "Original" next element is same or not
  2. The "alternative 1" next element is different or not

Why? Because by logic, If it has the same element, we'll start the flip to make the subsequence better.

On the third variable, we have to choose which is higher between two things:
  1. The "Alternative 1" next element is same or not
  2. The "alternative 2" next element is different or not

Why? Because if the "flipped" string doesn't get higher, then it means that we have to stop the flip.

Example:

10

1010010001

First variable: 1 2 3 4 4 5 6 6 6 7

Second Variable: 1 2 3 4 **5** 6 7 7 7 8

Third Variable: 1 2 3 4 5 6 7 **8** 8 9

As we can see, the program start to flip on the 5th element, and stop the 8th element.
How do we know it? On the second variable, the answer is higher when we start to flip the string, and on the third variable is start to be higher than the second variable on the 8th element, which means it would be better if we don't (stop) flip the 8th element.

So the answer will be: **10101010**0**1**, which has the length of 9

## COMPARISON

We'll compare both methods base on three parameter:
  1. Complexity
  2. Simulated Time
  3. Memory

### 1. Complexity

Both best complexity is Ω(1) where the n is one
Both worst complexity is O(n)

Both methods have the same complexity because both only have a single loop (loop complexity = O(n))

### 2. Simulated Time
| n  | Greedy | DP |
| :---: | :---: | :---: |
| 1 | 0.0 | 0.0 |
| 10 | 0.0 | 0.0 |
| 100 | 0.0 | 0.0 |
| 1000 | 0.0 | 0.0 |
| 10000 | 0.001 | 0.0009 |
| 100000 | 0.0069 | 0.006 |
| 1000000 | 0.0579 | 0.06 |
| 1000000 | 0.69 | 0.6 |

As we can see, since both methods have the same time complexity, so both of simulated time is not to different.

![NtoTime](https://github.com/AAlab1819/ProjectTeam04-B/blob/master/chart.png)<br>

### 3. Memory

As we can see from the program, the dynamic programming uses more memory (3x of greedy) since it use a multi-dimension of array and greedy only use a one-dimensional array.

## CONCLUSION

Since both almost have the same time complexity (as we can see the simulated time) but the DP uses more memory, we conclude that **GREEDY** method perform better than DP in solving our test case.