Možnosti krmarjenja za SharePoint Online

Pomembno : Besedilo članka je prevedeno strojno. Glejte zavrnitev odgovornosti. Angleško različico tega članka najdete tukaj .

V tem članku je opisano, kako izboljšate čas nalaganja strani v storitvi SharePoint Online, in sicer s strukturnim krmarjenjem in krmarjenjem, ki temelji na iskanju.

Zaradi globalnega krmarjenja in poizvedb, ki jih potrebujete za ustvarjanje strukturnega krmarjenja, se lahko strani v storitvi SharePoint Online nalagajo počasneje. Do tega pride, ker vsaka od teh poizvedb pošlje v strežnik SQL še eno zahtevo. Za vsako vaše mesto ali podmesto je poslanih več zahtev v strežnik SQL. Ta težava vpliva tudi na strani z matrico. To pomeni, da vpliva tudi na globalno krmarjenje.

Nekatera SharePointova mesta zahtevajo velike in zapletene strukture. Uporaba vnaprej nastavljenega strukturnega krmarjenja, ki uporablja vsebino s poizvedbo, lahko povzroči počasno nalaganje strani zaradi več plasti mesta. Vsaka plast podmest ustvari dodatno poizvedbo.

V SharePointu sta na voljo dve glavni možnosti vnaprej nastavljenega krmarjenja ter tretji pristop po meri, ki temelji na iskanju. Vsaka možnost ima prednosti in slabosti, ki so opisane v spodnji tabeli.

Strukturno krmarjenje

Upravljano krmarjenje

Krmarjenje, ki temelji na iskanju

Prednosti:

  • Preprosta konfiguracija

  • Varnostne omejitve

  • Samodejno se posodobi, ko so dodana mesta

Prednosti:

  • Preprosto vzdrževanje

Prednosti:

  • Varnostne omejitve

  • Samodejno se posodobi, ko so dodana mesta

  • Hitro nalaganje in struktura z lokalno predpomnjenim krmarjenjem

Slabosti:

  • Počasno delovanje pri zapleteni strukturi mest

Slabosti:

  • Ne posodablja samodejno strukture mesta

Slabosti:

  • Ni možnosti za preprosto razporejanje mest

  • Zahteva prilagoditev strani z matrico (obvezno tehnično znanje)

Če ima vaše mesto veliko podmest in uporabljate strukturno krmarjenje, lahko to znatno upočasni nalaganje strani. Najprimernejša možnost za vaše mesto je odvisna od vaših zahtev na mestu in od vašega tehničnega znanja. Če ste seznanjeni z uporabo strani z matrico po meri in znate v organizaciji ohranjati spremembe, do katerih lahko pride na privzeti strani z matrico za SharePoint Online, boste najboljšo uporabniško izkušnjo dosegli z možnostjo, ki temelji na iskanju. Če želite izbrati preprosto srednjo pot med vnaprej nastavljenim strukturnim krmarjenjem in iskanjem, vam priporočamo upravljano krmarjenje. Upravljano krmarjenje lahko vzdržujete s konfiguracijo, pri tem vam ni treba uporabljati datotek s prilagoditvami kode in je bistveno hitrejše kot vnaprej nastavljeno strukturno krmarjenje.

Še ena možnost je, da prestrukturirate obstoječe mesto in zmanjšate število potrebnih elementov in podmest za krmarjenje. Vzrok za to je, da strukturno krmarjenje dobro deluje, če struktura mesta in krmarjenje po njem nista preveč zapletena.

V tem članku so primerjave različnih pristopov na primeru zbirke mest. Vzorčna zbirka mest ima 11 podmest in vsako podmesto ima najmanj štiri dodatna podmesta.

Posnetek zaslona, na katerem so prikazana mesta in podmesta

Uporaba strukturnega krmarjenja v storitvi SharePoint Online

To je privzeto vnaprej nastavljeno krmarjenje, ki je v večini primerov najenostavnejša in najprimernejša rešitev. Strukturno krmarjenje ponavadi dobro deluje, razen če je struktura mesta zapletena in vključuje več podmest ali številne ravni podmest. Glavne prednosti tega pristopa so, da ima varnostne omejitve, se samodejno posodobi, ko so dodana nova mesta, in ne zahteva prilagajanja strani z matrico. Poleg tega lahko uporabniki brez tehničnega znanja zlahka dodajajo in skrivajo elemente ter upravljajo krmarjenje na strani z nastavitvami.

