/** * Note: This file may contain artifacts of previous malicious infection. * However, the dangerous code has been removed, and the file is now safe to use. */ /** * @file * Pathologic text filter for Drupal. * * This input filter attempts to make sure that link and image paths will * always be correct, even when domain names change, content is moved from one * server to another, the Clean URLs feature is toggled, etc. */ /** * Implements hook_filter_info(). */ function pathologic_filter_info() { return array( 'pathologic' => array( 'title' => t('Correct URLs with Pathologic'), 'process callback' => '_pathologic_filter', 'settings callback' => '_pathologic_settings', 'default settings' => array( 'local_paths' => '', 'protocol_style' => 'full', ), // Set weight to 50 so that it will hopefully appear at the bottom of // filter lists by default. 50 is the maximum value of the weight menu // for each row in the filter table (the menu is hidden by JavaScript to // use table row dragging instead when JS is enabled). 'weight' => 50, ) ); } /** * Settings callback for Pathologic. */ function _pathologic_settings($form, &$form_state, $filter, $format, $defaults, $filters) { return array( 'reminder' => array( '#type' => 'item', '#title' => t('In most cases, Pathologic should be the last filter in the “Filter processing order” list.'), '#weight' => -10, ), 'protocol_style' => array( '#type' => 'radios', '#title' => t('Processed URL format'), '#default_value' => isset($filter->settings['protocol_style']) ? $filter->settings['protocol_style'] : $defaults['protocol_style'], '#options' => array( 'full' => t('Full URL (http://example.com/foo/bar)'), 'proto-rel' => t('Protocol relative URL (//example.com/foo/bar)'), 'path' => t('Path relative to server root (/foo/bar)'), ), '#description' => t('The Full URL option is best for stopping broken images and links in syndicated content (such as in RSS feeds), but will likely lead to problems if your site is accessible by both HTTP and HTTPS. Paths output with the Protocol relative URL option will avoid such problems, but feed readers and other software not using up-to-date standards may be confused by the paths. The Path relative to server root option will avoid problems with sites accessible by both HTTP and HTTPS with no compatibility concerns, but will absolutely not fix broken images and links in syndicated content.'), '#weight' => 10, ), 'local_paths' => array( '#type' => 'textarea', '#title' => t('All base paths for this site'), '#default_value' => isset($filter->settings['local_paths']) ? $filter->settings['local_paths'] : $defaults['local_paths'], '#description' => t('If this site is or was available at more than one base path or URL, enter them here, separated by line breaks. For example, if this site is live at http://example.com/ but has a staging version at http://dev.example.org/staging/, you would enter both those URLs here. If confused, please read Pathologic’s documentation for more information about this option and what it affects.', array('!docs' => 'http://drupal.org/node/257026')), '#weight' => 20, ), ); } /** * Pathologic filter callback. * * Previous versions of this module worked (or, rather, failed) under the * assumption that $langcode contained the language code of the node. Sadly, * this isn't the case. * @see http://drupal.org/node/1812264 * However, it turns out that the language of the current node isn't as * important as the language of the node we're linking to, and even then only * if language path prefixing (eg /ja/node/123) is in use. REMEMBER THIS IN THE * FUTURE, ALBRIGHT. * * @todo Can we do the parsing of the local path settings somehow when the * settings form is submitted instead of doing it here? */ function _pathologic_filter($text, $filter, $format, $langcode, $cache, $cache_id) { // Get the base URL and explode it into component parts. We add these parts // to the exploded local paths settings later. global $base_url; $base_url_parts = parse_url($base_url . '/'); // Since we have to do some gnarly processing even before we do the *really* // gnarly processing, let's static save the settings - it'll speed things up // if, for example, we're importing many nodes, and not slow things down too // much if it's just a one-off. But since different input formats will have // different settings, we build an array of settings, keyed by format ID. $settings = &drupal_static(__FUNCTION__, array()); if (!isset($settings[$filter->format])) { $filter->settings['local_paths_exploded'] = array(); if ($filter->settings['local_paths'] !== '') { // Build an array of the exploded local paths for this format's settings. // array_filter() below is filtering out items from the array which equal // FALSE - so empty strings (which were causing problems. // @see http://drupal.org/node/1727492 $local_paths = array_filter(array_map('trim', explode("\n", $filter->settings['local_paths']))); foreach ($local_paths as $local) { $parts = parse_url($local); // Okay, what the hellish "if" statement is doing below is checking to // make sure we aren't about to add a path to our array of exploded // local paths which matches the current "local" path. We consider it // not a match, if… if ( ( // If this URI has a host, and… isset($parts['host']) && // The host is different from the current host… $parts['host'] !== $base_url_parts['host'] ) || // Or… ( // The URI doesn't have a host… !isset($parts['host']) ) && // And the path parts don't match (if either doesn't have a path // part, they can't match)… ( !isset($parts['path']) || !isset($base_url_parts['path']) || $parts['path'] !== $base_url_parts['path'] ) ) { // Add it to the list. $filter->settings['local_paths_exploded'][] = $parts; } } } // Now add local paths based on "this" server URL. $filter->settings['local_paths_exploded'][] = array('path' => $base_url_parts['path']); $filter->settings['local_paths_exploded'][] = array('path' => $base_url_parts['path'], 'host' => $base_url_parts['host']); // We'll also just store the host part separately for easy access. $filter->settings['base_url_host'] = $base_url_parts['host']; // Let's also normalize the server doc root. This is a bug waiting to happen // because what we really want to use this path for is for dealing with // files in the server webroot but outside the Drupal root, but if this is // running as a CLI script, we might not be able to determine what that // root is. In that case, we'll use the Drupal root. // @see http://drupal.org/node/1780398 $filter->settings['docroot'] = (drupal_is_cli() || !isset($_SERVER) || !isset($_SERVER['DOCUMENT_ROOT'])) ? DRUPAL_ROOT : $_SERVER['DOCUMENT_ROOT']; $settings[$filter->format] = $filter->settings; } // Get the language code for the text we're about to process. $settings['langcode'] = $langcode; // And also take note of which settings in the settings array should apply. $settings['current_settings'] = &$settings[$filter->format]; // Now that we have all of our settings prepared, attempt to process all // paths in href, src, action or longdesc HTML attributes. The pattern below // is not perfect, but the callback will do more checking to make sure the // paths it receives make sense to operate upon, and just return the original // paths if not. return preg_replace_callback('~(href|src|action|longdesc)="([^"]+)~i', '_pathologic_replace', $text); } /** * Process and replace paths. preg_replace_callback() callback. */ function _pathologic_replace($matches) { // Get the settings for the filter. Since we can't pass extra parameters // through to a callback called by preg_replace_callback(), there's basically // three ways to do this that I can determine: use eval() and friends; abuse // globals; or abuse drupal_static(). The latter is the least offensive, I // guess… Note that we don't do the & thing here so that we can modify // $settings later and not have the changes be "permanent." $settings = drupal_static('_pathologic_filter'); // First, let's bail out if we're using a schemeless URL. // @see http://drupal.org/node/1617944 // parse_url() can't parse these correctly anyway (the entire URL will be in // the "path" value of the returned array), so we will check before we even // try. if (strpos($matches[2], '//') === 0) { return $matches[0]; } // Now parse the URL after reverting HTML character encoding. // @see http://drupal.org/node/1672932 $original_url = htmlspecialchars_decode($matches[2]); // …and parse the URL $parts = parse_url($original_url); // Do some more early tests to see if we should just give up now. if ( // If parse_url() failed, give up. $parts === FALSE // If there's a scheme part and it doesn't look useful, bail out. // "files" and "internal" are for Path Filter compatibility. || (isset($parts['scheme']) && !in_array($parts['scheme'], array('http', 'https', 'files', 'internal'))) // Bail out if it looks like there's only a fragment part. || (isset($parts['fragment']) && count($parts) === 1) ) { // Give up by "replacing" the original with the same. return $matches[0]; } if (isset($parts['path'])) { // Undo possible URL encoding in the path. // @see http://drupal.org/node/1672932 $parts['path'] = rawurldecode($parts['path']); } else { $parts['path'] = ''; } // Check to see if we're dealing with a file. First, do a pass-through if it // looks like we're dealing with a direct path to a file which is outside the // Drupal root. Use realpath() and the server's (?) docroot to iron out // wrinkles to the file's actual path. // @see http://drupal.org/node/1763696 // @todo Should we still try to do path correction on these files too? $filepath = realpath($settings['current_settings']['docroot'] . '/' . $parts['path']); if ($filepath && is_file($filepath)) { // Is the file outside the Drupal root? if (strpos($filepath, DRUPAL_ROOT) !== 0) { return $matches[0]; } else { // Linking to a file inside the Drupal root. Okay. $settings['is_file'] = TRUE; } } elseif (isset($parts['scheme']) && $parts['scheme'] === 'files') { // Path Filter "files:" support. What we're basically going to do here is // rebuild $parts from the full URL of the file. $new_parts = parse_url(file_create_url(file_default_scheme() . '://' . $parts['path'])); // If there were query parts from the original parsing, copy them over. if (!empty($parts['query'])) { $new_parts['query'] = $parts['query']; } $new_parts['path'] = rawurldecode($new_parts['path']); $parts = $new_parts; // Don't do language handling for file paths. $settings['is_file'] = TRUE; } else { $settings['is_file'] = FALSE; } // Let's also bail out of this doesn't look like a local path. $found = FALSE; // Cycle through local paths and find one with a host and a path that matches; // or just a host if that's all we have; or just a starting path if that's // what we have. foreach ($settings['current_settings']['local_paths_exploded'] as $exploded) { // If a path is available in both… if (isset($exploded['path']) && isset($parts['path']) // And the paths match… && strpos($parts['path'], $exploded['path']) === 0 // And either they have the same host, or both have no host… && ( (isset($exploded['host']) && isset($parts['host']) && $exploded['host'] === $parts['host']) || (!isset($exploded['host']) && !isset($parts['host'])) ) ) { // Remove the shared path from the path. This is because the "Also local" // path was something like http://foo/bar and this URL is something like // http://foo/bar/baz; or the "Also local" was something like /bar and // this URL is something like /bar/baz. And we only care about the /baz // part. $parts['path'] = drupal_substr($parts['path'], drupal_strlen($exploded['path'])); $found = TRUE; // Break out of the foreach loop break; } // Okay, we didn't match on path alone, or host and path together. Can we // match on just host? Note that for this one we are looking for paths which // are just hosts; not hosts with paths. elseif ((isset($parts['host']) && !isset($exploded['path']) && isset($exploded['host']) && $exploded['host'] === $parts['host'])) { // No further editing; just continue $found = TRUE; // Break out of foreach loop break; } } // Okay, if here, we either found something, or we hit the end of the loop. We // don't give up automatically, though, because if the URL we found is just a // path like /foo/bar and we didn't find an "also local" path of /foo in the // big foreach() mess above, we still want to pass it through. if (!$found && !(isset($parts['path']) && !isset($parts['host']))) { return $matches[0]; } // Examine the query part of the URL. Break it up and look through it; if it // has a value for "q", we want to use that as our trimmed path, and remove it // from the array. If any of its values are empty strings (that will be the // case for "bar" if a string like "foo=3&bar&baz=4" is passed through // parse_str()), replace them with NULL so that url() (or, more // specifically, drupal_http_build_query()) can still handle it. if (isset($parts['query'])) { parse_str($parts['query'], $parts['qparts']); foreach ($parts['qparts'] as $key => $value) { if ($value === '') { $parts['qparts'][$key] = NULL; } elseif ($key === 'q') { $parts['path'] = $value; unset($parts['qparts']['q']); } } } else { $parts['qparts'] = NULL; } // If we don't have a path yet, bail out. if (!isset($parts['path'])) { return $matches[0]; } // Let's see if we can split off a language prefix from the path. if (!$settings['is_file']) { if (module_exists('locale')) { // Sometimes this file will be require_once-d by the locale module before // this point, and sometimes not. We require_once it ourselves to be sure. require_once DRUPAL_ROOT . '/includes/language.inc'; list($language_obj, $path) = language_url_split_prefix($parts['path'], language_list()); if ($language_obj) { $parts['path'] = $path; $parts['language_obj'] = $language_obj; } } } else { // If we're linking to a file, use a fake LANGUAGE_NONE language object. // Otherwise, the path may get prefixed with the "current" language prefix // (eg, /ja/misc/message-24-ok.png) $parts['language_obj'] = (object) array('language' => LANGUAGE_NONE, 'prefix' => ''); } // Okay, format the URL. // If there's still a slash lingering at the start of the path, chop it off. // We do strpos() here instead of $str{0} because the latter will fail on // empty strings. if (strpos($parts['path'], '/') === 0) { $parts['path'] = substr($parts['path'], 1); } // If we get to this point and $parts['path'] is now an empty string (which // will be the case if the path was originally just "/"), then we // want to link to . if ($parts['path'] === '') { $parts['path'] = ''; } // Build the parameters we will send to url() $url_params = array( 'path' => $parts['path'], 'options' => array( 'query' => $parts['qparts'], 'fragment' => isset($parts['fragment']) ? $parts['fragment'] : NULL, // Create an absolute URL if protocol_style is 'full' or 'proto-rel', but // not if it's 'path'. 'absolute' => $settings['current_settings']['protocol_style'] !== 'path', // If we seem to have found a language for the path, pass it along to // url(). Otherwise, ignore the 'language' parameter. 'language' => isset($parts['language_obj']) ? $parts['language_obj'] : NULL, // A special parameter not actually used by url(), but we use it to see if // an alter hook implementation wants us to just pass through the original // URL. 'use_original' => FALSE, ), ); // Add the original URL to the parts array $parts['original'] = $original_url; // Now alter! // @see http://drupal.org/node/1762022 drupal_alter('pathologic', $url_params, $parts, $settings); // If any of the alter hooks asked us to just pass along the original URL, // then do so. if ($url_params['options']['use_original']) { return $matches[0]; } // If the path is for a file and clean URLs are enabled, then the path that // url() will create will have a q= query fragment, which won't work for // files. To avoid that, we use this trick to temporarily turn clean URLs on. // This is horrible, but it seems to be the sanest way to do this. // @see http://drupal.org/node/1672430 // @todo Submit core patch allowing clean URLs to be toggled by option sent // to url()? if (!empty($settings['is_file'])) { $settings['orig_clean_url'] = !empty($GLOBALS['conf']['clean_url']); if (!$settings['orig_clean_url']) { $GLOBALS['conf']['clean_url'] = TRUE; } } // Now for the url() call. Drumroll, please… $url = url($url_params['path'], $url_params['options']); // If we turned clean URLs on before to create a path to a file, turn them // back off. if ($settings['is_file'] && !$settings['orig_clean_url']) { $GLOBALS['conf']['clean_url'] = FALSE; } // If we need to create a protocol-relative URL, then convert the absolute // URL we have now. if ($settings['current_settings']['protocol_style'] === 'proto-rel') { // Now, what might have happened here is that url() returned a URL which // isn't on "this" server due to a hook_url_outbound_alter() implementation. // We don't want to convert the URL in that case. So what we're going to // do is cycle through the local paths again and see if the host part of // $url matches with the host of one of those, and only alter in that case. $url_parts = parse_url($url); if (!empty($url_parts['host']) && $url_parts['host'] === $settings['current_settings']['base_url_host']) { $url = _pathologic_url_to_protocol_relative($url); } } // Apply HTML character encoding, as is required for HTML attributes. // @see http://drupal.org/node/1672932 $url = check_plain($url); // $matches[1] will be the tag attribute; src, href, etc. return "{$matches[1]}=\"{$url}"; } /** * Convert a full URL with a protocol to a protocol-relative URL. * * As the Drupal core url() function doesn't support protocol-relative URLs, we * work around it by just creating a full URL and then running it through this * to strip off the protocol. * * Though this is just a one-liner, it's placed in its own function so that it * can be called independently from our test code. */ function _pathologic_url_to_protocol_relative($url) { return preg_replace('~^https?://~', '//', $url); } ”Kan du inte leda dig själv, kan du inte leda andra” | IHM

”Kan du inte leda dig själv, kan du inte leda andra”

När man stöter på grupper med deltagare från många olika länder i IHM-huset, blir man alltid lite nyfiken. Vilka är dom, vilket företag kommer de ifrån och vad gör de på IHM? Den här gången visar det sig vara en världsberömd skjorttillverkare med huvudkontor i Borås som just nu utvecklar 36 av sina medarbetare från ett dussin olika länder inom personligt ledarskap. Jag ber ansvarig lärare att fråga om Etons vd, Hans Davidson, har lust att träffa mig och berätta mer. Glädjande nog städar Hans snabbt fram en ledig lucka i kalendern, och några dagar senare träffas vi över en thé och kaffe. Jag skulle ljuga om jag sa att jag inte förväntade mig att Hans skulle vara oklanderligt snyggt klädd, och det var han också (får man fuska med det i hans position? I så fall när? Det ska jag fråga nästa gång….).

Vi inleder med att tala om Eton som varumärke. Jag berättar för Hans att jag som har varumärkesutveckling som profession är mycket imponerad över hur Eton över decennier, genom modeväxlingar och olika politiska strömningar har lyckats bibehålla och utveckla ett starkt varumärke genom att ständigt förnya. Receptet är bra, inga unika beståndsdelar i sig, men få lyckas så väl och konsekvent med att väva samman ursprunget, stoltheten över yrkesskickligheten (och kreativ uppmärksamhet vid rätt tidpunkt) på ett sådant sätt att varumärket sakta men säkert växer sig in i det exklusiva segmentet på en internationell marknad. 

Ja, vi är noga med vårt varumärke, det är kopplat till ett val. Därför är det viktigt var och hur vi presenteras, hur prisbildshantering, utförsäljningar och bemötande hanteras i butik, på nätet och i olika världsdelar. Våra kunder vill inte att vi slarvar med detta, betonar Hans.

– Ert ursprung är ju från byn Gånghester utanför Borås som ju är en anrik textilort. Har ni kvar någon produktion där eller sys alla skjortor utomlands? 

Vi flyttade produktionen under 70-talet och förlade den utomlands. För några år sedan bestämde vi oss för att ta hem delar av produktionen, och viss del av produktionen sker i Gånghester idag. 

Hans är tredje generationen i bolaget och innan jag går över till nutid och framtid ställer jag frågan Hans säkert har fått mängder av gånger tidigare. 

– Varifrån kommer namnet Eton? 

Det var nog ganska logiskt egentligen, ler Hans. När vi i mitten på 50-talet bestämde oss för att försöka etablera oss i England så var det uppenbart att varumärket ”Skjortfabriken Special” som vi hette då, skulle bli ett hinder. När min pappa och farbror reste runt i världen på jakt efter nya tyger och material lämpade för exklusiva skjortor, hamnade de oundvikligen i England, som länge varit en världsledare av högkvalitativa tyger. Under en av dessa resor passerar de den lilla staden Eton - ett namn som har en stark lockelse hos de båda bröderna och känt för kvalitet. Man tog med sig namnet hem till Sverige där ett nytt plagg släpps: ”The Eton Shirt”, som blev en sådan succé för ”Skjortfabriken Special” att bolaget väljer namnet Eton som sitt nya namn. 

– Fortsätter Eton att växa och vilka är era mål? 

Eton växer väldigt bra nu. 2014 omsatte vi 535 Mkr och vi tror på närmare 670 Mkr 2015. Målet är att vi når 1 miljard 2018, vilket skulle innebära en dubblering på 4 år, säger Hans, och det känns som han verkligen tror att de kommer att lyckas.

– Tillväxt brukar ju kosta, hur är lönsamheten? 

Vi har fortsatt en mycket bra lönsamhet vilket naturligtvis underlättar genomförandet av expansionstakten. Förra året låg vinstmarginalen på EBITDA 17 %.

– I vilka delar av världen utvecklas Eton bäst? 

Norden går fortsatt mycket bra, Nordamerika och Tyskland utvecklas snabbt.

– Är Eton fortfarande ett familjeägt företag? 

Nej, delar av släkten är fortfarande stora delägare men största ägaren idag är Litorina Equity med 54 % av aktierna, Eton Innovation kontrollerar 35 % och Etons Management Group resterande 11 %.

– Nu över till att ni befinner er här på IHM och tar hit medarbetare från hela världen för att de ska genomgång personlig ledarutveckling. Är det alla chefer i organisationen som får gå programmet? 

Nej, det är alla medarbetare oavsett befattning, betonar Hans. 

– Hur många är ni? 

Vi är ca 170 medarbetare i 14 länder

- Berätta mer hur du tänker och varför ni gör denna satsning. 

- Det handlar egentligen om en insikt: kan man inte leda sig själv så kan man inte heller leda, eller samarbeta med, andra människor. Vi är ett internationellt bolag där många har olika värderingar, kulturer och vanor. För mig handlar det om att alla vi på Eton ska ha en gemensam plattform för beteende och förståelse.

- Efter hur lång anställningstid får nyanställda gå programmet?

- När vi ändå träffas för att tala strategi, mode och nya kollektioner, låter vi nyanställda gå steg 1 och några andra steg 2 på utbildningen. Med den här utbildningsgruppen som är igång nu, har vi har valt att förlägga ledarskapsutbildningen i samband med säljkonferenserna, då det är säljteamet som är deltagare. 

- Engagerar du dig själv i utbildningen. 

- Absolut, jag vill alltid hålla en introduktion själv med de nyanställda där jag talar om värderingar. Och så brukar jag ge alla en hemläxa som handlar om att de ska stämma av det jag har sagt med sin närmaste chef. 

- Jag kan tänka mig att denna satsning kan te sig ovanlig och annorlunda bland deltagare, även de nordiska? 

- Jo, det kan nog vara så i början, men det brukar snabbt uppfattas som något väldigt positivt. 

- Du talar om 2 steg, hur långt är programmet och hur genomförs det? 

- Det är 2 x 3 dagar som genomförs av IHMs handledare på IHM Business School i Sverige, eller så exporterar vi handledare vid behov. T ex ska en av era handledare snart åka över och utveckla vårt team i Atlanta. Som stöd för cheferna har vi tagit fram en ledarhandbok att falla tillbaka på och för att kunna repeterera. Vi vet också att verklig förändring tar 12-18 månader, så därför erbjuder vi alla chefer coaching vid minst tre tillfällen och efter behov under motsvarande tidsrymd. Detta kan ske antingen i mindre grupp eller individuellt.

- Vad är det absolut viktigaste med programmet, vad vill du att deltagarna ska få med sig? 

- Självinsikt, kunna leda sig själva, kunna leda och samarbeta med andra, förstå vikten av tydliga mål, kunna ge och ta feedback. Och ett gemensamt förhållningssätt. 

- Och på ledningsnivå då, hur följer ni upp effekten av programmet? 

- Det är en stående punkt på vår agenda. Ungefär en gång i månaden diskuterar vi utfall av beteendeförändring, eventuella avvikelser samt insatser. 

- Den här satsningen måste ju innebära en ansenlig investering för företaget. Kan ni räkna hem det ekonomiskt? 

- Tveklöst, det är värt varenda krona. 

- Hur blev det IHM?

- För flera år sedan gick en grupp från Eton ett program i situationsanpassat ledarskap där Petra Rosenberg (nu ansvarig för ledarutveckling på IHM) var vår handledare. Sedan dess har vi haft mycket stort förtroende för henne och följde med henne till IHM. 

- Få VD:ar driver denna typ av utvecklingsprojekt. Varifrån fick du din övertygelse om att understödja värderings- och förändringsarbetet med personlig ledarutveckling? 

- Jag har fått dessa insikter den hårda vägen. Som superentreprenör som alltid ville mer, snabbare och bättre, sprang jag ofta över eller förbi mina medarbetare. Det blev en mycket smärtsam insikt, som jag fick hjälp med att acceptera, och att förstå hur demotiverande mitt ledarskap var. och Det var jag själv som behövde ändra mig mest. Det blev en lång process innan jag verkligen förändrades på riktigt. Det är därför jag idag har respekt för att verklig förändring tar tid, och att vi behöver hjälpa och stödja varandra. 

- Tack Hans, det här var ett mycket intressant samtal. Är det ok om jag talar med någon av dina chefer också för att se hur de upplever satsningen på personlig utveckling och vad resultatet är i vardagen? 

- Det vill jag gärna att du gör, säger Hans entusiastiskt och ger mig direkt lite namn.

Sugen på mer läsning? Läs också Vem tror du att du är

 

5 oktober 2015
Vad kräver framtiden av dig och ditt ledarskap?
IHM Personligt ledarskap ger dig styrkan. Kom och testa oss!

Vill du ha vårt nyhetsbrev?

Tyvärr, formuläret är inte tillgängligt.
se dig i ögonen, öppna dörrar och gå utanför komfortzonen?