text:
Get iTunes on iOS, Android, Mac and Windows
Ghost ships, lost cities, unsolved crimes and mysteries, ancient mythology, dissapeared explorers - if it's a historical mystery, it's going under the microscope. History has always been fascinating, but more fascinating than what we know is what we don't; in this podcast Ashleigh Stiles looks into famous and obscure episodes of folklore, unexplained circumstances, and unsolved mysteries from around the world and throughout time. Taking a modern lens to these ancient puzzles, she uses all the evidence and findings to try and piece together what really happened, or as close a picture as we can get, to both entertain the listener, and inspire interest in these lesser-known chapters of the human experience. So sit back and listen along, and join us in pondering the great unsolved questions of history.
Demystified W!ZARD Studios
Ahead By A Century
Gord Downie really did say it best, didn't he? "No dress rehearsal - this is our life". Apt words from an inspiring man, but that's been the proverbial rub for most humans throughout all of time - we don't get a dress rehearsal, and opening night starts before we're even aware that the curtain has come up. But what if we could peek at the script, see the plot twists of our stories coming? Many have claimed this ability, but have any of them proven it? Is there such a thing as... a Secret Path?
You are what you eat - or so they say. And everyone has their own preferences... some might even give an odd look to those who actually *enjoy* Marmite or Vodka (heaven forfend both at once)! But how should we look upon those whose tastes are a little less... conventional? Those who literally can't stop eating... When an Old Fashioned isn't your cup of tea, perhaps you'll enjoy Turpentine and Methanol?
People love to share things - and most things are better shared! You go out for a meal and get the sharing platter, a round of drinks, and the bread - to share. You watch a film, read a book, or see a tv show you love and say to your friends "You've *got* to try it"! We share things because we want other people to see what we're seeing. But what if the things we're seeing aren't really there... and our friends start seeing them too? Stare into the mirror too long, and you may end up seeing double.
Fire - to destroy all you've done. Fire - to end all you've become. Morbid words in a rather jaunty tune, but it's true; fire has that capacity. It's been with us from the dawn of time, and has been so central to basically all of human existence since that time that how we came to possess it has been the subject of myths and legends from all over the world and across history. Some say that we stole it from the gods - others that some higher being gifted it to us. But what if the fire was inside us, all along...
A Demystified Announcement
Things are changing at Demystified, and Ashleigh Stiles gives you a sense of what's to come.
We Built This City (Part 2)
Way down deep in the jungle, there lies a city of such unimaginable splendour that to even conceive of it is to dream one's wildest dreams. There also lies a wealth of danger, tropical diseases, wild animals, and an endless sea of rainforest. Would you brave the latter to find the former? Or, dream and speculate about what treasures might be hiding away? How about both?
© 2021 Ashleigh Stiles
Top Podcasts In History
Dan Snow's History Hit
History Hit Network
You're Dead To Me
You're Wrong About
Michael Hobbes & Sarah Marshall
History Extra podcast
Evil Genius with Russell Kane
More by W!ZARD Studios
She's In A Pod
W!ZARD Studios
Busy Being Black
NoShade Podcast
Throne of Glass - The Podcast
THIS IS HOW
At Home with The Lallas


text:
Persuasive speech Outline
(fresh man student) please follow the instruction in the image and the file used simple lunagage
fullsizerender.jpg4444.jpg
problem__cause__solution_template_outline.docx
example_persuasive_outline__save_the_children_1_.docx
Problem, Cause, Solution Template Outline
A. Attention Getter
B. Audience Relevance
C. Speaker Credibility
D. Thesis
E. Preview
Transition to first main point
II. Body
A. Main Point 1: Problems
Sub point 1: Problem 1
Transition (signpost, summary, preview)
B. Main Point 2: Causes
Sub point 1: Cause 1
C. Main Point 3: Solutions
Sub point 1: Solution 1
Transition and signal closing
A. Restate Thesis
B. Review Main Points
C. Memorable Closer
Persuasive Speech: Save the Children
Helen Borges
1. Attention Getter: What can you do with $70? The answer to this question may
vary depending on who you are. Many people may choose to buy a pretty dress, a
pair of shoes, a game that just came out, a huge supply of McDonald's food… But
how many people you know can say that with only $70 they can provide education
for a girl in Afghanistan for a whole year, school fees, uniforms and supplies
included? Not many, right? Well, that's a shame, because it's true, and it is made
possible thanks to the hard work of the people from Save the Children.
2. Audience Relevance: According to the 2012 Census, 21 percent of children in
America live in poverty. That is 16 million children who understand all too well what
it means to go without things that may seem so simple, but are critical in a child's
life, such as books, proper nutrition, and a place to play and learn. As Dr. Eugene
Lewit explains in his article for The Future of the Children published in 1993, poor
children encounter multiple problems during their childhood. They are more likely
than their more affluent counterparts to go hungry, to be inadequately housed and
clothed, and to receive inadequate medical care as well as insufficient social support.
Save the Children's mission is to turn those things around, and do whatever is
possible to save the children, not only in the U.S. but all over the world.
3. Credibility: As a child, I knew all too well what it meant to "go
without". Growing up in a third world country, it wasn't all that rare to see myself
and my friends going without proper schooling, books, activities and even food. I
know how important those simple things are, and I can say that I know that when
you live in poverty, $50, $20 or even $10 can be the what defines whether you will
go to bed hungry or not.
4. Thesis: After listening to this speech, you will have a better understanding of the
amazing work that Saving the Children does and how a small donation can make a
big impact in the life of an impoverished child.
5. Preview of Main Points: In this speech, I will first briefly talk about the history
of Save the Children. Second, I will talk about their impact in the lives of children in
present days. Then, I will talk about how even a small donation can make such a big
difference in the lives of impoverished children not only in the U.S. but all over the
Main Point #1: Save the Children has a long history of helping children around the world
when they need it most.
Sub-Point 1: Save the Children is a non-government organization that has a
mission of protecting children's rights and providing support for children in around
120 countries worldwide. According to Save the Children's official website, last
updated in 2014, the foundation was established in the United Kingdom in April of
1919, less than a year after the end of World War 1. More than 60 million military
personnel were mobilized for the war efforts, and the casualty rates were
staggering. With that, destruction was widespread throughout Europe, and many
children became orphans of the war. When Save the Children was created, its goal
was to provide basic needed resources, such as education, health care, and
emergency aid for those affected by the war.
Sub-Point 2: According to Save the Children's official website, last updated in
2014, by 1921, only 2 years after it was created, they had raised over £1,000,000,
and conditions for children in Central Europe were improving due to their
efforts. The efforts of Save the Children would continue to change children's lives
throughout history. They were highly active in helping children in need during crisis
such as the Russian Famine of 1921 when, as University of Nottingham senior
lecturer James Muckle explains in his article for The Slavonic and East European
Review, more than one hundred and twenty million meals were served to children
and millions more to adults; working with refugee children and displaced people in
former occupied Europe, including holocaust survivors after World War 2, helping
children who were affected by the Korean War, as well as becoming active in
previous colonies of the British empire after its decline.
Transition: Now that you've seen the amazing work Save the Children has done protecting
children and defending their rights in several countries all throughout history, I would like to
second discuss the impact Save the Children has had in recent times.
Main Point #2: Save the Children continues to come to the rescue of children in need all
Sub-Point 1: In 2010, a magnitude 7.0 earthquake hit Haiti, killing thousands of
people and displacing millions. According to the Save the Children website, last
updated in 2014, 1.6 million Haitians including 700,000 children were provided with
shelter materials, food and water, health care, hygiene, and sanitation. With the
Syrian civil war, thousands of children were killed and many more were
displaced. Even in such dangerous conditions, Save the children was quick to
respond, helping keep the children safe and providing basic needs such as food,
shelter, and helping the children cope.
Sub-Point 2: Save the Children has also come to the rescue of the American
children when they needed the most. In 2005, the US Gulf Coast saw widespread
devastation from hurricane Katrina, which displaced hundreds of thousands of
children. In response, Save the Children set up schools, camps, child care and
counseling center in order to provide help for those in need. In 2012, Hurricane
Sandy devastated the East Coast. In response, Save the Children mobilized every
available resource in order to protect the children affected by the disaster, providing
protection through our Child Friendly Spaces in emergency shelters.
Transition: Now that you have a better idea of the amazing work Save the Children has
done by providing quick response aiding the children in need, even in the most dangerous
situations, we will finally talk about how you can be a part of this cause
Main Point #3: When helping save the children in need, every dollar counts
Sub-Point 1: Many people share my great admiration with the great cause of
charities like save the children, however, as Pia Rebello Britto from the Yale school of
medicine explains in her book "Handbook of Early Childhood Development Research
and its Impact on Global Policy" published in 2013, over one-third of children
worldwide under five years of age still fail to achieve their full developmental
potential due to malnutrition, poverty, disease, neglect, and lack of learning
opportunities. Save the Children has done everything in their power to help children
in need throughout history, but the only reason they have been able to do so is
because of the great people who believe in their cause and donate. Many people say
"Well, I don't have a lot of money, my donation wouldn't make a difference", and to
those people I say: When the cause is to save the children, every dollar makes a
difference. Those children are our future lawyers, our future engineers, our future
doctors, our future politicians. Without things such as proper education and proper
health care, those children, our future generation, will be in big trouble.
Sub-Point 2: As I said in the beginning, with only $70 dollars you can provide
education to a child in Afghanistan, uniforms, supplies and school fees included, for a
whole year. That is a tiny price for such a big impact in another person's
life. According to the World Health Organization website last updated in 2014, about
45% of all deaths of children under 5 are linked to malnutrition. Why wouldn't you
want to turn that around? You don't have to donate that amount. You can donate
any amount you want. $60, $50, $20, $10 dollars can make a huge
difference. Wouldn't you want to participate in such an amazing cause? Every
donation, large or small, is a vital part of the work Save the Children does. For even
a small amount of money, you can make a huge difference in a child's life.
Transition and signal closing: As I conclude this speech, I hope you have a
better idea of how great is the influence of Save the Children in the lives of children
around the world.
C. CONCLUSION
Restate Thesis: After listening to this speech, you hopefully gained a better
understanding of the amazing work that Saving the Children does, and how a small
donation can much a big impact in the life of an impoverished child.
Review Main-Points: In this speech, I briefly talked about the history of Save the
Children. Then, we discussed their impact in the lives of children in present
days. Finally, we examined how even a small donation can make such a big
Closure: Save the children has been doing amazing work providing care and
protection for children in need throughout history. From World War 1, through the
Russian Famine, through the Haitian earthquake and Hurricane Katrina, save the
children has using every resource available to give children in the U.S. and around
the world what they deserve – a healthy start, the opportunity to learn and
protection from harm. With a simple donation, you can be part of this amazing
journey to save our future generation. Do you want to be a vital part of this
amazing cause? Do you want to make a difference? Then donate, because every
donation is valuable in helping children all over the world. Make a difference. Help
save the children.
Britto, P. R. Engle, P. L. Super , C. M. (Eds.). (2013). Handbook of early childhood
development research and its impact on global policy. New York, NY: Oxford
University Press.
Lewit, E. (1993). The Future of Children, Adoption, 3, 176-182.
Muckle, J. (1990). Saving the Russian children: Materials in the archive of Save the
Children fund relating to Eastern Europe in 1920-1923. The Slavonic and East
European Review, 68, 507-511.
Save the Children (2014) Save the Children Foundation. Retrieved
fromhttp://www.savethechildren.org/site/c.8rKLIXMGIpI4E/b.6115947/k.8D6E/Offici
al_Site.htm
U.S. Census Bureau (2012) Social, Economic, and Housing Statistics Division: Poverty.
Retrieved from http://www.census.gov/hhes/www/poverty/data/
World Health Organization (2014) MDG 1: eradicate extreme poverty and hunger. Retrieved
from http://www.who.int/topics/millennium_development_goals/hunger/en/
World Health Organization (2014) Children: Reducing Mortality. Retrieved from
http://www.who.int/mediacentre/factsheets/fs178/en/
Set up linear programming model in excel, solve using excel QM, assignment help
Earplugs Critically Considered – discussion