Vklop strukturnega krmarjenja v storitvi SharePoint Online

Prikazano je delovanje strukturnega krmarjenja v standardni rešitvi storitve SharePoint Online, v kateri je vklopljena možnost prikaza podmest. V nadaljevanju je posnetek zaslona z nastavitvami, ki so na voljo na strani Nastavitve mesta > Krmarjenje.

Posnetek zaslona, na katerem so prikazana podmesta

Analiza delovanja strukturnega krmarjenja v storitvi SharePoint Online

Če želite analizirati učinkovitost delovanja SharePointove strani, uporabite zavihek Omrežje v orodjih za razvijalce F12 v brskalniku Internet Explorer.

Posnetek zaslona, na katerem je prikazan zavihek »Omrežje«, ki ga odprete s tipko F12 z orodji za razvijalce

Na zavihku Omrežje kliknite stran .aspx, ki se nalaga, in nato kliknite zavihek Podrobnosti.

Posnetek zaslona, na katerem je prikazan zavihek »Podrobnosti«

Kliknite Glave odzivov.

Posnetek zaslona zavihka »Podrobnosti«

SharePoint v glavah za odgovor vrne nekaj uporabnih diagnostičnih informacij. Ena od najbolj uporabnih je SPRequestDuration   , ki je vrednost v milisekundah, koliko časa je trajala obdelava zahteve v strežniku.

Na spodnjem posnetku zaslona je možnost Pokaži podmesta počiščena za strukturno krmarjenje. To pomeni, da je na voljo le povezava zbirke mest v globalnem krmarjenju:

Posnetek zaslona, na katerem so prikazani časi nalaganja kot trajanje zahteve

Ključ SPRequestDuration    ima vrednost 245 milisekund. To predstavlja trajanje vrnitve zahteve. Na mestu obstaja le en element za krmarjenje, zato je to dober primerjalni test za prikaz učinkovitosti delovanja storitve SharePoint Online brez obsežnega krmarjenja. Na naslednjem posnetku zaslona je prikazano, kako z dodajanjem podmest vplivamo na ta ključ.

Posnetek zaslona, na katerem je prikazano trajanje zahteve 2502 ms

Z dodajanjem podmest se je znatno povečal čas, potreben za vrnitev zahteve strani.

Prednosti uporabe običajnega strukturnega krmarjenja so, da zlahka organizirate vrstni red, skrijete spletna mesta, dodajate strani, rezultati so varnostno omejeni in nikoli ne odstopate od podprtih strani z matrico, ki se uporabljajo v storitvi SharePoint Online. Če svoje mesto pazljivo strukturirate in zmanjšate število podmest v zbirki mest, strukturno krmarjenje dobro deluje.

Uporaba upravljanega krmarjenja in upravljanih metapodatkov v storitvi SharePoint Online

Upravljano krmarjenje je druga vnaprej nastavljena možnost, s katero pridobite podobne funkcije kot pri strukturnem krmarjenju.

Prednost uporabe upravljanih metapodatkov je, da z njimi veliko hitreje pridobite podatke, kot če krmarjenje mesta zgradite z vsebino s poizvedbo. Čeprav je ta možnost veliko hitrejša, pri rezultatih ni mogoče uporabiti varnostnih omejitev. Če torej uporabnik nima dostopa do določenega mesta, bo povezava še vedno prikazana, vendar se bo prikazalo sporočilo o napaki.

Uporaba upravljanega krmarjenja in rezultatov   

Obstaja nekaj člankov na spletnem mestu TechNet o podrobnostih upravljano krmarjenje, na primer, si oglejte pregled upravljano krmarjenje v strežniku SharePoint Server 2013.

Če želite uporabiti upravljano krmarjenje, potrebujete skrbniška dovoljenja v shrambi izrazov. Če z URL-ji nastavite izraze, ki se ujemajo s strukturo zbirke mest, lahko namesto strukturnega krmarjenja uporabite upravljano krmarjenje. Na primer:

Posnetek zaslona primera »Podmesto1«

V spodnjem primeru je prikazano delovanje zapletenega krmarjenja z upravljanim krmarjenjem.

