When you need more than filtered results

Recently, in one of our major Coveo renderings, there was a splurge of new requirements.  Well, no huge surprise there I think.  When powerful people meet in the same room, new ideas do come by, not such a good news to us developers who have scratched their brains and pulled up hours to wrap up the initial implementation.  Although, I believe it is a good venue when time is on your side to learn something new. 🙂

This is exactly what happened to us, the requirement sounds pretty simple, but took me few hours to find an optimum solution which solves the problem, but, also would not involve too many changes to existing logic in play.
Goal –   Get all the results that match the filters(facets) selected by end user with out the default pagination applied (Coveo has default pagination and only pulls the values entered in Number of results value given on the rendering properties).   After few hours of going over Coveo documentation, I found something though completely not the same as what I was looking for, it kind of sparked the similar wave of implementation.

I almost always start a Q&A either to confirm my thoughts or to see if there are any other ways to accomplish the same.   In this case, what i was going for just felt right and Coveo team member confirmed the same.  You can follow the trail here.


So, basically to achieve what I was looking for, you need to fire a parallel query with exact same filters based on user interaction and simply change the results to an upper bound.  It would have been nice to actually set it to Totalresults, I have not tried that, but, could work when you get the value from the correct variable.

Here is a snippet –

Coveo.$(‘#<%= Model.Id %>’).on(Coveo.QueryEvents.querySuccess,function(e, args)
var query = args.query;
query.numberOfResults = 2;
//Do any other modifications on the query
Coveo.SearchEndpoint.endpoints[“default”].search(query).done(function(data) {
//do any other logic on the data up here

That is it, we have everything we need plus a handler over all results.  I am pretty sure it would come up often hopefully it helps any one else.

Happy problem solving folks. 🙂

Coveo Sorting Part 3

Hey There!

This time soon enough, I really wanted to complete my thoughts on Coveo sorting.  We so far learnt two main things from the previous posts.  How to accomplish Coveo Sorting on a typical custom coveo rendering on a sortable field and how to make sorting work when you have Coveo Tabs that list the results out.

Next step, we will learn how we can achieve the same on Java script, there are few situations where this would come in handy.  In my example, what I was trying to do is apply Coveo Sorting on a computed field.  We are all aware that a computed field is in memory and hence we do not have a GUID we could use to work around the active issue which was present on adding default sort order to Custom Coveo rendering.  With out GUID, the sorting will not work on the rendering due to the issue, this would not be a problem if you are using latest version of Coveo, but, in our case we had no option, but, to battle this challenge.

A option that you could achieve sorting via javascript was the key to successfully getting the sort to work on a sortable computed field.

Below are few resources that helped me get started.


Below is the code snippet that I plugged in my Custom Coveo View which needed the default sort order to be set


Do note that you have to set this in function, so, the properties get set properly and applied on XHR request. Mission accomplished.

Now, I covered all the ways that we applied Coveo sorting on different style components. Another cool thing I noticed if it helps some one is that even if your field is of type Date, do not use that option for Default Sort Order. Just use Field as your type and all is working as expected.

Happy Problem Solving people. Enjoy your rest of the weekend! I am actually blogging from SF airport after hogging on organic veggie quesadilla. 😉

Coveo Sorting Part 2

Hi There!

Welcome back again to my three part series of sorting with Coveo.
This time, we look more deeper in to how to make your tabs have a sorted list, below are few easy steps you will need to do make sorting work on Coveo tabs.

  1. Ensure you have a Sort Component added to your presentation.  If you do not do this step, the Default sort order you would enter on Coveo Tab Component would not work and could also lead to exceptions on console.   Read more details about Coveo Sort Component here if curious https://developers.coveo.com/display/public/JsSearch/Sort+Component;jsessionid=6D194F8CCE1AC89DDB1B92C50E446CFF
  2. See screenshot below to see how a Coveo Custom Sort View would look like.
  3. Ensure you plug in the same Default Sort Properties you have defined on your Coveo Custom Tab, which means you should match Sort Order, Field and Order exactly to same values on both your components for the sort to work fine.
 Shown below is the view of Custom Sort View that goes hand in hand with Coveo Tab
Shown below is the Sort Order Default defition on Coveo Sort View
Shown below is the Default Sort order properties on Coveo Custom Tab view. Notice how they are exactly the same, except that on the below we have to use GUID to overcome an existing bug on version of Coveo we are using.
That is it, after this steps, publish your changes and go to the page where you have coveo renderings with tabs, you will now see two things. One, your sort options will be appended to the URL by default and you can also confirm the parameters passed on the Network tab in the XHR request.
If all is well, you now have your sort order working on Coveo Custom tabs.

Coveo Sorting Part 1 – On the Rendering

Coveo provides lot of tools and places where you could provide a sort mechanism.  First things first, sort is the most important piece that goes with listing.  If the listing of search results that you are showing to end user are not sorted per either business drive or more power to user where the user could actually select how he/she wants to sort their results is the key for the user to be able to find what they are looking for.

Steps to get sorting working
  1. Firstly define which field either sitecore or computed field you are going to use as a sort field.
  2. Note that OOTB, not all fields are sortable and you will need to configure and ensure that the field you are going to base the sort on is Coveo sortable.  For example – string fields are not inherently sortable while number fields are.
  3. If the field you decided as sort field is not inherently sortable, configure it per directions listed here by Coveo documentation and rebuild your indexes.
  4. After this step, always do a sanity check on admin tool that this field has a checkbox for sortable.

Now that you have basic configuration ready, the next step is fairly simple.  Go to presentation on the template which has your coveo rendering on which you would like to apply sort.  Pull open the properties of Coveo rendering and you will see a Default Sort order section like below.  Input three parameters it looks for –
  • Default Sort Type – Field | Date | Relevancy – I found Field and Date to be extremely useful
  • Default Sort Direction – Ascending | Descending
  • Default Sort Field – You have a pick list provided by Coveo which is a searchbox where you can type and find the sortable field you are looking for.  We are using December 2016 version of Coveo which has an active bug, so, we had to use GUID as a workaround instead of using field picker. See an example on the screenshot below

After you pick everything coveo is expecting, give it a spin – Go to the page where this rendering exists and check what is happening on the query request. You should see the below two populate with the field you picked and direction you mentioned on default sort order. If you do not see this then the sort would not be working and you will have to debug further. Couple times, it is due to presentation being overridden, so try resetting it before you panic. 😱

Now, all this works beautifully if you have just the basic Coveo custom rendering on your page.  Now, how will you make sort work with tabs, how about facet ordering.  What happens when you have both going.  How about if you need to apply sort ordering on a custom or computed field.  I will post details about these scenarios soon.  More to come later….Sorting O what fun. 😆
Happy Sitecoring and have fun every one.  Between, on a side note, last month I presented at LASUG about Coveo, if you wanna to check it out here is the link to youtube video.  Post your comments.

Helix/Habitat for TDS Setup Steps

The buzz around is that Sitecore is heavily pushing for Helix/Habitat and making it a standard.  If you have not already read through the core concepts, there is some awesome documentation that can you started here on Helix concepts –
http://helix.sitecore.net/Now, once you read through this, I bet just like me you will be tempted to get a copy for yours. I use TDS for my everyday chores, so I got mine from here –

Fun fact: Habitat team maintains two trees of the sample project for Habitat, one for TDS and the default one uses Unicorn.(https://github.com/Sitecore/Habitat)

I really wanted to play with this after reading through bits and pieces of the information and would like to share my experience of setting Habitat on my local with you all.

I am ready to get started with Habitat, are you ready?

First things first,  get the repo from the Githib for TDS Habitat.  Please note, the clone URL setup on the github is not cloning the TDS version(may be not setup correctly, I will log a comment).  So, for now, please click on Download Zip instead of cloning the repo to continue with local set up.

After this step, I got some serious code on my local.   For the next step, I needed SIM which I already had on my machine, so went straight for it.  I went ahead and installed a fresh Sitecore Instance 8.2, Update 1 per recommendation.  Not sure if it is my internet connection, it did take some time. 🙂

Next step is to install webforms for marketers.  You can get this as a package specific for the sitecore version and can install through the site once it is up.  In my case here is the version needed for Sitecore 8.2, Update 1


Important point to note here – When you install WFFMModule from link above, do not think it is a sitecore package, unzip the folder and choose the one based on your server environment, mine is obviously local so I picked the basic package for install.  After zipping pick the one highlighted below when installing from Sitecore Package Installer.


After this step, please rebuild the whole solution and ensure there are no errors.  Then, right click on your solution and select deploy.  Quick note on deploy, It takes a while as there are lot of solutions and lot of items to deploy, it did time out for me once, I did a redeploy and it worked.

Login to sitecore admin(admin/b) and Publish the site.  Go to your local URL and ensure the site is up and running(screenshot below).  Now, for the next steps, I will explore the solution and excited to see what Helix/Habitat could do for us. 🙂

Sitecore Schedule Tasks – CM/CD Environment

I recently had to set up sitemap on CM/CD environment where we had the typical sitecore configuration one CM and two load balanced CD servers. 
I wanted to run some experiments to see optimal items and configuration needed to ensure both CD’s have the sitemap.xml auto generated. 
I did this because I was curious to know why folks said we need multiple same scheduled tasks one for each server node.  I was definitely positive that I can pull this off with just one scheduled task across all environments.  Turns out, I was over ambitious!
Below are the experiments I did to content my curious brain. 
Case 1 –  Only one task across all environments

My ambitious drive of making it work with just one scheduled task, in our patch file where we have the path for scheduled tasks defined which would be incorporated on showconfig, I ensured that all the servers pointed to the same path. 
For example – 
     <agent type=”Sitecore.Tasks.DatabaseAgent” method=”Run” interval=”00:10:00″             name=”Master_Database_Agent”>
        <param desc=”database”>master</param>
        <param desc=”schedule root”>/sitecore/system/tasks/schedules/CM</param>

Post this setup, all is well on CD1, the sitemap was generated and by the looks of it covered all URL’s of items in content and protocol was followed fine as well per setup. The issue is the CD2, turns out sitemap is not updated on this server. 
I checked the logs on CD2 to see if there was an error, there were none related to sitemap generation, but, one thing I did notice on the logs is that – every time I would see that the schedule specific to refreshing sitemap would come back as not due. 
In the logs, I would see entry like below – 
ManagedPoolThread #3 18:19:38 INFO  Scheduling.DatabaseAgent started. Database: liveweb
ManagedPoolThread #3 18:19:38 INFO  Examining schedules (count: 1)
ManagedPoolThread #3 18:19:38 INFO  Not due: Refresh XML Sitemap
ManagedPoolThread #3 18:19:38 INFO  Job ended: Web_Database_Agent (units processed: 1)
This would mean that every time the scheduling agent runs it finds out the task has already been run per schedule and does not run it any more. 
Case 2 –  One task per server 

Now, the case which I did not wanted to do, I always strive to avoid duplication which would mean more management and more configuration, but, I had to test and ensure load balanced servers have sitemap served properly when crawlers do their stuff. 
What I did to test this case is to duplicate the scheduled tasks one for each server, so on my master database I would have three different nodes and scheduled tasks and on each server the path on configuration would be different as well. 
On CD1 – 
 <agent type=”Sitecore.Tasks.DatabaseAgent” method=”Run” interval=”00:10:00″ name=”Web_Database_Agent”>
        <param desc=”database”>liveweb</param>
        <param desc=”schedule root”>/sitecore/system/tasks/schedules/CD1</param>
On CD2- 
<agent type=”Sitecore.Tasks.DatabaseAgent” method=”Run” interval=”00:10:00″ name=”Web_Database_Agent”>
        <param desc=”database”>liveweb</param>
        <param desc=”schedule root”>/sitecore/system/tasks/schedules/CD2</param>
 Results – 
In this scenario and setup, everything works well and servers are happily serving the most updated sitemap.xml 
So, the bottom line is,  if you want a task to run on all servers at least once and can not possibly live with running just once regardless of which server it ran on, then, we need to duplicate and there seems to be no option. 
Do you all have any other ways to make this work with no duplication of tasks when both load balanced servers are pointing to same database. (web)?
I would be super curious to know, do post comments or suggestions. 

Coveo Zero Results Issue

First, based on project requirements on Coveo version you have installed all Coveo components, hooked up your sitecore to use Coveo and all is well on Diagnostics. All components are Green.

Now, you drop or use newly and successfully built index for your search queries, you get zero results back.
Why would it return zero results, is it picking incorrect index? Are my configurations fine? Then you go the good old CES console to see if there are any errors.  Except for query returning 0 results, there are no errors.
But, I note this on the CES console –

Query (@fz95xlanguage76852==”en”) (@fz95xpath76852==3ab17f3f16be4a018105ecade4380857) (@fz95xtemplate76852==f5cc486b394c40ff8320480ec7c650a7) performed by extranetAnonymous [Sitecore Security Provider for blah-blah.com]. 0 results in 0.016 seconds.

I copied the query and ran it in Index Browser on CES Administration tool.  It did return loads of results.  So, it is not data, it is there for sure and query is correct as well.

Seems like the query was run by Anonymous user.  So, few check points to ensure this is not permissions issue.

  1. Ensure extranet/anonymous user on sitecore instance have read permissions on the content tree 
  2. Go to Index Browser and run the query above, go to any of the search results and look for permissions tab under Details.  It should show who all have access to this item.  
  3. You should see ‘Anonymous’ there.  If Anonymous is not there, that could be a problem and which is why the results come back as ‘0’.  I did not see this user in permissions and started scrambling on what I can do to fix this.  I came across the below blog 
The problem stated there looked exactly like mine.  I did the last step which is to clear caches on Details Tab under content security and once I did that, I could now see anonymous under permissions in individual documents. 
All is well and no more empty results. 
Query (@fz95xlanguage76852==”en”) (@fz95xpath76852==3ab17f3f16be4a018105ecade4380857) (@fz95xtemplate76852==f5cc486b394c40ff8320480ec7c650a7) performed by extranetAnonymous [Sitecore Security Provider for blah.com]. 203 results in 0.031 seconds.

Debugging CD issues – No matching constructor was found

Most of the times, when you set up a CD server at some point or the other.  You will see errors like ‘No matching constructor found….’
These nasty errors are hard to debug specifically if you have bunch of complex third party system’s interacting with your sitecore instance. I encountered something like this while setting up our pre-production environment with load balancer going on.  If you choose to do trial and error, these errors could take for ever to resolve.  
I applied a strategy and that seemed to get me to the problem more quickly.  Also, I felt the strategy is generic, so, it could be applied to any error similar to this kind.
So, here is the error I had to battle – 
Could not create instance of type: Sitecore.ContentSearch.LuceneProvider.LuceneIndex. No matching constructor was found.
Here are the steps I took to resolve this.  Hopefully, it will help some one scrambling for a resolve. 
Go to sitecoreinstance/sitecore/admin/showconfig.aspx and ensure there are no references to ‘master’ any where, since this is a CD after you enable Switch master to web config and you did a good job at it, you should not be seeing any references.  If you do, then, revise your config. 
After you eliminate #1, check for which constructor it is is complaining about.  In my case it was Sitecore.ContentSearch.LuceneProvider.LuceneIndex.  So, I pulled up the *.dll specific to this that comes with Sitecore installation using reflector. 
If you notice – there are three constructors I could see from what reflector has to say –  In this case the below:
protected LuceneIndex(string name);
public LuceneIndex(string name, string folder, IIndexPropertyStore propertyStore);
public LuceneIndex(string name, string folder, IIndexPropertyStore propertyStore, string group);
Next, I opened up sitecoreinstance/sitecore/admin/showconfig.aspx again and went through all entries on the config that inherit or have provider listed as Sitecore.ContentSearch.LuceneProvider.LuceneIndex to check and see if they are passing the params to adhere to one of the three the *.dll supports.  
There were only about nine references, so, it was not such a pain to see each of those to compare.  I found one entry that was not passing params per expectation.  You should also see from which patch file this entry is coming from.  Thank you Sitecore.
I deleted that entry as I did not need it as the original config file from which this index was originally defined was disabled per Sitecore set up instructions.  But, in your case if you need that entry, ensure you are passing in params that would match atleast one constructor. 
That’s all!! Error behind us and I could go back to sleep peacefully.  This strategy could be applied to any error you will face.  The fact is trial and error is not so much fun and application of clear strategy shows you understand what you are doing. 
Hope this helps someone!!!

Say Hello to Glass!!!!

Wanted to share something cool and powerful.  Not sure if you all are already aware, but, pretty awesome, so wanted to share regardless.

Goal – “To get descendants under an item in the content tree that are of specific template ID “
Many straight forward ways to achieve this. Like loading a VM on controller or a new property by casting and doing bunch of queries.
We are close to a launch and typically at this time, more code would mean more bugs and additional effort to resolve those.  I wanted to avoid this as much as possible. 

So, I tried loading what I needed through Glass like below.   That is it, Just two lines of code and everything loaded as I wished for. J
No casting, no object massaging, nothing at all.   So cool and yet so powerful.  It could come in handy for you all when working with hierarchical data.
 [SitecoreQuery(“.//*[@@templateid='{A5617868-1226-4C7F-89A7-C7355BD1532A}’]”, IsRelative = true)]
       public virtual IEnumerable<MyTemplate> itemsOfMyTemplateUnderCurrent { get; set; }

Glass documentation helped me get a clue, but, it was more about children only and also note for some reason the sample format given by Glass did not work in case of descendants atleast. 
Notice the {} around GUID of template, my second try and wohoo!!! everything loaded in the object as I needed and wished for. 

Helpful reference:

Make Coveo For Sitecore work on Authenticated Sitecore URL

You have your Sitecore Instance URL protected.  Why? Many organizations do this to protect their under development site to be indexed or even worse seen by search engines and obviously you dont want any one who knows the URL to actually access your not so ready site or worse add a reference link or something.
So, yes, it is very common to have this kind of set up on lower environments while development is in progress.  It could be to share this URL with selected Clients for UAT or content load in some cases.
You have Coveo for Sitecore installed on this Sitecore instance that you protected using IIS authentication.
The Problem – “Coveo For Sitecore will not work – Diagnostics will fail 401, Index rebuilding will not work(401 again!) and obviously your renderings will not load as Indexes are not built yet”
Solution – While scrambling for a good solution and still leave the Sitecore Instance URL protected, we actually did find more than one solution through various unrelated sources and one from Coveo team as well . 🙂

Hopefully, this will help some one who is still scrambling and unable to find a solution.  Select which way to implement and go with based on your usage of Coveo Indexes.

  1. If your project uses plain old Coveo renderings and not use Coveo Indexes from Sitecore content search – You can choose to add another IIS site on CD server and point that to the same site, use this URL(internally open and no auth) to manage your coveo indexes. 
  2. If your project accesses Coveo indexes from code and content search – #1 wont work and will cause 500(Coveo rest end point to pull index will error due to 401 again). In this case, you have two options 
    • Disable IIS basic auth and use IP whitelisting for security instead as our infrastructure thinks this is a possible
    •  Keep IIS Authentication enabled on all folders of the Sitecore instance except WebsiteCoveorest and Website/Sitecore Modules/Web/Coveo 
Have fun Sitecoring and Coveofying your search. (New word..lol)

New Items not Indexed on Coveo

New Items Not Showing Up on Coveo Indexes

You have set up everything alright.  All Coveo components are green, your search renderings show up fine on UI.  All is set! You are a rock star. 
You notice something really wierd, updates on sitecore content items show up fine on Coveo Indexes, but, new items added are not showing up on Indexes until you manually rebuild them using Indexing manager. Well, this is a problem we can not live with as we can not ask Content authors to actually rebuild indexes everytime they add a new item.  Bad solution!
Have to resolve this for sure, there is no option. 
Below are the check points I made – 
1. Check the logs for errors
2. Ensure on showconfig.aspx, Coveo index sync strategies are set up fine OOTB one’s are perfect in most cases. 
3. Check CES console for any errors
4.  No luck so far, everything looks perfect. 
5. Next resort was CES Admin Tool, I  used localhost:8081 as I was debugging on my local. 
6. Dates looked pretty off and outdated, so, I tried to turn off and turn on Live Monitoring
7. Re-opened CES console and added new item
8. Voila!!! new items now showed up on Master 
9. Published and yep showed up on Live site too. 
Problem Solved!!!!  Back to being relaxed. 🙂
I posted this on Coveo Questions and Answers too so some one else in my shoes can probably benefit. 

Coveo Facet Slider Across Two Fields

Coveo Facet Slider Across Two Fields

We had a requirement that obviously could not be achieved using OOTB Facet Slider control. 
We were aware of that and did know we need to do some customization.  Just did not realize that there wont be any to none straight forward solution. 
I came up with the below solution though was not heavily confident while re-iterating this to the team, just  felt worth a shot. 
Good news is after a lot gymnastics it did work. 
Goal –  Use Coveo Facet Slider on two fields on the same item.
Challenge – Coveo does not allow number based Multi Value Field on their Index, hidden challenge I can not base Facet Slider on a Multi Value String field either.  So, I am at wall in both directions. 
Solution – Fluke at first and reality the next 
Below are the steps I did
1. Turn off Auto Max/Min Calculation on Coveo facet slider on the layout
              We can have some livable manual entries for Max/Min on layout as they are required if not auto-generated, I will see what I can do here.
2.       Next, grab Max/Min across all Neighborhood’s under the current metro page from back end
3.       I overwrite the max/min of Coveo controls with this back end loaded Max/Min patching on to their exposed events.
4.       Now, the filtering by default could be based on only one field(our challenge) –“In our case Maximum Neighborhood Price”
5    I will have to hijack the rest api call that Coveo makes on slider change to inject this expression along with others it does, so I do not interrupt the inner workings of Slider.  Additional Detail: Used Disjunction available from Coveo query builder expressions  

Coveo facets error

Coveo Facets Error 

So, you are on September release of coveo components and you do not have tab component on your search view.  You now want to add coveo facet or the view, which was added fine, but the facet though indexed and pointing to correct field, it would either not render fine on view, what would you do ??? 
I tried doing the below…
  • Checked conside and tried to debug error 
    •  Actual Error – ‘Value can not be null or empty ‘ 
  • What value is coveo asserting for ?checked call stack,  nothing important is missing 
  • Checked Presentation Details and ensured that everything is set correctly. 
  • Dropped facet component , no error any more …??
  • Slack conversation with Coveo team , no break through!!!! They asked to check if I am not hard coding ‘Model .ID’ like plain text, but, nope we were doing things the correct way. 

What else ??? Google should have been my first resort, but I like to do basic checks first, seems like I should follow the reverse order. 

Found below link and seemed very much related, so gave it a shot.  That’s it!!!
It started working. Yippeeee!
Hope, this would help some one battling this issue and unaware that it is a known issue on September release. 
Few Screen Shots of Error for reference 

Sitecore Tagging Surprises

Sitecore tagging is immensely powerful out of the box starting Sitecore 7+.  You can tag any items( including bucketed items)
The below links will get you started on the basic features –




Now, coming to the surprises…

  1. While working with the basics,  the __Semantics field on my local sitecore instance did not look anything like the articles explain.  After some pondering,  it turns out my ‘raw’ view was checked.  So, for the multi-value search field to behave and allow selection as expected make sure this is unchecked.
  2. After adding some new tags into tag repository(),  when i go back to tagging section of my item, I did not see the newly added tags in the selection list.   This is because tagging depends and reads from indexes.  when i re-built my indexes, I could then see the new one’s
  3. Since, tagging is so dependent on indexing,  selecting a good indexing strategy is very important.  Doing this operation only as often as needed and not overdoing goes long way.
To tackle #3,  it would be handy to know the default indexing strategies on master and web databases.  For master, the default is syncMaster and for web database, the default strategy is onPublishEndAsync.   You can apply different one’s as needed, but, in our case the defaults would just do it. 
You can read more on indexing strategies available through Sitecore OOTB on the below article, Good reads. 🙂




Sitecore URL Duplication

Sitecore is amazing when it comes to how it can resolve a URL seamlessly to an item and how we can tune that based on requirements and project demands.
In most of the blogs out there – Good reads
https://jammykam.wordpress.com/2015/07/13/seo-friendly-urls-in-sitecore-prevention-is-better-than-cure/  – My Fav

you will see how you can tackle LinkManager using  to ensure you always have a good SEO friendly URL using <encodeNameReplacements> and how to avoid the side effects of this by ensuring we do not allow hyphen in item names using “InvalidItemNameChars”

Now, there are other problems we will have to deal with.  Google does not like duplicate content, which means when two URL’s yield same result, in our case render same item content.  It means it is duplication.

But, though spaces are replaced by hyphens internally, it does not do anything when user or say some refferal link some where actually has spaces
For example – www.domain.com/test%20page and www.domain.com/test%20page would yield same page/content

Not Good…Google would not like it!

So, good SEO options are either do a 404 on space version(%20) above or do a 301 re-direct.  Canononical links might help a little if you cant do both of the above.

You could also you IIS re-write rules to replace spaces with ‘-‘ instead of %20

Wait for more…