redpajama_set_name: RedPajamaCommonCrawl


text:
Last edited by Mazugar
Thursday, September 2, 2021 | History
4 edition of Deforestation found in the catalog.
social dynamics in watersheds and mountain ecosystems
Published 1988 by Routledge in London, New York .
Deforestation -- Environmental aspects.,
Nature conservation -- Social aspects.
Includes bibliographies and index.
Statement edited by J. Ives and D.C. Pitt.
Contributions Ives, Jack D., Pitt, David C.
Pagination xiii, 247 p. :
RIO DE JANEIRO (AP) — Deforestation in the Brazilian Amazon dropped for the second consecutive month in August compared to the same period in , according to .
Smithsons Island
shadow of the hawk.
A brief introduction to fluid mechanics
Human rights in crisis
Doctor Goebbels
Jam today, jam tomorrow?.
Self-Help for the laryngectomy
Toward a new economics
Challenge of change
New England hiking
Californians together
Psychoanalysis and Film (International Journal of Psychoanalysis Key Paper Series)
The Moderns
Deforestation Download PDF EPUB FB2
The book features several case studies which are quite interesting: Finland's pulp industry, Indonesia's oil palm industry, deforestation in the Amazon, etc - a Deforestation book.
Free day shipping within the U. when you order of eligible items sold or fulfilled by Amazon. Or get business-day shipping on this item for Author: Richard Spilsbury.
Deforestation. Richard Spilsbury. The Rosen Publishing Group, Inc, - Juvenile Nonfiction - 48 pages. 2 Reviews. Studies from around the world showcase 55(2). 1 Deforestation: Causes, Effects and Control Strategies Sumit Chakravarty 1, S. Ghosh 2, C. Suresh 2, A.
Dey 1 and Gopal Shukla 3 1Department of Forestry File Size: KB. This book provides a general view about deforestation dynamics around the Deforestation book, incorporating analyses of its causes, impacts and actions to prevent it.
Its 17 Author: Paulo Moutinho. like the Amazon. Many farmers use deforested areas of land to raise cattle; however, it might surprise you to learn that corporations do this on a much larger Size: KB.
Deforestation is the purposeful clearing of forested land. Throughout history and into modern times, forests have been razed to make space for agriculture and animal Estimated Reading Time: 4 mins.
Editors Note: This story is the third part in a series. Please read part 1, part 2, and part 4 for a more complete picture of Amazon deforestation. Scientists have. Tropical Forest Destruction Accelerated in There were bright spots, but the total lost acreage increased by 12 percent over all from the year before, according.
Deforestation is a Deforestation book concern in tropical rain forests because these forests are home to much of the worlds biodiversity.
For example, in the Amazon around. The Amazon rainforest, which is the source of 20 of the worlds oxygen supply, loses approximately acres of its area every minute due to deforestation. Causes Estimated Reading Time: 9 mins. Deforestation rates in the Amazon peaked in the late s and early s, with some years see square miles razed within 12 month periods.
Because the Estimated Reading Time: 9 mins. Deforestation in the Brazilian Amazon soared by 55 percent in the first four months of the year compared to the same period last year, according to Brazil's National Estimated Reading Time: 6 mins. At the root of the problem: the best books about deforestation An orangutan seen through a haze caused by forest clearing in Borneo, Indonesia.
Photograph: Estimated Reading Time: 4 mins. Deforestation of the Amazon Rainforest Timeline. The Amazon Rainforest has a devastating history and has been constantly exploited by humans and will continue to.
This pattern follows one of the most common deforestation trajectories in the Amazon. Legal and illegal roads penetrate a remote part of the forest, and small. On a normal day the Amazon releases 20 billion tons of moisture into the atmosphere seeding the clouds with rain. Deforestation causes the forest to dry out and can Estimated Reading Time: 3 mins.
Amazon deforestation and fires are a hazard to public health. New study exposes big differences amongst Amazonian countries in their rates of forest. Deforestation releases more carbon into the atmosphere. As mentioned above, trees store carbon dioxide, which is released when cutting them down, burning them or.
But deforestation and global warming over the last 40 years have affected rainfall and temperature with potential impacts for the Amazons ability to store carbon.
The Amazon rainforest is also the planets largest deforestation front. 21 With billion metric tons of carbon stored in the Amazons forests Estimated Reading Time: 9 mins. Deforestation or forest clearance is the removal of a forest or stand of trees from land that is then converted to non-forest use.
Deforestation can involve Estimated Reading Time: 10 mins. Decades of deforestation and fires in the Amazon coupled with the global climate crisis have caused the dry season to get longer and made megadroughts more common Author: Liz Kimbrough.
Deforestation in the Brazilian Amazon dropped for the second consecutive month in August compared to the same period in RIO DE JANEIRO -- Deforestation in the. The Amazon rainforest absorbs more greenhouse gases than any other tropical forest.
Rising deforestation in Brazil threatens biodiversity and could accelerate. Already last year, deforestation in the Amazon had reached levels not seen since At the same time, the coronavirus has killed more t peopl e in Estimated Reading Time: 9 mins.
Amazon forest fire expert professor Dolors Armenteras, who was the lead author of a study that connected isolated forest fires to future deforestation in the Estimated Reading Time: 11 mins.
Enquist, the studys senior author, said that deforestation policies have fueled increasing rates of deforestation that have deprived the Amazon of valuable time.
Deforestation, Environment, and Sustainable Development: A Comparative Analysis. Deforestation, Environment, and Sustainable Development. : Dhirendra K. n: illustrated.
deforestation for making books We should be moving to digital content instead of wasting trees by printing millions of books every year. Kom graun, oso na graun op. The fires were just the tip of the iceberg. This is Part 1 of Vox Atlas: The Amazon, a three-part series about the world's largest rainforest, why it's.
Deforestation in Brazil's Amazon rainforest fell for the second consecutive month in August, compared to a year ago, according to preliminary government data. Deforestation in Brazils Amazon rainforest fell in August compared with the same period a year earlier, continuing a downward trend while remaining higher than.
Deforestation of the Amazon rainforest in Brazil has surged to its highest level sincethe country's space agency (Inpe) reports. A total of 11, sq km Estimated Reading Time: 3 mins.
Deforestation, clearing or thinning of forests by humans to make the land available for other uses. Deforestation is a major driver of terrestrial habitat loss and.
Deforestation in the Brazilian Amazon dropped for the second consecutive month in August compared to the same period inaccording to preliminary data released. Indigenous groups are urging world leaders to back a new target to protect 80 percent of the Amazon basin bysaying bold action is needed to stop deforestation.
Deforestation explained. Human-driven and natural loss of trees-deforestation-affects wildlife, ecosystems, weather patterns, and Author: Christina Nunez. Indigenous Amazon Communities Fight Deforestation with New Early-Alert Tool. A pilot program reveals that deforestation declined when Peruvian Indigenous.
Amazon deforestation and number of fires show summer of not a 'normal' year. Simulations show parts of Amazon could switch from carbon sink to.
May - September Amazon: regrowing forests have offset less than 10% of carbon emissions from deforestation. Driven largely by the expansion of farm land to meet increasing global. Amazon gold mining drives malaria surges among Indigenous peoples. The troubling connection between deforestation, mining, and malaria is poised to create .