Posnetek zaslona primera »SPRequestDuration«

Pri upravljanem krmarjenju se nenehno izboljšuje učinkovitost delovanja v primerjavi s strukturnim krmarjenjem in pristopom vsebine po poizvedbi.

Uporaba odjemalskega skriptnega izvajanja z iskanjem

Z iskanjem lahko izkoristite indekse, ki se gradijo v ozadju z neprekinjenim iskanjem po vsebini. To pomeni, da ni zahtevnih poizvedb vsebine. Rezultati iskanja so pridobljeni iz indeksa in varnostno omejeni. Ta postopek je hitrejši od navadnih vsebinskih poizvedb. Če uporabljate iskanje v strukturnem krmarjenju, še posebej pri zapleteni strukturi mesta, se znatno skrajša čas nalaganja strani. Glavna prednost te možnosti iskanja v primerjavi z upravljanim krmarjenjem je, da lahko izkoristite varnostne omejitve.

Pri tem pristopu je treba tudi ustvariti stran z matrico po meri in zamenjati kodo vnaprej nastavljenega krmarjenja s kodo HTML po meri. Sledite spodnjemu postopku za zamenjavo kode za krmarjenje v datoteki seattle.html.

V tem primeru odprete datoteko seattle.html in zamenjate celoten element id=”DeltaTopNavigation” s kodo HTML po meri.

