/** * 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); } Det tar lång tid att vända en atlantångare, även i digitala farvatten! | IHM

Det tar lång tid att vända en atlantångare, även i digitala farvatten!

Hej alla, jag har under de senaste åren haft förmånen att träffa många företagare, ibland för att jag intervjuat dem, ibland som föreläsare och ibland har jag bara sprungit på dem här på IHM. Och alla pratar om digitaliseringen ur olika perspektiv.

De yngre bygger hela sin affärsidé kring digitaliseringen eller förändrar processer i redan befintliga bolag för att skapa än mer kund- och affärsnytta. De verkar i många fall ha en process klar för sig för hur de ska utveckla sin affär i samma takt som det digitala landskapet växer och förändras. Hoppas det är så!

Tittar man på de äldre jag har träffat så är medvetenheten om att något måste göras lika stor men man processar vad och hur i långsamma kvarnar, det här gäller naturligtvis inte alla, men ju större bolag desto trögare mal kvarnen, det i sig är inte så konstigt, det är mycket som ska tas till vara och värnas om i ett stort och åldrat bolag. Men…

…det är påfallande ofta jag får höra förklaringar som rubriken i det här inlägget, ”det tar tid att vända en atlantångare” eller liknande uttryck, och när jag då ställer följdfrågan; Men vad bra, då är ni iallafall igång, hur startade ni er process och hur ser den ut i just ert bolag, så finns det inga svar. Det känns som medvetandegraden om att vi står inför stora förändringar är hög, till någras stora lycka och till andras sorg, men att många inte riktigt vet var man ska börja nysta i den här härvan.

Det bekräftas också när jag pratar med David Ståhlberg, ansvarig för IHM Digital Business Transformation, han hävdar, med stöd av diverse undersökningar, att det kan vara så många som 80% av våra bolag som i princip sitter still i båten och hoppas på det bästa. Det här är djupt oroande och förödande för svenskt näringsliv på sikt och jag hoppas verkligen inte det är så illa. Så…

…jag bestämmer mig för att intervjua någon VD på ett någorlunda stort bolag för att se hur de jobbar med den här problematiken. Att det just blir en VD är inte bara för att han eller hon är kapten på skutan, det är också VD:ar som utpekas som de stora bromsklossarna tillsammans med styrelsen i många av de diskussioner jag deltagit i under åren. Efter lite funderande över vad jag har för kontakter så ringer jag upp Volvofinans VD Conny Bergström, en tidigare kund till mig, och frågar om han är intresserad. 

Volvofinans är intressant ur många perspektiv, de är ett förhållandevis gammalt bolag med start 1959, de ägs idag till 50% av Volvohandlarföreningen (alla återförsäljare av Volvo i Sverige) och till 50% av Volvo Personvagnar AB vilket förmodligen innebär stora och långsamma kvarnar? De är ett förhållandevis stort bolag med ca 200 anställda och en balansomslutning på ca 33 miljarder. De är en bank vilket förmodligen innebär en hemskt massa regler och de har i våras lanserat sin app CarPay, ett steg ut i digitala farvatten. Conny säger ja, jag är välkommen dit, perfekt, nu ska vi se hur de manövrerat sitt fartyg!

Jag slår mig ner på Connys kontor tillsammans med Roderik Jönsson, Affärsutvecklingschef på Volvofinans. Jag kommer i intervjun inte ange om det är Conny eller Roderik som svarat, för de fyller i varandras svar, diskuterar sinsemellan i en härlig diskussion, så jag hinner inte med helt enkelt, men jag börjar iallafall med Conny och sedan blir det deras samlade svar.

– Hej, jättekul att vara tillbaka i huset i en ny roll. Många pratar idag om svårigheten för äldre och stora bolag att ta sig an den digitala transformationen, man siar om att en stor del av bolagen kommer att dö och jämför gärna med Facit och Hasselblad som bevis på att stora bolag kan försvinna ganska fort. Ni är ett stort och relativt gammalt bolag, hur har ni resonerat och tagit er an de digitala utmaningarna?

– Hej, riktigt kul att se dig igen Aludd! När det gäller de digitala utmaningarna så börjar vår resa redan 2009, med bankkrisen. Det här var en jobbig och omvälvande tid där jag kände att stora delar av vår vardag gick åt till att klara de nya regel- och ramverk som kom i samband med återuppbyggnaden av ett helt nytt banksystem med inriktning på att skapa motståndskraftiga banker. Det här var en tuff tid för många bolag och slet hårt på organisationen, men när vi klev in i 2013 så ville styrelsen också att vi fokuserade på nyutveckling och vi fick kraft att tänka progressivt.

– Och vad gjorde ni då?

– Vi satte igång ett stort strategiarbete med utgångspunkten; Vad borde vi vara? Ett omfattande arbete där vi vände på alla stenar vi kunde hitta, vi tittade på hot och möjligheter, vi tittade på hur vi attraherar och utvecklar vår personal, vi värderade vårt dåvarande it-system och vi ställde oss en central fråga i; När gör vi skillnad för våra kunder, i huvudsak Volvo- och Renaultägare.

– Och vad såg ni för hot?

– Många, vi såg att digitaliseringen innebar att vi behövde nya kompetenser i bolaget, vi såg att vårt tidigare beslut att jobba med standardsystem i vår IT-utveckling inte gav oss de möjligheter vi ville för framtiden, vi såg att framtidens konsumenter kommer att använda kort i betydligt mindre omfattning, en central koppling mellan oss och våra kunder och vi såg att betalningar via mobilen ökade lavinartat. Nu skummar vi ändå bara på ytan, det här var en jobbig process och jag kände inte riktigt att vi hittade fram i de centrala frågorna; Vad borde vi vara i framtiden och när gör vi skillnad för våra kunder.

– Mycket hot och svårt att se möjligheterna?

– Ja, initialt så kändes det så. Jag tror att detta är ett vanligt problem för lite större och etablerade företag, man blir van vid det inarbetade och har svårt att se utanför sin vanliga vy.

– Och hur gick ni vidare då?

– Vi presenterade vårt arbete för styrelsen och möttes av stor förståelse, de kände nog lite precis som oss. Men de gav oss stöd att fortsätta arbetet så vi fick lite luft under vingarna och bestämde oss för att pröva lite andra sätt att komma framåt. Vi startade en projektgrupp med ca 10 personer från företaget dessutom tog vi in en del extern kompetens.

– Och då lossnade det?

– Delvis, vi fick upp mycket idéer på bordet och kom fram till en del tankar vi ville testa. Vi pratade om hur ett digitalt kort skulle se ut i mobilen och hade mycket idéer på funktioner som kunde hjälpa kunden. I det arbetet så skapades CarPay även om appen idag inte ser exakt likadan ut. 

– Du säger att det bara lossnade delvis, vad var det som kändes som ett problem?

– Vi hade mycket bra på gång men jag tror att vi också hade en ganska spretig målbild, många av hoten hade nu blivit möjligheter men vi såg nog olika på det mesta.

– Och hur löste ni det?

– Vi tog in en extern kraft som fick en genomgång i våra tankar och ett uppdrag att försöka omsätta den visionen i en film. Filmen blev kanon och då kände vi att det släppte ordentligt. Då insåg vi att vi var på rätt spår och att vi nu tillsammans kunde ta oss fram mot målet; Att skapa appen CarPay som gav den nytta som konsumenterna skulle förvänta sig av en framtida bilbank. Det var nu vi på riktigt tog steget mot att bli en bilbank för alla bilägare, och till och med en mobilbank för alla bilägare.

– Då var det bara att köra, eller?

– Ja, i princip, men vi ville att det här skulle bli riktigt bra så vi satte ihop ett internt lab, projektgruppen + personer från alla avdelningar och några externa krafter. Utgångspunkten för labbet var; Vad behöver vi för att göra detta riktigt bra? Den här processen var riktigt bra och vi rensade i vår tänkta produkt, blev enklare och såg en tydligare väg framåt. Det här arbetet presenterade vi sedan för styrelsen för att få accept på de resurser vi behövde för att få till det här ordentligt.

– Många säger ju i de här sammanhangen att den största utmaningen ligger just i att få styrelse och VD att förstå vad digitaliseringen innebär, utgångspunkten i det resonemanget är att styrelse och VD ofta är lite äldre och därför inte lever med digitaliseringen på samma sätt som de yngre. Vad säger du Roderik, som är lite yngre och varit med i den här processen hela vägen men också har en VD som fyller 57 år i år? (Här ler Conny stort)

– Jag förstår den generaliseringen, dels från mitt tidigare yrkesliv och dels från vad jag hör från vänner och kollegor. Men här har vi inte haft det problemet, Conny har ju varit IT-chef i ett av sina tidigare jobb och enligt mig har en stor förståelse för vad digitaliseringen är och kan bli.

– Tack, det värmer en gammal mans hjärta :-) Det visste du inte Aludd! Jag kan också förstå att detta är ett problem på många bolag, allt händer så fort idag. Jag förstår inte allt i detalj och tror inte det är nödvändigt, här har jag ju medarbetare som levererar expertkompetens, men jag tror att jag har en bra övergripande förståelse vilket absolut är nödvändigt idag i ledningsgruppen. Kompetens och förståelse för vad digitaliseringen innebär faller inte bara på VDn, jag tror att det handlar om att ha en ledningsgrupp som är nyfiken och vågar testa, men det måste idag definitivt finnas digital kompetens i ledningsgruppen i alla bolag.

– Ok, en guldstjärna till dig Conny :-) Men det här var ett litet sidospår, åter till er egen process. Ni har haft ett flertal labs kring er app. CarPay och fått ok från styrelsen på de resurser ni tror ni behöver, hur lång har den här processen varit?

– Processen så långt är nästan två år, men man måste förstå att det är extremt svårt, för alla bolag, att driva en kraftig utveckling samtidigt som man måste driva sin traditionella affär framåt, här är det naturligtvis ofta snabbare att driva utvecklingen i ett sidobolag eller köpa upp ett startup-bolag.

– Varför valde ni att inte göra det då?

– I vårt fall handlar det om säkerhet, vi har extremt höga krav på säkerheten som bank och ett väldigt stort regelverk som ska följas, därför så valde vi att göra detta själva och tillsammans med extern kompetens.

– Och vad blev nästa steg för att förverkliga er app?

– I början av 2015 så tar vi beslutet att appen ska lanseras inom ett år. I gamla tider skulle jag säga att det är en extrem forcering, men i den nya världen så kan det kännas långsamt, men vi behövde den tiden för att behålla vår höga säkerhetsnivå. Säkerheten, när det handlar om kundernas pengar, i den digitala världen har alltid varit viktig men i takt med att det hänt en del under åren både nationellt och internationellt så finns det en del skepsis hos kunderna, och här vill vi verkligen skapa en produkt som de kan känna sig trygga med.

– Så under 2015 sätter ni igång bygget av er app för att lansera i början av 2016, hur såg det året ut?

– Det stämmer, vår interna arbetsgrupp, förstärkt med Pär Bäck som konsult och HiQ som extern samarbetspartner sätter igång bygget. Det här blev, som beräknat, ett mastodontbygge och det blev väldigt viktigt att vi jobbade i en agil process för att vi skulle orka ta oss framåt. 

– Och om vi nu hoppar fram till 2016 så vad är det ni lanserar?

– Här måste jag poängtera att CarPay som vi lanserade är en produkt av stora förändringar vi gjort under året i bolaget och ett direkt resultat av hela den här processen, men det finns mycket mer under ytan. Carpay är en kostnadsfri app. där du får en tydlig översikt över din bilekonomi och kan se allt från saldo och korttransaktioner till sparkonton, bilens finansiering, erbjudanden och inte minst intjänad bonus. Som vi sa tidigare så har vi rensat en hel del i vad appen var från början, men dessa idéer ligger i vår utvecklingsplan. Vi höll vår tidsplan och beta-lanserade i början av 2016 för att fyra månader senare göra vår stora lansering.

– Vad hände då?

– Vi fick snabbt en bra respons och den trendade högt på iTunes och Google play under flera veckor, en dag i topp, och vi fick snabbt ca 60.000 användare. Det var en spännande tid som alla inblandade följde med stort intresse, skulle systemet hålla, fungerade allt som det skulle, vad tyckte kunderna?

Här måste vi passa på att ge en stor eloge till hela företaget som följde och rapporterade allt det hörde eller var med om själva. Och det löpte på bra, naturligtvis med personal som finkalibrerade allt eftersom vi såg hur kunderna använde appen. Kunderna var nöjda och det spred sig snabbt och efter sex månader så var vi uppe i över 140.000 användare vilket vi ser som en väldigt bra början på den här resan. 

– Ja, det låter väldigt bra och jag tackar för att ni delat med er av er resa och hoppas det stärker några andra bolag i deras digitala process. Till sist vill jag bara fråga om det är något ni själva vill lägga till?

– Tack själv. Det man skulle kunna lägga till är att man måste vara ödmjuk på en sådan här resa, för det är svårt och det slukar resurser, men hittar man rätt så är det underbart. 

När vi skiljs åt så tar jag mig en funderare, det är många jag mött genom åren som säger att det är stort och svårt att göra de förflyttningar som behövs in i en allt mer digital värld. Stunden med Conny och Roderik visar tydligt att det är en jobbig process men att det går att göra stora förändringar även i stora traditionstyngda bolag, s.k. atlantångare, riktigt spännande. Jag tror att Conny och Roderik, idag, snarare skulle vilja likna bolaget vid en speedboat, för deras utvecklingstakt har nog hamnat på en hög nivå för att stanna med tanke på allt de ska bygga på sin app. i nästa och nästa steg. Stort lycka till!

Aludd

PS Vill du testa appen så laddar du ner den här på iTunes och här på Google Play.

12 december 2016
David Ståhlberg är djupt imponerad. Varför?
Läs Petter Løkens senaste blogginlägg