text:
Q: Arterisk can not be split from String I'm practicing Java with a fraction calculator. All it does is, the calculator will determine what operation is given in the input (e.g. 1/4 + 2/4) to calculate the fractions and return the result. However it seems the program fails to split arterisk * from the String [] fractionsplit and gives me following error message:
String multiplication() {
        String fractioninput = input.replaceAll(" ", "");
        System.out.println("You entered " + fractioninput);
        String [] fractionsplit = fractioninput.split("//*/");

        Integer num1 = Integer.parseInt(fractionsplit[0]);
        Integer den1 = Integer.parseInt(fractionsplit[1]);
        Integer num2 = Integer.parseInt(fractionsplit[2]);
        Integer den2 = Integer.parseInt(fractionsplit[3]);

        result = ((num1 * num2) + "/" + (den1 * den2));
        System.out.println("This is multiplication of fraction. Result is " + result);
        return result;
    }

Exception in thread "main" java.lang.NumberFormatException: For input string: "2*3"
          at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:68)
          at java.base/java.lang.Integer.parseInt(Integer.java:652)
          at java.base/java.lang.Integer.parseInt(Integer.java:770)
          at Encapsulation.MultiplicationDivision.multiplication(fractiontest1.java:77)
          at Encapsulation.fractiontest1.main(fractiontest1.java:19)

I'm using the same way to develop methods for addition, subtraction and division operations, they are all working just as expected, only multiplication() specifically fails. I referred to this question but still having the issue. I appreciate if anyone could point out the issue to me. Thanks

A: Since * is a meta-character, you need to escape it with a \. And since \ also is a meta-character, you need another \ to escape this. Thus, you need to use \\* as the regex.
Demo:
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        String exp = "4*5";
        String[] arr = exp.split("\\*");
        System.out.println(Arrays.toString(arr));
    }
}

Output:
[4, 5]

redpajama_set_name: RedPajamaStackExchange


Days are definately getting shorter and the sun hardly gets to dry up the rock in between showers and snow. One sunny day last week I just had to escape from work for a few hours to do a couple of routes out on Dyviksudde, a classic crag on the Tyresö peninsula outside Stockholm. Erik Lindvall joined me to take advantage of the beautiful day.
Ничего вводить я вообще не вижу, никакой капчи нет а сайт просит почему то ?


text:
<?php
/**
 * Piwik - free/libre analytics platform
 *
 * @link http://piwik.org
 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
 *
 */

namespace Piwik\Plugin;

use Piwik\Cache;
use Piwik\Columns\Dimension;
use Piwik\Config as PiwikConfig;
use Piwik\Config;
use Piwik\Container\StaticContainer;
use Piwik\Db;
use Piwik\EventDispatcher;
use Piwik\Filesystem;
use Piwik\Log;
use Piwik\Option;
use Piwik\Piwik;
use Piwik\Plugin;
use Piwik\PluginDeactivatedException;
use Piwik\Singleton;
use Piwik\Theme;
use Piwik\Tracker;
use Piwik\Translation\Translator;
use Piwik\Updater;
use Piwik\Plugin\Dimension\ActionDimension;
use Piwik\Plugin\Dimension\ConversionDimension;
use Piwik\Plugin\Dimension\VisitDimension;

require_once PIWIK_INCLUDE_PATH . '/core/EventDispatcher.php';

/**
 * The singleton that manages plugin loading/unloading and installation/uninstallation.
 *
 * @method static Manager getInstance()
 */
class Manager extends Singleton
{
    protected $pluginsToLoad = array();

    protected $doLoadPlugins = true;

    private $pluginsLoadedAndActivated;

    /**
     * @var Plugin[]
     */
    protected $loadedPlugins = array();
    /**
     * Default theme used in Piwik.
     */
    const DEFAULT_THEME = "Morpheus";

    protected $doLoadAlwaysActivatedPlugins = true;

    // These are always activated and cannot be deactivated
    protected $pluginToAlwaysActivate = array(
        'CoreHome',
        'CoreUpdater',
        'CoreAdminHome',
        'CoreConsole',
        'CorePluginsAdmin',
        'CoreVisualizations',
        'Installation',
        'SitesManager',
        'UsersManager',
        'API',
        'Proxy',
        'LanguagesManager',

        // default Piwik theme, always enabled
        self::DEFAULT_THEME,
    );

    // Plugins bundled with core package, disabled by default
    protected $corePluginsDisabledByDefault = array(
        'DBStats',
        'ExampleCommand',
        'ExampleSettingsPlugin',
        'ExampleUI',
        'ExampleVisualization',
        'ExamplePluginTemplate',
        'ExampleTracker',
        'ExampleReport'
    );

    // Themes bundled with core package, disabled by default
    protected $coreThemesDisabledByDefault = array(
        'ExampleTheme'
    );

    private $trackerPluginsNotToLoad = array();

    /**
     * Loads plugin that are enabled
     */
    public function loadActivatedPlugins()
    {
        $pluginsToLoad = $this->getActivatedPluginsFromConfig();
        $this->loadPlugins($pluginsToLoad);
    }

    /**
     * Called during Tracker
     */
    public function loadCorePluginsDuringTracker()
    {
        $pluginsToLoad = Config::getInstance()->Plugins['Plugins'];
        $pluginsToLoad = array_diff($pluginsToLoad, $this->getTrackerPluginsNotToLoad());
        $this->loadPlugins($pluginsToLoad);
    }

    /**
     * @return array names of plugins that have been loaded
     */
    public function loadTrackerPlugins()
    {
        $cacheId = 'PluginsTracker';
        $cache = Cache::getEagerCache();

        if ($cache->contains($cacheId)) {
            $pluginsTracker = $cache->fetch($cacheId);
        } else {

            $this->unloadPlugins();
            $this->loadActivatedPlugins();

            $pluginsTracker = array();

            foreach ($this->loadedPlugins as $pluginName => $plugin) {
                if ($this->isTrackerPlugin($plugin)) {
                    $pluginsTracker[] = $pluginName;
                }
            }

            if (!empty($pluginsTracker)) {
                $cache->save($cacheId, $pluginsTracker);
            }
        }

        if (empty($pluginsTracker)) {
            $this->unloadPlugins();
            return array();
        }

        $pluginsTracker = array_diff($pluginsTracker, $this->getTrackerPluginsNotToLoad());
        $this->doNotLoadAlwaysActivatedPlugins();
        $this->loadPlugins($pluginsTracker);

        // we could simply unload all plugins first before loading plugins but this way it is much faster
        // since we won't have to create each plugin again and we won't have to parse each plugin metadata file
        // again etc
        $this->makeSureOnlyActivatedPluginsAreLoaded();

        return $pluginsTracker;
    }

    /**
     * Do not load the specified plugins (used during testing, to disable Provider plugin)
     * @param array $plugins
     */
    public function setTrackerPluginsNotToLoad($plugins)
    {
        $this->trackerPluginsNotToLoad = $plugins;
    }

    /**
     * Get list of plugins to not load
     *
     * @return array
     */
    public function getTrackerPluginsNotToLoad()
    {
        return $this->trackerPluginsNotToLoad;
    }