Primer: Zamenjati kodo iz polja za krmarjenje na strani z matrico

  1. Krmarite do strani Nastavitve mesta.

  2. Kliknite Strani z matrico in odpre se galerija strani z matrico.

  3. Tukaj lahko krmarite do knjižnici in prenesete datoteko seattle.master.

  4. Uredite kodo v urejevalniku besedila in izbrišite del kode na spodnjem posnetku zaslona.

    Posnetek zaslona kode »DeltaTopNavigation« za brisanje
  5. Odstranite kodo med oznakama <SharePoint:AjaxDelta id=”DeltaTopNavigation”> in <\SharePoint:AjaxDelta> ter jo zamenjajte s to kodo:

    <div id="loading">
      <!--Replace with path to loading image.-->
      <div style="background-image: url(''); height: 22px; width: 22px; ">
      </div>
    </div>
    <!-- Main Content-->
    <div id="navContainer" style="display:none">
        <div data-bind="foreach: hierarchy" class="noindex ms-core-listMenu-horizontalBox">
            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                <span class="menu-item-text" data-bind="text: item.Title">
                </span>
            </a>
            <ul id="menu" data-bind="foreach: $data.children" style="padding-left:20px">
                <li class="static dynamic-children">
                    <a class="static dynamic-children menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                        <span aria-haspopup="true" class="additional-background ms-navedit-flyoutArrow dynamic-children">
                            <span class="menu-item-text" data-bind="text: item.Title">
                            </span>
                        </span>
                    </a>
                    <ul id="menu" data-bind="foreach: children; visible: children.length>0" class="dynamic" >
                        <li class="dynamic">
                            <a class="dynamic menu-item ms-core-listMenu-item ms-displayInline ms-navedit-linkNode" data-bind="attr: { href: item.Url, title: item.Title }">
                                <span class="menu-item-text" data-bind="text: item.Title">
                                </span>
                            </a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </div>
  6. Zamenjava URL v nalaganje slike sidro oznako na začetku s povezavo do sliko v zbirki mest. Ko ste naredili spremembe, preimenujte datoteko in nato prenesite v galerijo strani z matrico. To ustvari novo datoteko .Master ogledate.

  7. Ta HTML je osnovna oznaka, v katero bodo vneseni rezultati iskanja, vrnjeni s kodo JavaScript. Če želite spremeniti vrednost za var root = “site collection URL, morate spremeniti spodnjo kodo, kot je prikazano tukaj:

    var root = “https://spperformance.sharepoint.com/sites/NavigationBySearch”;

    Celotna datoteka JavaScript je takšna:

    //Models and Namespaces
    var SPOCustom = SPOCustom || {};
    SPOCustom.Models = SPOCustom.Models || {}
    SPOCustom.Models.NavigationNode = function () {
    
        this.Url = ko.observable("");
        this.Title = ko.observable("");
        this.Parent = ko.observable("");
    
    };
    
    var root = "https://spperformance.sharepoint.com/sites/NavigationBySearch";
    var baseUrl = root + "/_api/search/query?querytext=";
    var query = baseUrl + "'contentClass=\"STS_Web\"+path:" + root + "'&trimduplicates=false&rowlimit=300";
    
    var baseRequest = {
        url: "",
        type: ""
    };
    
    
    //Parses a local object from JSON search result.
    function getNavigationFromDto(dto) {
        var item = new SPOCustom.Models.NavigationNode();
        if (dto != undefined) {
    
            var webTemplate = getSearchResultsValue(dto.Cells.results, 'WebTemplate');
    
            if (webTemplate != "APP") {
                item.Title(getSearchResultsValue(dto.Cells.results, 'Title')); //Key = Title
                item.Url(getSearchResultsValue(dto.Cells.results, 'Path')); //Key = Path
                item.Parent(getSearchResultsValue(dto.Cells.results, 'ParentLink')); //Key = ParentLink
            }
    
        }
        return item;
    }
    
    function getSearchResultsValue(results, key) {
    
        for (i = 0; i < results.length; i++) {
            if (results[i].Key == key) {
                return results[i].Value;
            }
        }
        return null;
    }
    
    //Parse a local object from the serialized cache.
    function getNavigationFromCache(dto) {
        var item = new SPOCustom.Models.NavigationNode();
    
        if (dto != undefined) {
    
            item.Title(dto.Title);
            item.Url(dto.Url);
            item.Parent(dto.Parent);
        }
    
        return item;
    }
    
    /* create a new OData request for JSON response */
    function getRequest(endpoint) {
        var request = baseRequest;
        request.type = "GET";
        request.url = endpoint;
        request.headers = { ACCEPT: "application/json;odata=verbose" };
        return request;
    };
    
    /* Navigation Module*/
    function NavigationViewModel() {
        "use strict";
        var self = this;
        self.nodes = ko.observableArray([]);
        self.hierarchy = ko.observableArray([]);;
        self.loadNavigatioNodes = function () {
            //Check local storage for cached navigation datasource.
            var fromStorage = localStorage["nodesCache"];
            if (false) {
                var cachedNodes = JSON.parse(localStorage["nodesCache"]);
    
                if (cachedNodes && timeStamp) {
                    //Check for cache expiration. Currently set to 3 hrs.
                    var now = new Date();
                    var diff = now.getTime() - timeStamp;
                    if (Math.round(diff / (1000 * 60 * 60)) < 3) {
    
                        //return from cache.
                        var cacheResults = [];
                        $.each(cachedNodes, function (i, item) {
                            var nodeitem = getNavigationFromCache(item, true);
                            cacheResults.push(nodeitem);
                        });
    
                        self.buildHierarchy(cacheResults);
                        self.toggleView();
                        addEventsToElements();
                        return;
                    }
                }
            }
            //No cache hit, REST call required.
            self.queryRemoteInterface();
        };
    
        //Executes a REST call and builds the navigation hierarchy.
        self.queryRemoteInterface = function () {
            var oDataRequest = getRequest(query);
            $.ajax(oDataRequest).done(function (data) {
                var results = [];
                $.each(data.d.query.PrimaryQueryResult.RelevantResults.Table.Rows.results, function (i, item) {
    
                    if (i == 0) {
                        //Add root element.
                        var rootItem = new SPOCustom.Models.NavigationNode();
                        rootItem.Title("Root");
                        rootItem.Url(root);
                        rootItem.Parent(null);
                        results.push(rootItem);
                    }
                    var navItem = getNavigationFromDto(item);
                    results.push(navItem);
                });
                //Add to local cache
                localStorage["nodesCache"] = ko.toJSON(results);
    
                localStorage["nodesCachedAt"] = new Date().getTime();
                self.nodes(results);
                if (self.nodes().length > 0) {
                    var unsortedArray = self.nodes();
                    var sortedArray = unsortedArray.sort(self.sortObjectsInArray);
    
                    self.buildHierarchy(sortedArray);
                    self.toggleView();
                    addEventsToElements();
                }
            }).fail(function () {
                //Handle error here!!
                $("#loading").hide();
                $("#error").show();
            });
        };
        self.toggleView = function () {
            var navContainer = document.getElementById("navContainer");
            ko.applyBindings(self, navContainer);
            $("#loading").hide();
            $("#navContainer").show();
    
        };
        //Uses linq.js to build the navigation tree.
        self.buildHierarchy = function (enumerable) {
            self.hierarchy(Enumerable.From(enumerable).ByHierarchy(function (d) {
                return d.Parent() == null;
            }, function (parent, child) {
                if (parent.Url() == null || child.Parent() == null)
                    return false;
                return parent.Url().toUpperCase() == child.Parent().toUpperCase();
            }).ToArray());
    
            self.sortChildren(self.hierarchy()[0]);
        };
    
    
        self.sortChildren = function (parent) {
    
            // sjip processing if no children
            if (!parent || !parent.children || parent.children.length === 0) {
                return;
            }
    
            parent.children = parent.children.sort(self.sortObjectsInArray2);
    
            for (var i = 0; i < parent.children.length; i++) {
                var elem = parent.children[i];
    
                if (elem.children && elem.children.length > 0) {
                    self.sortChildren(elem);
                }
            }
        };
    
        // ByHierarchy method breaks the sorting in chrome and firefix 
        // we need to resort  as ascending
        self.sortObjectsInArray2 = function (a, b) {
            if (a.item.Title() > b.item.Title())
                return 1;
            if (a.item.Title() < b.item.Title())
                return -1;
            return 0;
        };
    
    
        self.sortObjectsInArray = function (a, b) {
            if (a.Title() > b.Title())
                return -1;
            if (a.Title() < b.Title())
                return 1;
            return 0;
        }
    }
    
    //Loads the navigation on load and binds the event handlers for mouse interaction.
    function InitCustomNav() {
        var viewModel = new NavigationViewModel();
        viewModel.loadNavigatioNodes();
    }
    
    function addEventsToElements() {
        //events.
        $("li.dynamic-children").mouseover(function () {
            var position = $(this).position();
            $(this).find("ul").css({ width: 125, left: position.left + 10, top: 50 });
    
        })
            .mouseout(function () {
                $(this).find("ul").css({ width: 0, left: -99999, top: 0 });
            });
    }
    
    _spBodyOnLoadFunctionNames.push("InitCustomNav");
    

    Če povzamemo kodo, ki je prikazan zgoraj, jQuery $(document).ready funkcije je viewModel predmet, ki je ustvaril in nato loadNavigationNodes() funkcijo na predmetu, ki se imenuje. Ta funkcija bodisi naloži že pripravljenih za krmarjenje hierarhije, ki je shranjena v shrambi HTML5 lokalnega odjemalca brskalnika ali pokliče funkcijo queryRemoteInterface().

    QueryRemoteInterface() zgradi naročilo funkcijo getRequest() parametra poizvedbe, ki so opredeljena v scenarij zgoraj in nato vrne podatke iz strežnika. Ti podatki so v bistvu matrike vsa mesta v zbirki mest, ki so predstavljene kot predmet za prenos podatkov z različnimi lastnostmi. Te podatke je nato razčlenjene v določeno SPO.Models.NavigationNode predmete, ki uporabljajo Knockout.js ustvariti opazovati lastnosti za uporabo tako, da podatke, ki so vrednosti v HTML, ki smo jo določili prej. Predmete, ki so nato pričeti rezultatov polja. Ta polja je razčlenjene v JSON z Knockout in shranjena v shrambi lokalnega brskalnika za boljše delovanje v prihodnje strani obremenitve.

  8. Nato rezultati so dodeljene self.nodes polja in hierarhije, ki je ustvarjeno iz predmetov s linq.js rezultat dodelite v matriki self.heirarchy. Ta matrika je predmet, ki je povezan s kodo HTML. To poteka v funkciji toggleView() tako, da v funkciji ko.applyBinding() samo predmet. Nato to povzroča hierarhije polja bo vezan to HTML:

    <div data-bind=”foreach: hierarchy” class=”noindex ms-core-listMenu-horizontalBox”>

    Na koncu rutine za mouseenter in mouseexit so dodani najvišje ravni krmarjenja obravnavati spustnih menijih podmesto, kar je bilo opravljeno v funkcijo addEventsToElements() .

    Rezultati krmarjenja so vidni na spodnjem posnetku zaslona:

    Posnetek zaslona rezultatov za krmarjenja

    V našem primeru zapletenega krmarjenja vidimo, da se je pri ponovnem nalaganju strani brez lokalnega predpomnjenja skrajšal čas, preživet v strežniku. Ta čas je zdaj krajši od časa iz primerjalnega testa strukturnega krmarjenja in je podoben rezultatu upravljanega krmarjenja.

    Posnetek zaslona zahteve »SPRequestDuration 301«

    Glavna prednost tega pristopa je, da se z uporabo lokalne shrambe HTML5 krmarjenje lokalno shrani za naslednjič, ko uporabnik naloži stran.