    public function getCorePluginsDisabledByDefault()
    {
        return array_merge( $this->corePluginsDisabledByDefault, $this->coreThemesDisabledByDefault);
    }

    // If a plugin hooks onto at least an event starting with "Tracker.", we load the plugin during tracker
    const TRACKER_EVENT_PREFIX = 'Tracker.';

    /**
     * @param $pluginName
     * @return bool
     */
    public function isPluginOfficialAndNotBundledWithCore($pluginName)
    {
        static $gitModules;
        if (empty($gitModules)) {
            $gitModules = file_get_contents(PIWIK_INCLUDE_PATH . '/.gitmodules');
        }
        // All submodules are officially maintained plugins
        $isSubmodule = false !== strpos($gitModules, "plugins/" . $pluginName . "\n");
        return $isSubmodule;
    }

    /**
     * Update Plugins config
     *
     * @param array $pluginsToLoad Plugins
     */
    private function updatePluginsConfig($pluginsToLoad)
    {
        $pluginsToLoad = $this->sortPluginsSameOrderAsGlobalConfig($pluginsToLoad);
        $section = PiwikConfig::getInstance()->Plugins;
        $section['Plugins'] = $pluginsToLoad;
        PiwikConfig::getInstance()->Plugins = $section;
    }

    /**
     * Update PluginsInstalled config
     *
     * @param array $plugins Plugins
     */
    private function updatePluginsInstalledConfig($plugins)
    {
        $section = PiwikConfig::getInstance()->PluginsInstalled;
        $section['PluginsInstalled'] = $plugins;
        PiwikConfig::getInstance()->PluginsInstalled = $section;
    }

    public function clearPluginsInstalledConfig()
    {
        $this->updatePluginsInstalledConfig( array() );
        PiwikConfig::getInstance()->forceSave();
        PiwikConfig::getInstance()->init();
    }

    /**
     * Returns true if plugin is always activated
     *
     * @param string $name Name of plugin
     * @return bool
     */
    private function isPluginAlwaysActivated($name)
    {
        return in_array($name, $this->pluginToAlwaysActivate);
    }

    /**
     * Returns true if the plugin can be uninstalled. Any non-core plugin can be uninstalled.
     *
     * @param $name
     * @return bool
     */
    private function isPluginUninstallable($name)
    {
        return !$this->isPluginBundledWithCore($name);
    }

    /**
     * Returns `true` if a plugin has been activated.
     *
     * @param string $name Name of plugin, eg, `'Actions'`.
     * @return bool
     * @api
     */
    public function isPluginActivated($name)
    {
        return in_array($name, $this->pluginsToLoad)
        || ($this->doLoadAlwaysActivatedPlugins && $this->isPluginAlwaysActivated($name));
    }

    /**
     * Checks whether the given plugin is activated, if not triggers an exception.
     *
     * @param  string $pluginName
     * @throws PluginDeactivatedException
     */
    public function checkIsPluginActivated($pluginName)
    {
        if (!$this->isPluginActivated($pluginName)) {
            throw new PluginDeactivatedException($pluginName);
        }
    }

    /**
     * Returns `true` if plugin is loaded (in memory).
     *
     * @param string $name Name of plugin, eg, `'Acions'`.
     * @return bool
     * @api
     */
    public function isPluginLoaded($name)
    {
        return isset($this->loadedPlugins[$name]);
    }

    /**
     * Reads the directories inside the plugins/ directory and returns their names in an array
     *
     * @return array
     */
    public function readPluginsDirectory()
    {
        $pluginsName = _glob(self::getPluginsDirectory() . '*', GLOB_ONLYDIR);
        $result = array();
        if ($pluginsName != false) {
            foreach ($pluginsName as $path) {
                if (self::pluginStructureLooksValid($path)) {
                    $result[] = basename($path);
                }
            }
        }
        return $result;
    }

    public static function getPluginsDirectory()
    {
        return PIWIK_INCLUDE_PATH . '/plugins/';
    }

    /**
     * Deactivate plugin
     *
     * @param string $pluginName Name of plugin
     */
    public function deactivatePlugin($pluginName)
    {
        // execute deactivate() to let the plugin do cleanups
        $this->executePluginDeactivate($pluginName);

        $this->unloadPluginFromMemory($pluginName);

        $this->removePluginFromConfig($pluginName);

        $this->clearCache($pluginName);

        /**
         * Event triggered after a plugin has been deactivated.
         *
         * @param string $pluginName The plugin that has been deactivated.
         */
        Piwik::postEvent('PluginManager.pluginDeactivated', array($pluginName));
    }

    /**
     * Tries to find the given components such as a Menu or Tasks implemented by plugins.
     * This method won't cache the found components. If you need to find the same component multiple times you might
     * want to cache the result to save a tiny bit of time.
     *
     * @param string $componentName     The name of the component you want to look for. In case you request a
     *                                  component named 'Menu' it'll look for a file named 'Menu.php' within the
     *                                  root of all plugin folders that implement a class named
     *                                  Piwik\Plugin\$PluginName\Menu.
     * @param string $expectedSubclass  If not empty, a check will be performed whether a found file extends the
     *                                  given subclass. If the requested file exists but does not extend this class
     *                                  a warning will be shown to advice a developer to extend this certain class.
     *
     * @return \stdClass[]
     */
    public function findComponents($componentName, $expectedSubclass)
    {
        $plugins    = $this->getPluginsLoadedAndActivated();
        $components = array();

        foreach ($plugins as $plugin) {
            $component = $plugin->findComponent($componentName, $expectedSubclass);

            if (!empty($component)) {
                $components[] = $component;
            }
        }

        return $components;
    }

    public function findMultipleComponents($directoryWithinPlugin, $expectedSubclass)
    {
        $plugins = $this->getPluginsLoadedAndActivated();
        $found   = array();

        foreach ($plugins as $plugin) {
            $components = $plugin->findMultipleComponents($directoryWithinPlugin, $expectedSubclass);

            if (!empty($components)) {
                $found = array_merge($found, $components);
            }
        }

        return $found;
    }

    /**
     * Uninstalls a Plugin (deletes plugin files from the disk)
     * Only deactivated plugins can be uninstalled
     *
     * @param $pluginName
     * @throws \Exception
     * @return bool
     */
    public function uninstallPlugin($pluginName)
    {
        if ($this->isPluginLoaded($pluginName)) {
            throw new \Exception("To uninstall the plugin $pluginName, first disable it in Piwik > Settings > Plugins");
        }
        $this->loadAllPluginsAndGetTheirInfo();

        \Piwik\Settings\Manager::cleanupPluginSettings($pluginName);

        $this->executePluginDeactivate($pluginName);
        $this->executePluginUninstall($pluginName);

        $this->removePluginFromPluginsInstalledConfig($pluginName);

        $this->unloadPluginFromMemory($pluginName);

        $this->removePluginFromConfig($pluginName);
        $this->removeInstalledVersionFromOptionTable($pluginName);
        $this->clearCache($pluginName);

        self::deletePluginFromFilesystem($pluginName);
        if ($this->isPluginInFilesystem($pluginName)) {
            return false;
        }
        return true;
    }

    /**
     * @param string $pluginName
     */
    private function clearCache($pluginName)
    {
        $this->resetTransientCache();
        Filesystem::deleteAllCacheOnUpdate($pluginName);
    }

    public static function deletePluginFromFilesystem($plugin)
    {
        Filesystem::unlinkRecursive(PIWIK_INCLUDE_PATH . '/plugins/' . $plugin, $deleteRootToo = true);
    }

    /**
     * Install loaded plugins
     *
     * @throws
     * @return array Error messages of plugin install fails
     */
    public function installLoadedPlugins()
    {
        Log::debug("Loaded plugins: " . implode(", ", array_keys($this->getLoadedPlugins())));
        $messages = array();
        foreach ($this->getLoadedPlugins() as $plugin) {
            try {
                $this->installPluginIfNecessary($plugin);
            } catch (\Exception $e) {
                $messages[] = $e->getMessage();
            }
        }

        return $messages;
    }

    /**
     * Activate the specified plugin and install (if needed)
     *
     * @param string $pluginName Name of plugin
     * @throws \Exception
     */
    public function activatePlugin($pluginName)
    {
        $plugins = PiwikConfig::getInstance()->Plugins['Plugins'];
        if (in_array($pluginName, $plugins)) {
            throw new \Exception("Plugin '$pluginName' already activated.");
        }

        if (!$this->isPluginInFilesystem($pluginName)) {
            throw new \Exception("Plugin '$pluginName' cannot be found in the filesystem in plugins/ directory.");
        }
        $this->deactivateThemeIfTheme($pluginName);

        // Load plugin
        $plugin = $this->loadPlugin($pluginName);
        if ($plugin === null) {
            throw new \Exception("The plugin '$pluginName' was found in the filesystem, but could not be loaded.'");
        }
        $this->installPluginIfNecessary($plugin);
        $plugin->activate();

        EventDispatcher::getInstance()->postPendingEventsTo($plugin);

        $this->pluginsToLoad[] = $pluginName;

        $this->updatePluginsConfig($this->pluginsToLoad);
        PiwikConfig::getInstance()->forceSave();

        $this->clearCache($pluginName);

        /**
         * Event triggered after a plugin has been activated.
         *
         * @param string $pluginName The plugin that has been activated.
         */
        Piwik::postEvent('PluginManager.pluginActivated', array($pluginName));
    }

    protected function isPluginInFilesystem($pluginName)
    {
        $existingPlugins = $this->readPluginsDirectory();
        $isPluginInFilesystem = array_search($pluginName, $existingPlugins) !== false;
        return Filesystem::isValidFilename($pluginName)
        && $isPluginInFilesystem;
    }

    /**
     * Returns the currently enabled theme.
     *
     * If no theme is enabled, the **Morpheus** plugin is returned (this is the base and default theme).
     *
     * @return Plugin
     * @api
     */
    public function getThemeEnabled()
    {
        $plugins = $this->getLoadedPlugins();

        $theme = false;
        foreach ($plugins as $plugin) {
            /* @var $plugin Plugin */
            if ($plugin->isTheme()
                && $this->isPluginActivated($plugin->getPluginName())
            ) {
                if ($plugin->getPluginName() != self::DEFAULT_THEME) {
                    return $plugin; // enabled theme (not default)
                }
                $theme = $plugin; // default theme
            }
        }
        return $theme;
    }

    /**
     * @param string $themeName
     * @throws \Exception
     * @return Theme
     */
    public function getTheme($themeName)
    {
        $plugins = $this->getLoadedPlugins();

        foreach ($plugins as $plugin) {
            if ($plugin->isTheme() && $plugin->getPluginName() == $themeName) {
                return new Theme($plugin);
            }
        }
        throw new \Exception('Theme not found : ' . $themeName);
    }

    public function getNumberOfActivatedPlugins()
    {
        $counter = 0;

        $pluginNames = $this->getLoadedPluginsName();
        foreach ($pluginNames as $pluginName) {
            if ($this->isPluginActivated($pluginName)) {
                $counter++;
            }
        }

        return $counter;
    }

    /**
     * Returns info regarding all plugins. Loads plugins that can be loaded.
     *
     * @return array An array that maps plugin names with arrays of plugin information. Plugin
     *               information consists of the following entries:
     *
     *               - **activated**: Whether the plugin is activated.
     *               - **alwaysActivated**: Whether the plugin should always be activated,
     *                                      or not.
     *               - **uninstallable**: Whether the plugin is uninstallable or not.
     *               - **invalid**: If the plugin is invalid, this property will be set to true.
     *                              If the plugin is not invalid, this property will not exist.
     *               - **info**: If the plugin was loaded, will hold the plugin information.
     *                           See {@link Piwik\Plugin::getInformation()}.
     * @api
     */
    public function loadAllPluginsAndGetTheirInfo()
    {
        /** @var Translator $translator */
        $translator = StaticContainer::get('Piwik\Translation\Translator');

        $plugins = array();

        $listPlugins = array_merge(
            $this->readPluginsDirectory(),
            PiwikConfig::getInstance()->Plugins['Plugins']
        );
        $listPlugins = array_unique($listPlugins);
        foreach ($listPlugins as $pluginName) {
            // Hide plugins that are never going to be used
            if ($this->isPluginBogus($pluginName)) {
                continue;
            }

            // If the plugin is not core and looks bogus, do not load
            if ($this->isPluginThirdPartyAndBogus($pluginName)) {
                $info = array(
                    'invalid'         => true,
                    'activated'       => false,
                    'alwaysActivated' => false,
                    'uninstallable'   => true,
                );
            } else {
                $translator->addDirectory(self::getPluginsDirectory() . $pluginName . '/lang');
                $this->loadPlugin($pluginName);
                $info = array(
                    'activated'       => $this->isPluginActivated($pluginName),
                    'alwaysActivated' => $this->isPluginAlwaysActivated($pluginName),
                    'uninstallable'   => $this->isPluginUninstallable($pluginName),
                );
            }

            $plugins[$pluginName] = $info;
        }

        $loadedPlugins = $this->getLoadedPlugins();
        foreach ($loadedPlugins as $oPlugin) {
            $pluginName = $oPlugin->getPluginName();

            $info = array(
                'info' => $oPlugin->getInformation(),
                'activated'       => $this->isPluginActivated($pluginName),
                'alwaysActivated' => $this->isPluginAlwaysActivated($pluginName),
                'missingRequirements' => $oPlugin->getMissingDependencies(),
                'uninstallable' => $this->isPluginUninstallable($pluginName),
            );
            $plugins[$pluginName] = $info;
        }

        return $plugins;
    }

    protected static function isManifestFileFound($path)
    {
        return file_exists($path . "/" . MetadataLoader::PLUGIN_JSON_FILENAME);
    }

    /**
     * Returns `true` if the plugin is bundled with core or `false` if it is third party.
     *
     * @param string $name The name of the plugin, eg, `'Actions'`.
     * @return bool
     */
    public function isPluginBundledWithCore($name)
    {
        return $this->isPluginEnabledByDefault($name)
                || in_array($name, $this->getCorePluginsDisabledByDefault())
                || $name == self::DEFAULT_THEME;
    }

    protected function isPluginThirdPartyAndBogus($pluginName)
    {
        if ($this->isPluginBundledWithCore($pluginName)) {
            return false;
        }
        if ($this->isPluginBogus($pluginName)) {
            return true;
        }

        $path = $this->getPluginsDirectory() . $pluginName;
        if (!$this->isManifestFileFound($path)) {
            return true;
        }
        return false;
    }

    /**
     * Load AND activates the specified plugins. It will also overwrite all previously loaded plugins, so it acts
     * as a setter.
     *
     * @param array $pluginsToLoad Array of plugins to load.
     */
    public function loadPlugins(array $pluginsToLoad)
    {
        $this->resetTransientCache();
        $this->pluginsToLoad = $this->makePluginsToLoad($pluginsToLoad);
        $this->reloadActivatedPlugins();
    }

    /**
     * Disable plugin loading.
     */
    public function doNotLoadPlugins()
    {
        $this->doLoadPlugins = false;
    }

    /**
     * Disable loading of "always activated" plugins.
     */
    public function doNotLoadAlwaysActivatedPlugins()
    {
        $this->doLoadAlwaysActivatedPlugins = false;
    }

    /**
     * Execute postLoad() hook for loaded plugins
     */
    public function postLoadPlugins()
    {
        $plugins = $this->getLoadedPlugins();
        foreach ($plugins as $plugin) {
            $plugin->postLoad();
        }
    }

    /**
     * Returns an array containing the plugins class names (eg. 'UserCountry' and NOT 'UserCountry')
     *
     * @return array
     */
    public function getLoadedPluginsName()
    {
        return array_keys($this->getLoadedPlugins());
    }

    /**
     * Returns an array mapping loaded plugin names with their plugin objects, eg,
     *
     *     array(
     *         'UserCountry' => Plugin $pluginObject,
     *         'UserLanguage' => Plugin $pluginObject,
     *     );
     *
     * @return Plugin[]
     */
    public function getLoadedPlugins()
    {
        return $this->loadedPlugins;
    }

    /**
     * @param  string $piwikVersion
     * @return Plugin[]
     */
    public function getIncompatiblePlugins($piwikVersion)
    {
        $plugins = $this->getLoadedPlugins();

        $incompatible = array();
        foreach ($plugins as $plugin) {
            if ($plugin->hasMissingDependencies($piwikVersion)) {
                $incompatible[] = $plugin;
            }
        }

        return $incompatible;
    }

    /**
     * Returns an array of plugins that are currently loaded and activated,
     * mapping loaded plugin names with their plugin objects, eg,
     *
     *     array(
     *         'UserCountry' => Plugin $pluginObject,
     *         'UserLanguage' => Plugin $pluginObject,
     *     );
     *
     * @return Plugin[]
     */
    public function getPluginsLoadedAndActivated()
    {
        if (is_null($this->pluginsLoadedAndActivated)) {
            $enabled = $this->getActivatedPlugins();

            if (empty($enabled)) {
                return array();
            }

            $plugins = $this->getLoadedPlugins();
            $enabled = array_combine($enabled, $enabled);
            $plugins = array_intersect_key($plugins, $enabled);

            $this->pluginsLoadedAndActivated = $plugins;
        }

        return $this->pluginsLoadedAndActivated;
    }

    /**
     * Returns a list of all names of currently activated plugin eg,
     *
     *     array(
     *         'UserCountry'
     *         'UserLanguage'
     *     );
     *
     * @return string[]
     */
    public function getActivatedPlugins()
    {
        return $this->pluginsToLoad;
    }