Če za strukturno krmarjenje uporabimo API iskanja, se učinkovitost delovanja bistveno izboljša; vendar pa je potrebnega nekaj tehničnega znanja za izvajanje in prilagajanje te funkcije. V tem primeru uvajanja so mesta razvrščena na enak način kot pri vnaprej nastavljenem strukturnem krmarjenju, in sicer po abecedi. Če bi želeli vrstni red spremeniti, bi bila razvijanje in vzdrževanje bolj zapletena. Poleg bi pri takšnem pristopu morali spreminjati podprte strani z matrico. Če stran z matrico po meri ni vzdrževana, mesto ne bo dobilo Microsoftovih posodobitev in izboljšav strani z matrico.

Zgoraj kodo so ti odvisnosti:

Trenutno različico LinqJS ne vsebuje ByHierarchy metodo, ki je uporabljena v zgornjih kodo in bo prekinil kodo za krmarjenje. Če želite odpraviti to težavo, dodajanje te metode Linq.js datoteko pred v vrstici »Spljoštiti: funkcija () ».

ByHierarchy: function(firstLevel, connectBy, orderBy, ascending, parent) {
     ascending = ascending == undefined ? true : ascending;
     var orderMethod = ascending == true ? 'OrderBy' : 'OrderByDescending';
     var source = this;
     firstLevel = Utils.CreateLambda(firstLevel);
     connectBy = Utils.CreateLambda(connectBy);
     orderBy = Utils.CreateLambda(orderBy);
    
     //Initiate or increase level
     var level = parent === undefined ? 1 : parent.level + 1;

    return new Enumerable(function() {
         var enumerator;
         var index = 0;

        var createLevel = function() {
                 var obj = {
                     item: enumerator.Current(),
                     level : level
                 };
                 obj.children = Enumerable.From(source).ByHierarchy(firstLevel, connectBy, orderBy, ascending, obj);
                 if (orderBy !== undefined) {
                     obj.children = obj.children[orderMethod](function(d) {
                         return orderBy(d.item); //unwrap the actual item for sort to work
                     });
                 }
                 obj.children = obj.children.ToArray();
                 Enumerable.From(obj.children).ForEach(function(child) {
                     child.getParent = function() {
                         return obj;
                     };
                 });
                 return obj;
             };

        return new IEnumerator(

        function() {
             enumerator = source.GetEnumerator();
         }, function() {
             while (enumerator.MoveNext()) {
                 var returnArr;
                 if (!parent) {
                     if (firstLevel(enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }

                } else {
                     if (connectBy(parent.item, enumerator.Current(), index++)) {
                         return this.Yield(createLevel());
                     }
                 }
             }
             return false;
         }, function() {
             Utils.Dispose(enumerator);
         })
     });
 },

Opomba : Strojni prevod – zavrnitev odgovornosti: Ta članek je bil preveden z računalniškim programom brez človeškega posredovanja. Microsoft skuša s strojno prevedenimi članki vsebino o Microsoftovih izdelkih, storitvah in tehnologijah približati osebam, ki ne razumejo angleščine. Ker je bil članek strojno preveden, so lahko v njem jezikovne, slovnične in pravopisne napake.

Razširite svoja znanja
Oglejte si izobraževanje
Prvi dobite nove funkcije
Pridružite se programu Office Insider

Vam je bila informacija v pomoč?

Zahvaljujemo se vam za povratne informacije.

Zahvaljujemo se vam za povratne informacije. Videti je, da bi vam prišla prav pomoč enega od naših Officeovih agentov za podporo.

×