    public function getActivatedPluginsFromConfig()
    {
        $plugins = @Config::getInstance()->Plugins['Plugins'];

        return $this->makePluginsToLoad($plugins);
    }

    /**
     * Returns a Plugin object by name.
     *
     * @param string $name The name of the plugin, eg, `'Actions'`.
     * @throws \Exception If the plugin has not been loaded.
     * @return Plugin
     */
    public function getLoadedPlugin($name)
    {
        if (!isset($this->loadedPlugins[$name])) {
            throw new \Exception("The plugin '$name' has not been loaded.");
        }
        return $this->loadedPlugins[$name];
    }

    /**
     * Load the plugins classes installed.
     * Register the observers for every plugin.
     */
    private function reloadActivatedPlugins()
    {
        $pluginsToPostPendingEventsTo = array();
        foreach ($this->pluginsToLoad as $pluginName) {
            if (!$this->isPluginLoaded($pluginName)
                && !$this->isPluginThirdPartyAndBogus($pluginName)
            ) {
                $newPlugin = $this->loadPlugin($pluginName);
                if ($newPlugin === null) {
                    continue;
                }

                if ($newPlugin->hasMissingDependencies()) {
                    $this->deactivatePlugin($pluginName);
                    continue;
                }

                $pluginsToPostPendingEventsTo[] = $newPlugin;
            }
        }

        // post pending events after all plugins are successfully loaded
        foreach ($pluginsToPostPendingEventsTo as $plugin) {
            EventDispatcher::getInstance()->postPendingEventsTo($plugin);
        }
    }

    public function getIgnoredBogusPlugins()
    {
        $ignored = array();
        foreach ($this->pluginsToLoad as $pluginName) {
            if ($this->isPluginThirdPartyAndBogus($pluginName)) {
                $ignored[] = $pluginName;
            }
        }
        return $ignored;
    }

    /**
     * Returns the name of all plugins found in this Piwik instance
     * (including those not enabled and themes)
     *
     * @return array
     */
    public static function getAllPluginsNames()
    {
        $pluginsToLoad = array_merge(
            PiwikConfig::getInstance()->Plugins['Plugins'],
            self::getInstance()->readPluginsDirectory(),
            self::getInstance()->getCorePluginsDisabledByDefault()
        );
        $pluginsToLoad = array_values(array_unique($pluginsToLoad));
        return $pluginsToLoad;
    }

    /**
     * Loads the plugin filename and instantiates the plugin with the given name, eg. UserCountry.
     * Contrary to loadPlugins() it does not activate the plugin, it only loads it.
     *
     * @param string $pluginName
     * @throws \Exception
     * @return Plugin|null
     */
    public function loadPlugin($pluginName)
    {
        if (isset($this->loadedPlugins[$pluginName])) {
            return $this->loadedPlugins[$pluginName];
        }
        $newPlugin = $this->makePluginClass($pluginName);

        $this->addLoadedPlugin($pluginName, $newPlugin);
        return $newPlugin;
    }

    /**
     * @param $pluginName
     * @return Plugin
     * @throws \Exception
     */
    protected function makePluginClass($pluginName)
    {
        $pluginFileName = sprintf("%s/%s.php", $pluginName, $pluginName);
        $pluginClassName = $pluginName;

        if (!Filesystem::isValidFilename($pluginName)) {
            throw new \Exception(sprintf("The plugin filename '%s' is not a valid filename", $pluginFileName));
        }

        $path = self::getPluginsDirectory() . $pluginFileName;

        if (!file_exists($path)) {
            // Create the smallest minimal Piwik Plugin
            // Eg. Used for Morpheus default theme which does not have a Morpheus.php file
            return new Plugin($pluginName);
        }

        require_once $path;

        $namespacedClass = $this->getClassNamePlugin($pluginName);
        if (!class_exists($namespacedClass, false)) {
            throw new \Exception("The class $pluginClassName couldn't be found in the file '$path'");
        }
        $newPlugin = new $namespacedClass;

        if (!($newPlugin instanceof Plugin)) {
            throw new \Exception("The plugin $pluginClassName in the file $path must inherit from Plugin.");
        }
        return $newPlugin;
    }

    protected function getClassNamePlugin($pluginName)
    {
        $className = $pluginName;
        if ($pluginName == 'API') {
            $className = 'Plugin';
        }
        return "\\Piwik\\Plugins\\$pluginName\\$className";
    }

    private function resetTransientCache()
    {
        $this->pluginsLoadedAndActivated = null;
    }

    /**
     * Unload plugin
     *
     * @param Plugin|string $plugin
     * @throws \Exception
     */
    public function unloadPlugin($plugin)
    {
        $this->resetTransientCache();

        if (!($plugin instanceof Plugin)) {
            $oPlugin = $this->loadPlugin($plugin);
            if ($oPlugin === null) {
                unset($this->loadedPlugins[$plugin]);
                return;
            }

            $plugin = $oPlugin;
        }

        unset($this->loadedPlugins[$plugin->getPluginName()]);
    }

    /**
     * Unload all loaded plugins
     */
    public function unloadPlugins()
    {
        $this->resetTransientCache();

        $pluginsLoaded = $this->getLoadedPlugins();
        foreach ($pluginsLoaded as $plugin) {
            $this->unloadPlugin($plugin);
        }
    }

    /**
     * Install a specific plugin
     *
     * @param Plugin $plugin
     * @throws \Piwik\Plugin\PluginException if installation fails
     */
    private function executePluginInstall(Plugin $plugin)
    {
        try {
            $plugin->install();
        } catch (\Exception $e) {
            throw new \Piwik\Plugin\PluginException($plugin->getPluginName(), $e->getMessage());
        }
    }

    /**
     * Add a plugin in the loaded plugins array
     *
     * @param string $pluginName plugin name without prefix (eg. 'UserCountry')
     * @param Plugin $newPlugin
     * @internal
     */
    public function addLoadedPlugin($pluginName, Plugin $newPlugin)
    {
        $this->resetTransientCache();

        $this->loadedPlugins[$pluginName] = $newPlugin;
    }

    /**
     * Return names of all installed plugins.
     *
     * @return array
     * @api
     */
    public function getInstalledPluginsName()
    {
        $pluginNames = PiwikConfig::getInstance()->PluginsInstalled['PluginsInstalled'];
        return $pluginNames;
    }

    /**
     * Returns names of plugins that should be loaded, but cannot be since their
     * files cannot be found.
     *
     * @return array
     * @api
     */
    public function getMissingPlugins()
    {
        $missingPlugins = array();
        if (isset(PiwikConfig::getInstance()->Plugins['Plugins'])) {
            $plugins = PiwikConfig::getInstance()->Plugins['Plugins'];
            foreach ($plugins as $pluginName) {
                // if a plugin is listed in the config, but is not loaded, it does not exist in the folder
                if (!self::getInstance()->isPluginLoaded($pluginName)
                    && !$this->isPluginBogus($pluginName)
                ) {
                    $missingPlugins[] = $pluginName;
                }
            }
        }
        return $missingPlugins;
    }

    /**
     * Install a plugin, if necessary
     *
     * @param Plugin $plugin
     */
    private function installPluginIfNecessary(Plugin $plugin)
    {
        $pluginName = $plugin->getPluginName();
        $saveConfig = false;

        // is the plugin already installed or is it the first time we activate it?
        $pluginsInstalled = $this->getInstalledPluginsName();

        if (!$this->isPluginInstalled($pluginName)) {
            $this->executePluginInstall($plugin);
            $pluginsInstalled[] = $pluginName;
            $this->updatePluginsInstalledConfig($pluginsInstalled);
            $updater = new Updater();
            $updater->markComponentSuccessfullyUpdated($plugin->getPluginName(), $plugin->getVersion());
            $saveConfig = true;
        }

        if ($saveConfig) {
            PiwikConfig::getInstance()->forceSave();
        }
    }

    public function isTrackerPlugin(Plugin $plugin)
    {
        $dimensions = VisitDimension::getDimensions($plugin);
        if (!empty($dimensions)) {
            return true;
        }

        $dimensions = ActionDimension::getDimensions($plugin);
        if (!empty($dimensions)) {
            return true;
        }

        $hooks = $plugin->getListHooksRegistered();
        $hookNames = array_keys($hooks);
        foreach ($hookNames as $name) {
            if (strpos($name, self::TRACKER_EVENT_PREFIX) === 0) {
                return true;
            }
            if ($name === 'Request.initAuthenticationObject') {
                return true;
            }
        }

        $dimensions = ConversionDimension::getDimensions($plugin);
        if (!empty($dimensions)) {
            return true;
        }

        return false;
    }

    private static function pluginStructureLooksValid($path)
    {
        $name = basename($path);
        return file_exists($path . "/" . $name . ".php")
        || self::isManifestFileFound($path);
    }

    /**
     * @param $pluginName
     */
    private function removePluginFromPluginsInstalledConfig($pluginName)
    {
        $pluginsInstalled = PiwikConfig::getInstance()->PluginsInstalled['PluginsInstalled'];
        $key = array_search($pluginName, $pluginsInstalled);
        if ($key !== false) {
            unset($pluginsInstalled[$key]);
        }

        $this->updatePluginsInstalledConfig($pluginsInstalled);
    }

    /**
     * @param $pluginName
     */
    private function removePluginFromPluginsConfig($pluginName)
    {
        $pluginsEnabled = PiwikConfig::getInstance()->Plugins['Plugins'];
        $key = array_search($pluginName, $pluginsEnabled);
        if ($key !== false) {
            unset($pluginsEnabled[$key]);
        }
        $this->updatePluginsConfig($pluginsEnabled);
    }

    /**
     * @param $pluginName
     * @return bool
     */
    private function isPluginBogus($pluginName)
    {
        $bogusPlugins = array(
            'PluginMarketplace', //defines a plugin.json but 1.x Piwik plugin
            'DoNotTrack', // Removed in 2.0.3
            'AnonymizeIP', // Removed in 2.0.3
        );
        return in_array($pluginName, $bogusPlugins);
    }

    private function deactivateThemeIfTheme($pluginName)
    {
        // Only one theme enabled at a time
        $themeEnabled = $this->getThemeEnabled();
        if ($themeEnabled
            && $themeEnabled->getPluginName() != self::DEFAULT_THEME) {
            $themeAlreadyEnabled = $themeEnabled->getPluginName();

            $plugin = $this->loadPlugin($pluginName);
            if ($plugin->isTheme()) {
                $this->deactivatePlugin($themeAlreadyEnabled);
            }
        }
    }

    /**
     * @param $pluginName
     */
    private function executePluginDeactivate($pluginName)
    {
        if (!$this->isPluginBogus($pluginName)) {
            $plugin = $this->loadPlugin($pluginName);
            if ($plugin !== null) {
                $plugin->deactivate();
            }
        }
    }

    /**
     * @param $pluginName
     */
    private function unloadPluginFromMemory($pluginName)
    {
        $key = array_search($pluginName, $this->pluginsToLoad);
        if ($key !== false) {
            unset($this->pluginsToLoad[$key]);
        }
    }

    /**
     * @param $pluginName
     */
    private function removePluginFromConfig($pluginName)
    {
        $this->removePluginFromPluginsConfig($pluginName);
        PiwikConfig::getInstance()->forceSave();
    }

    /**
     * @param $pluginName
     */
    private function executePluginUninstall($pluginName)
    {
        try {
            $plugin = $this->getLoadedPlugin($pluginName);
            $plugin->uninstall();
        } catch (\Exception $e) {
        }

        if (empty($plugin)) {
            return;
        }

        try {
            foreach (VisitDimension::getDimensions($plugin) as $dimension) {
                $this->uninstallDimension($dimension);
            }
        } catch (\Exception $e) {
        }

        try {
            foreach (ActionDimension::getDimensions($plugin) as $dimension) {
                $this->uninstallDimension($dimension);
            }
        } catch (\Exception $e) {
        }

        try {
            foreach (ConversionDimension::getDimensions($plugin) as $dimension) {
                $this->uninstallDimension($dimension);
            }
        } catch (\Exception $e) {
        }
    }

    /**
     * @param ConversionDimension|VisitDimension|ActionDimension $dimension
     */
    private function uninstallDimension(Dimension $dimension)
    {
        $dimension->uninstall();
        Option::delete('version_' . $dimension->getVersion());
    }

    /**
     * @param $pluginName
     * @return bool
     */
    public function isPluginInstalled($pluginName)
    {
        $pluginsInstalled = $this->getInstalledPluginsName();
        return in_array($pluginName, $pluginsInstalled);
    }

    private function removeInstalledVersionFromOptionTable($version)
    {
        Option::delete('version_' . $version);
    }

    private function makeSureOnlyActivatedPluginsAreLoaded()
    {
        foreach ($this->getLoadedPlugins() as $pluginName => $plugin) {
            if (!in_array($pluginName, $this->pluginsToLoad)) {
                $this->unloadPlugin($plugin);
            }
        }
    }

    /**
     * Reading the plugins from the global.ini.php config file
     *
     * @return array
     */
    protected function getPluginsFromGlobalIniConfigFile()
    {
        $pluginsBundledWithPiwik = PiwikConfig::getInstance()->getFromGlobalConfig('Plugins');
        $pluginsBundledWithPiwik = $pluginsBundledWithPiwik['Plugins'];
        return $pluginsBundledWithPiwik;
    }

    /**
     * @param $name
     * @return bool
     */
    protected function isPluginEnabledByDefault($name)
    {
        $pluginsBundledWithPiwik = $this->getPluginsFromGlobalIniConfigFile();

        if(empty($pluginsBundledWithPiwik)) {
            return false;
        }
        return in_array($name, $pluginsBundledWithPiwik);
    }

    /**
     * @param array $pluginsToLoad
     * @return array
     */
    private function makePluginsToLoad(array $pluginsToLoad)
    {
        $pluginsToLoad = array_unique($pluginsToLoad);
        if ($this->doLoadAlwaysActivatedPlugins) {
            $pluginsToLoad = array_merge($pluginsToLoad, $this->pluginToAlwaysActivate);
        }
        $pluginsToLoad = array_unique($pluginsToLoad);
        $pluginsToLoad = $this->sortPluginsSameOrderAsGlobalConfig($pluginsToLoad);
        return $pluginsToLoad;
    }

    private function sortPluginsSameOrderAsGlobalConfig(array $plugins)
    {
        $global = $this->getPluginsFromGlobalIniConfigFile();
        if(empty($global)) {
            return $plugins;
        }
        $global = array_values($global);
        $plugins = array_values($plugins);

        $defaultPluginsLoadedFirst = array_intersect($global, $plugins);

        $otherPluginsToLoadAfterDefaultPlugins = array_diff($plugins, $defaultPluginsLoadedFirst);

        // sort by name to have a predictable order for those extra plugins
        sort($otherPluginsToLoadAfterDefaultPlugins);

        $sorted = array_merge($defaultPluginsLoadedFirst, $otherPluginsToLoadAfterDefaultPlugins);

        return $sorted;
    }

    public function loadPluginTranslations()
    {
        /** @var Translator $translator */
        $translator = StaticContainer::get('Piwik\Translation\Translator');
        foreach ($this->getAllPluginsNames() as $pluginName) {
            $translator->addDirectory(self::getPluginsDirectory() . $pluginName . '/lang');
        }
    }
}

redpajama_set_name: RedPajamaGithub


New solutions for integrating hardware and software that meet the IoT era's security demands are arriving.
Deep packet inspection (DPI) technology offers network traffic user, application, and location information for fine-tuned traffic control. Employing software-defined networking (SDN) technology makes it possible to implement programmable network traffic, redirect traffic, and configure automatic security policy. With network function virtualization (NFV), security resource pools can be established for collaborative deployment among computing and security assets.
Figure 1: Key deployment points of unified DPI equipment. Sharing DPI equipment at key points of the telecom network, unified DPI reduces duplication of equipment deployment, allows DPI equipment and DPI applications to evolve independently of each other, and greatly enhances the ability to innovate DPI applications.
With the network traffic visualization DPI achieves, telecom operators can optimize their businesses for specific services, develop value-added services based on user identity, and handle security more effectively. DPI equipment has been tightly coupled with the corresponding DPI application. As the number of DPI applications increases, more and more DPI equipment must be deployed, leading to inefficiencies.
The unified DPI concept proposes to reduce inefficiency by enabling DPI equipment sharing. Unified DPI standardizes network traffic visualization. By coordinating DPI equipment deployment from a network-wide perspective, the DPI requirements are unified at key network locations, and DPI services are shared among multiple DPI applications through a suite of unified northbound API. This approach avoids the repeated deployment of DPI equipment (Figure 1).
The number of traffic types DPI equipment can identify, the foundation of all upper layer DPI application innovations, affects the equipment's value. As do the analytic capabilities, which depend on software design and to a greater extent on DPI hardware platform computing performance. Performance must be powerful enough to identify more types of traffic in real time.
To avoid coupling between upper layer DPI applications and lower layer DPI equipment, to allow a range of deployment locations, and to be compatible with different DPI application hardware, unified DPI specifies the requirements for hardware interface support. Depending on the deployment location in the telecom network, DPI equipment needs to support ingress/egress network traffic with 1G/10G WAN/LAN, 2.5G/10G POS networks or 100GbE. For DPI equipment that needs to be concatenated in the network, the required network interfaces must be implemented natively on the DPI equipment. Implementation by using external splitters, switches, or protocol convertors is disallowed, preventing the added devices from introducing extra failure risk. Therefore, in addition to sufficient ingress/egress ports and processing bandwidth, unified DPI equipment must also provide flexible network IO configuration, so the appropriate interface modules can be selected to adapt to different deployment locations.
Supporting various upper layer DPI applications calls for common protocol identification and statistical functions and strong flow control logic. To enable the fine-grained traffic control upper layer applications demand, the DPI equipment must support flow control based on the identified network traffic, including minimum bandwidth guarantee, maximum bandwidth limit, flow pass-through, and flow discarding.
Developing network security applications means DPI equipment must support white-list and black-list settings based on flow metadata such as source address, destination address, protocol number, source port, destination port, domain name, and user ID. If these functional requirements are implemented with traditional methods, functional implementation is not transparent, and available upgrade space is limited. SDN technology can be used to classify traffic flow based on multi-dimensional metadata and set different flow control strategies. Constructing DPI service logic based on SDN architecture enables the DPI analysis, statistics, control, multiplex, and security functions to be centralized and opens the possibility of a wide range of DPI application innovations.
Unified DPI equipment must provide 99.999% high availability, with the main service components providing an appropriate hot-standby solution. Other system components, such as power supply unit and fan tray must provide appropriate redundancy and support online replacement when they experience a failure. DPI equipment that needs to be concatenated in the communication link needs a LAN bypass function. When DPI equipment suffers from a power loss or a self-test failure, it can switch the communication link from the main unit to the bypass unit automatically, ensuring continuity of service.
Data communications begin at the user and go sequentially over the access network, metro network, provincial network, and backbone network. Therefore, an overview of network traffic conditions can be determined by deploying DPI equipment at key points along the route which the data traffic travels. According to the unified DPI specification from China Mobile, these key deployment points can be summarized as: PS side, IDC export, provincial network export, inter-provincial network export, and inter-backbone network export. The required external network interfaces are different at these key points, as is network traffic size, so a single device can't meet the different requirements at all deployment points. However, to reduce TCO and reserve upgrade capacity for future use, most DPI service providers would prefer a single scalable platform that can deal with most deployment scenarios. Adopting modular design and supporting linear expansion for the computing units solves this dilemma.
Traditional network security uses firewalls, unified threat management (UTM), intrusion prevention systems (IPS) or other network security products to block attacks at the network entrance boundary. This network boundary forms when networks that have different security levels are connected together. For example, the private network of an enterprise has a higher security level requirement than the public internet, and the connection point between private network and public internet forms the natural security boundary. Once, preventing an intrusion from outside the enterprise network simply required establishing reliable security protection measures at the boundary.
But with the advent of cloud computing, enterprises are moving more of their operations to the public cloud. As a result, the network boundary between private and public networks is blurring. Relying on the traditional concept of the network security boundary is no longer viable. Cloud computing needs a new generation of network security equipment.
In network security, DPI has played an increasingly important role, and it is becoming the cornerstone of cloud computing security in the IoT era. More end-user applications are using HTTP/HTTPS protocols to exchange data. If traditional matching techniques based on TCP/IP 5-tuples are used, most of the traffic flows belonging to other applications will be misidentified as normal Web surfing. Whether for business optimization, content review, or security, it is necessary to 1) know the identity of the traffic flow using DPI analysis, and 2) perform the appropriate control strategy based on protection needs. Because the working mode of DPI analytics engines is generally concatenated, the average computational workload will increase linearly as the number of application types to be identified increases. To guarantee a smooth implementation of DPI analytics, DPI equipment must be equipped with adequate computing power based on the application types to be identified and the traffic size to be handled.
Traditional network security equipment is deployed at the physical security boundary, monitoring traffic flow that enters and leaves the security zone and then performing the required network security tasks. Cloud computing's multi-tenant environment and frequent virtual machine migrations mean that a security zone with a physical boundary does not exist. Even the logical boundaries of the security zone will experience constant changes as virtual machines migrate, resulting in a significant challenge for cloud computing security.
As a virtual machine migration occurs, the network security policies configured for that virtual machine must also be adjusted. If the migration does not go beyond the protective scope of the current network security appliance, then the security policies related to that virtual machine can be adjusted. However, if the virtual machine migration extends beyond the scope of the current network security appliance, then the security policies related to that virtual machine must be migrated to the new network security appliance. The configurations of traditional network security appliances are often static, localized, and need human intervention, making it difficult to implement dynamic, globalized, and automated re-configuration on traditional network security platforms. The industry has been trying to introduce SDN technology to overcome the challenges brought by a blurred security boundary in a virtualized network environment. SDN can direct targeted network traffic flow to a virtualized network security appliance through flow diverting and aggregating. And when a virtual machine migrates, SDN, with its global perspective and flexible programmability, can help to achieve the automated migration of relevant network security policies.
In order to solve the security isolation issues of a multi-tenant virtualization environment, tunneling technologies such as Virtual eXtensible Local Area Network (VXLAN) can be used extensively. VXLAN is an encapsulation technology that repackages layer 2 packets in a layer 3 protocol and can help solve the limitations of MAC table size and VLAN ID space found in top-of-rack (TOR) switches. Because network security appliances are often concatenated in the communication link, they must support VXLAN to handle the network traffic flowing through them. Removing and adding VXLAN headers consumes significant CPU resources and noticeably lowers network security equipment overall performance, but using an extra hardware acceleration unit to assist in VXLAN processing helps.
Encryption technology is being used more extensively in cloud computing to enhance security. As with VXLAN, processing encrypted network traffic will also consume significant CPU resources and can be better managed with an additional hardware unit to assist in the encryption and decryption process. When the CPU is relieved of these resource intensive tasks, it can better focus on the key task of performing DPI more effectively and efficiently.
Figure 2: The CSA-5100/5200 1U/2U rackmount network security platform addresses the needs of small and medium enterprises (SME) with a design targeting low- and mid-level security application scenarios. Through four IO expansion slots, up to 32 10G SFP+ ports can be provided on this platform.
Figure 3: The ADLINK CSA-7200 is designed to be a next generation network security appliance, featuring high-performance dual Intel® Xeon processor E5 v3 and up to 64x 10G SFP+ ports through eight Network Interface Modules (NIMs).
Figure 4: The ADLINK CSA-7400 is a high-performance high-density computing platform supporting four dual-processor Intel® Xeon® processor E5 v3 computes nodes interconnected by dual redundant switch modules. The CSA-7400 ensures uninterrupted service delivery through hot-swappable compute nodes and switch modules. It is ideally suited for building next generation high-performance firewalls and virtualized telecom elements.
DPI equipment computing requirements are increasing, while SDN is expected to be supported on DPI equipment to enhance its functionality and adaptability. In addition, network security equipment is standardizing. To strengthen NFV, SDN, and big data technologies from open platforms, network security equipment is shifting from traditional proprietary computing platforms to open, COTS-based computing platforms. The Cyber Security Appliance (CSA) series of products from ADLINK Technology is designed and built to meet these trends and needs. By integrating the special requirements of next-generation network security appliances on open computing platforms, ADLINK's CSA products can assist network security providers in constructing services that meet DPI and cloud computing security requirements in the IoT era (Table 1).
Table 1: Rising to the needs of the IoT era, ADLINK CSA products feature high-density design to solve high-capacity and high-bandwidth network security demands. CSA solutions also introduce the latest computing and communication technologies from the open computing domain, ensuring a rich set of new features that allow users to easily meet network security challenges.
ADLINK Technology has taken great efforts to fully understand the requirements of DPI and cloud computing security in the IoT era, and introduced the CSA series of computing platforms to meet these requirements. By integrating high-performance DPI processing capability and support for NFV, SDN and hardware acceleration units, the CSA series forms a solid foundation for developing the next generation of network security equipment. CSA platforms are designed with a modular concept in order to achieve maximum intercompatibility of components across the product line and reduce TCO. ADLINK has also developed and integrated the requisite software components and open source middleware, reducing development efforts required by customers. The growth of applications in cloud computing is accelerating at a faster pace as we enter the IoT era, bringing with it an increasing number of network security threats. ADLINK Technology is committed to providing high-performance, high-availability ARiP platforms that meet the requirements of network security for industrial IoT, and will continue to analyze new trends and challenges in the network security industry, listen to customer feedback, and provide the best network security platforms built on open computing technologies.
Qizhi Zhang is System Architect for the Network & Communication Business Center, ADLINK Technology, where he is responsible for product definition, architectural design, and technical consulting for the enterprise's Network & Communication platforms. Dr. Zhang received his Ph.D. in Automation from Shanghai Jiao Tong University. With 10+ years' working experience in telecom industry, he is equipped with solid expertise in system management, high availability systems, and network security devices.
This entry was posted on Wednesday, August 23rd, 2017 at 6:26 pm and is filed under Article, Contributed.