text:
'use strict';
/* global urlContainsParams, urlMissingParams, mockExplainOther*/
/*global describe,beforeEach,inject,it,expect*/
describe('Service: searchSvc: Solr', function () {

  // load the service's module
  beforeEach(module('o19s.splainer-search'));

  // instantiate service
  var searchSvc;
  var activeQueries;
  var $httpBackend = null;
  var fieldSpecSvc = null;
  var mockSolrUrl = 'http://example.com:1234/solr/select';
  var mockSolrParams = {
    q: ['#$query##'],
    fq: ['field:value', 'field1:value', 'field2:#$query##']
  };
  var expectedParams = angular.copy(mockSolrParams);
  var mockQueryText = 'query text';
  var mockFieldSpec = null;
  expectedParams.q[0] =   encodeURIComponent(mockQueryText);
  expectedParams.fq[2] = 'field2:' + encodeURIComponent(mockQueryText);
  var mockResults = {
    response: {
      numFound: 2,
      docs : [
        {id: 'doc1'}, {id: 'doc2'}
      ]
    }
  };

  beforeEach(inject(function($injector) {
    $httpBackend = $injector.get('$httpBackend');
  }));

  beforeEach(inject(function (_searchSvc_, _fieldSpecSvc_, _activeQueries_) {
    searchSvc     = _searchSvc_;
    fieldSpecSvc  = _fieldSpecSvc_;
    activeQueries = _activeQueries_;
    mockFieldSpec = fieldSpecSvc.createFieldSpec('field field1 hl:field2');

    activeQueries.count = 0;
  }));

  it('access solr with mock solr params using JSONP', function() {
    var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                mockSolrParams, mockQueryText);
    $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                            .respond(200, mockResults);
    searcher.search();
    $httpBackend.flush();
    $httpBackend.verifyNoOutstandingExpectation();
  });

  it('access solr with mock solr params using GET', function() {
    // By default we talk to Solr with JSONP because Solr doesn't support cors.  However, if you
    // want your Search API to look like Solr to Quepid, well, you don't need clunky JSONP.
    var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                mockSolrParams, mockQueryText, { apiMethod: 'GET' });
    $httpBackend.expectGET(urlContainsParams(mockSolrUrl, expectedParams))
                            .respond(200, mockResults);
    searcher.search();
    $httpBackend.flush();
    $httpBackend.verifyNoOutstandingExpectation();
  });

  it('tracks active queries', function() {
    expect(searchSvc.activeQueries()).toEqual(0);
    var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                mockSolrParams, mockQueryText);
    $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                            .respond(200, mockResults);
    searcher.search();
    expect(searchSvc.activeQueries()).toEqual(1);
    $httpBackend.flush();
    $httpBackend.verifyNoOutstandingExpectation();
    expect(searchSvc.activeQueries()).toEqual(0);
  });

  describe('highlights', function() {
    var fullSolrResp = {'responseHeader':{
      'status':0,
      'QTime':1,
      'params':{
          'df':'content',
          'echoParams':'all',
          'rows':'2',
          'debugQuery':'true',
          'fl':'path content',
          'indent':['true',
            'true'],
          'q':'*:*',
          'wt':'json',
        }
      },
      'response':{'numFound':100,'start':0,'docs':[
          {
            'content':'stuff',
            'path':'http://larkin.com/index/'
          },
          {
            'content':'more stuff',
            'path':'http://www.rogahnbins.com/main.html'
          }
        ]
      }
    };

    // optional highlighting part
    var highlighting = null;

    var searcher = null;

    var createSearcherHlOn = function() {
      var fieldSpec = fieldSpecSvc.createFieldSpec('id:hl:path hl:content');
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
    };

    var createSearcherHlOff = function() {
      var fieldSpec = fieldSpecSvc.createFieldSpec('id:path content');
      var noHlConfig = searchSvc.configFromDefault();
      noHlConfig.highlight = false;
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText,
                                                  noHlConfig);
    };

    var expectedHlParams = null;

    beforeEach(function() {
      highlighting ={
        'http://larkin.com/index/': {
          content: searchSvc.HIGHLIGHTING_PRE + 'highlighted larkin' + searchSvc.HIGHLIGHTING_POST,
          contentHlBold: 'highlighted larkin'
        },
        'http://www.rogahnbins.com/main.html': {
          content: searchSvc.HIGHLIGHTING_PRE + 'highlighted rogah' + searchSvc.HIGHLIGHTING_POST,
          contentHlBold: 'highlighted rogah'
        }
      };

      expectedHlParams = {'hl': ['true'],
                          'hl.simple.pre': [searchSvc.HIGHLIGHTING_PRE],
                          'hl.simple.post': [searchSvc.HIGHLIGHTING_POST],
                          'hl.fl': ['path content']};
    });

    it('asks for highlights', function() {
      createSearcherHlOn();
      var copiedResp = angular.copy(fullSolrResp);
      copiedResp.highlighting = highlighting;

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedHlParams))
                              .respond(200, copiedResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);

    });

    it('gets highlight snippet field values if returned', function() {
      createSearcherHlOn();
      var copiedResp = angular.copy(fullSolrResp);
      copiedResp.highlighting = highlighting;
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, copiedResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var solrDocs = searcher.docs;
        var docId = fullSolrResp.response.docs[0].path;
        var expectedSnip = highlighting[docId].content;
        var expectedHl = highlighting[docId].contentHlBold;
        expect(solrDocs[0].snippet(docId, 'content')).toEqual(expectedSnip);
        expect(solrDocs[0].highlight(docId, 'content', '', '')).toEqual(expectedHl);

        docId = fullSolrResp.response.docs[1].path;
        expectedSnip = highlighting[docId].content;
        expectedHl = highlighting[docId].contentHlBold;
        expect(solrDocs[1].snippet(docId, 'content')).toEqual(expectedSnip);
        expect(solrDocs[1].highlight(docId, 'content', '', '')).toEqual(expectedHl);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);
    });

    it('gets null if no highlights for field', function() {
      createSearcherHlOn();
      var copiedResp = angular.copy(fullSolrResp);
      copiedResp.highlighting = highlighting;
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, copiedResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var solrDocs = searcher.docs;
        var docId = fullSolrResp.response.docs[0].path;
        var expectedSnip = null;
        var expectedHl = null;
        expect(solrDocs[0].snippet(docId, 'some_other_field')).toEqual(expectedSnip);
        expect(solrDocs[0].highlight(docId, 'some_other_field', '', '')).toEqual(expectedHl);
        docId = fullSolrResp.response.docs[1].path;
        expectedSnip = null;
        expectedHl = null;
        expect(solrDocs[1].snippet(docId, 'yet_another_field')).toEqual(expectedSnip);
        expect(solrDocs[1].highlight(docId, 'yet_another_field', '', '')).toEqual(expectedHl);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);
    });

    it('gets null if no highlights', function() {
      createSearcherHlOn();
      var copiedResp = angular.copy(fullSolrResp);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, copiedResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var solrDocs = searcher.docs;
        var docId = fullSolrResp.response.docs[0].path;
        var expectedSnip = null;
        var expectedHl = null;
        expect(solrDocs[0].snippet(docId, 'content')).toEqual(expectedSnip);
        expect(solrDocs[0].highlight(docId, 'content', '', '')).toEqual(expectedHl);
        docId = fullSolrResp.response.docs[1].path;
        expectedSnip = null;
        expectedHl = null;
        expect(solrDocs[1].snippet(docId, 'content')).toEqual(expectedSnip);
        expect(solrDocs[1].highlight(docId, 'content', '', '')).toEqual(expectedHl);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);
    });

    it('doesnt request hls if hls off', function() {
      createSearcherHlOff();
      var copiedResp = angular.copy(fullSolrResp);
      $httpBackend.expectJSONP(urlMissingParams(mockSolrUrl, expectedHlParams))
                              .respond(200, copiedResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var solrDocs = searcher.docs;
        var docId = fullSolrResp.response.docs[0].path;
        var expectedSnip = null;
        var expectedHl = null;
        expect(solrDocs[0].snippet(docId, 'content')).toEqual(expectedSnip);
        expect(solrDocs[0].highlight(docId, 'content', '', '')).toEqual(expectedHl);
        docId = fullSolrResp.response.docs[1].path;
        expectedSnip = null;
        expectedHl = null;
        expect(solrDocs[1].snippet(docId, 'content')).toEqual(expectedSnip);
        expect(solrDocs[0].highlight(docId, 'content', '', '')).toEqual(expectedHl);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);
    });
  });

  describe('explain info ', function() {
    var fullSolrResp = {'responseHeader':{
      'status':0,
      'QTime':1,
      'params':{
          'df':'content',
          'echoParams':'all',
          'rows':'2',
          'debugQuery':'true',
          'fl':'path content',
          'indent':['true',
            'true'],
          'q':'*:*',
          'wt':'json',
        }
      },
      'response':{'numFound':100,'start':0,'docs':[
          {
            'content':'stuff',
            'path':'http://larkin.com/index/'
          },
          {
            'content':'more stuff',
            'path':'http://www.rogahnbins.com/main.html'
          }
        ]
      },
      'debug':{
          'rawquerystring':'*:*',
          'querystring':'*:*',
          'parsedquery':'MatchAllDocsQuery(*:*)',
          'parsedquery_toString':'*:*',
          'explain':{
            'http://larkin.com/index/':'\n1.0 = (MATCH) MatchAllDocsQuery, product of:\n  1.0 = queryNorm\n',
            'http://www.rogahnbins.com/main.html':'\n1.0 = (MATCH) MatchAllDucksQuery, product of:\n  1.0 = queryNorm\n'
          },
          'explainOther': {
            'http://snarkin.com/index/': mockExplainOther.l514,
            'http://ploppers.com/main.html':mockExplainOther.l71
          },
          'QParser':'LuceneQParser',
          'timing':{
            'time':11.0,
            'prepare':{
              'time':1.0,
              'query':{
                'time':1.0
              },
              'facet':{
                'time':0.0
              },
              'mlt':{
                'time':0.0
              },
              'highlight':{
                'time':0.0
              },
              'stats':{
                'time':0.0
              },
              'debug':{
                'time':0.0
              }
            },
            'process':{
              'time':6.0,
              'query':{
                'time':3.0
              },
              'facet':{
                'time':0.0
              },
              'mlt':{
                'time':0.0
              },
              'highlight':{
                'time':0.0
              },
              'stats':{
                'time':0.0
              },
              'debug':{
                'time':0.0
              }
            }
          }
        }
    };
    var fieldSpec = null;
    var searcher = null;
    var expectedDebugParams = null;

    beforeEach(function() {
      expectedDebugParams = {'debug': ['true'],
                             'debug.explain.structured': ['true']};
    });

    var createSearcherWithDebug = function() {
      fieldSpec = fieldSpecSvc.createFieldSpec('id:path content');
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
    };

    var createSearcherDebugOff = function() {
      var fieldSpec = fieldSpecSvc.createFieldSpec('id:path content');
      var noDebugConfig = searchSvc.configFromDefault();
      noDebugConfig.debug = false;
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText,
                                                  noDebugConfig);
    };

    var mockQuerqyInfolog = {
      'common_rules': [
        {
          'APPLIED_RULES': [
            "92e016b6-c2ad-4672-bb93-73791d94d6ca"
          ]
        }
      ]
    };

    var mockQuerqyDecorations = ["REDIRECT https://www.example.org/"];

    it('populates explain()', function() {
      createSearcherWithDebug();
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, fullSolrResp);
      searcher.search().then(function() {
        var solrDocs = searcher.docs;
        expect(solrDocs[0].explain('http://larkin.com/index/')).toEqual('\n1.0 = (MATCH) MatchAllDocsQuery, product of:\n  1.0 = queryNorm\n');
        expect(solrDocs[1].explain('http://www.rogahnbins.com/main.html')).toEqual('\n1.0 = (MATCH) MatchAllDucksQuery, product of:\n  1.0 = queryNorm\n');
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('populates others explained', function() {
      createSearcherWithDebug();
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, fullSolrResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var othersExplained = searcher.othersExplained;
        expect(Object.keys(othersExplained).length).toBe(2);
        expect(othersExplained.hasOwnProperty('http://snarkin.com/index/')).toBeTruthy();
        expect(othersExplained['http://snarkin.com/index/']).toEqual(mockExplainOther.l514);
        expect(othersExplained.hasOwnProperty('http://ploppers.com/main.html')).toBeTruthy();
        expect(othersExplained['http://ploppers.com/main.html']).toEqual(mockExplainOther.l71);
      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('populates parsed query details', function() {
      createSearcherWithDebug();
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, fullSolrResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var parsedQueryDetails = searcher.parsedQueryDetails;
        expect(Object.keys(parsedQueryDetails).length).toBe(5);
        expect(parsedQueryDetails['rawquerystring']).toEqual('*:*');
        expect(parsedQueryDetails['querystring']).toEqual('*:*');
        expect(parsedQueryDetails['parsedquery']).toEqual('MatchAllDocsQuery(*:*)');
        expect(parsedQueryDetails['parsedquery_toString']).toEqual('*:*');
        expect(parsedQueryDetails['QParser']).toEqual('LuceneQParser');
      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('identifies querqy.infoLogging presence and adds to parsedQueryDetails', function() {
      createSearcherWithDebug();

      var mockSolrResultsWithQuerqyInfolog = angular.copy(fullSolrResp);
      mockSolrResultsWithQuerqyInfolog['querqy.infoLog']= mockQuerqyInfolog;

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, mockSolrResultsWithQuerqyInfolog);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var parsedQueryDetails = searcher.parsedQueryDetails;
        expect(Object.keys(parsedQueryDetails).length).toBe(6);
        expect(parsedQueryDetails['rawquerystring']).toEqual('*:*');
        expect(parsedQueryDetails['querqy.infoLog']).toEqual(mockQuerqyInfolog);
      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('identifies querqy_decorations presence and adds to parsedQueryDetails', function() {
      createSearcherWithDebug();

      var mockSolrResultsWithQuerqyDecorations = angular.copy(fullSolrResp);
      mockSolrResultsWithQuerqyDecorations['querqy_decorations']= mockQuerqyDecorations;

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, mockSolrResultsWithQuerqyDecorations);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var parsedQueryDetails = searcher.parsedQueryDetails;
        expect(Object.keys(parsedQueryDetails).length).toBe(6);
        expect(parsedQueryDetails['rawquerystring']).toEqual('*:*');
        expect(parsedQueryDetails['querqy_decorations']).toEqual(mockQuerqyDecorations);
      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('populates raw query details', function() {
      createSearcherWithDebug();
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, fullSolrResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var queryDetails = searcher.queryDetails;
        expect(Object.keys(queryDetails).length).toBe(8);
        expect(queryDetails['df']).toEqual('content');
        expect(queryDetails['indent']).toEqual(['true','true']);
      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('populates query timing details', function() {
      createSearcherWithDebug();
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, fullSolrResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        var timingDetails = searcher.timingDetails;

        expect(Object.keys(timingDetails.events).length).toBe(12);
        expect(timingDetails.events[6].name).toEqual('process_query');
        expect(timingDetails.events[6].duration).toEqual(3);
      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('returns empty hash on no params', function() {
      createSearcherWithDebug();
      var copiedResp = angular.copy(fullSolrResp);
      delete copiedResp.responseHeader;
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, copiedResp);
      var called = 0;
      searcher.search().then(function() {
        called++;
        expect(searcher.queryDetails).toEqual({});

      });
      $httpBackend.flush();
      expect(called).toBe(1);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('returns null on no explain', function() {
      createSearcherWithDebug();
      var copiedResp = angular.copy(fullSolrResp);
      delete copiedResp.debug;
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, copiedResp);
      searcher.search().then(function() {
        var solrDocs = searcher.docs;
        expect(solrDocs[0].explain('http://larkin.com/index/')).toBe(null);
        expect(solrDocs[1].explain('http://www.rogahnbins.com/main.html')).toBe(null);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('doesnt request debug info when configured not to', function() {
      createSearcherDebugOff();
      var copiedResp = angular.copy(fullSolrResp);
      delete copiedResp.debug;
      $httpBackend.expectJSONP(urlMissingParams(mockSolrUrl, expectedDebugParams))
                              .respond(200, copiedResp);
      searcher.search().then(function() {
        var solrDocs = searcher.docs;
        expect(solrDocs[0].explain('http://larkin.com/index/')).toBe(null);
        expect(solrDocs[1].explain('http://www.rogahnbins.com/main.html')).toBe(null);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('handles parsing the debug json when debug is set to null versus empty array', function() {
      createSearcherWithDebug();
      var copiedResp = angular.copy(fullSolrResp);
      copiedResp.debug = null;
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, copiedResp);
      searcher.search().then(function() {
        var solrDocs = searcher.docs;
        expect(solrDocs[0].explain('http://larkin.com/index/')).toBe(null);
        expect(solrDocs[1].explain('http://www.rogahnbins.com/main.html')).toBe(null);
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });
  });

  // For tests where 'id' is not the id field
  describe('alt id field tests', function() {
    var mockResultsAltId = {
      response: {
        numFound: 2,
        docs : [
          {altId: 'alt_doc1'}, {altId: 'alt_doc2'}
        ]
      }
    };

    var fieldSpec = null;
    var searcher = null;
    beforeEach(function() {
      fieldSpec = fieldSpecSvc.createFieldSpec('id:altId');
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
    });

    it('works with an alternate id field', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResultsAltId);
      searcher.search().then(function() {
        var numDocs = searcher.numFound;
        var solrDocs = searcher.docs;
        expect(solrDocs.length).toEqual(2);
        expect(numDocs).toEqual(2);
        // sanity check on these docs
        angular.forEach(solrDocs, function(queryDoc) {
          expect(['alt_doc1', 'alt_doc2']).toContain(queryDoc.altId);
        });
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('creates docs that can construct tokens URL', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResultsAltId);
      searcher.search().then(function() {
        var numDocs = searcher.numFound;
        var solrDocs = searcher.docs;
        expect(solrDocs.length).toEqual(2);
        expect(numDocs).toEqual(2);
        // sanity check on these docs
        angular.forEach(solrDocs, function(queryDoc) {
          var generatedUrl = queryDoc._url('altId', queryDoc.altId);
          expect(generatedUrl.indexOf('q=altId:' + queryDoc.altId)).not.toBe(-1);
        });
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();

    });

    it('escapes percents in the query', function() {
      var mockSolrParamsWithMm = angular.copy(mockSolrParams);
      mockSolrParamsWithMm.mm = ['100%'];
      var expectedParamsMm = angular.copy(expectedParams);
      mockSolrParamsWithMm.mm = ['100%25'];
      var fieldSpec = fieldSpecSvc.createFieldSpec('id:altId');
      var searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParamsWithMm, mockQueryText);
      $httpBackend.expectJSONP(
        urlContainsParams(mockSolrUrl, expectedParamsMm)
      ).respond(200, mockResultsAltId);

      searcher.search();
      $httpBackend.verifyNoOutstandingExpectation();

    });
  });

  describe('encode URL', function() {
    it('encodes the url characters', function() {
      var s = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
      var e = '%20!%22%23%24%25%26\'()*%2B%2C-.%2F0123456789%3A%3B%3C%3D%3E%3F%40ABCDEFGHIJKLMNOPQRSTUVWXYZ%5B%5C%5D%5E_%60abcdefghijklmnopqrstuvwxyz%7B%7C%7D~';
      expect(e).toEqual(encodeURIComponent(s));
    });
  });

  describe('search' ,function() {
    it('passes the rows param and sets it to 10 by default', function() {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      var expectedSearchParams = angular.copy(expectedParams);
      expectedSearchParams.rows = ['10'];

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedSearchParams))
        .respond(200, mockResults);

      var called = 0;
      searcher.search().then(function() {
        called++;
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);
    });

    it('passes the rows param and sets it to what is passed in the config', function() {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText,
        { numberOfRows: 30 }
      );

      var expectedSearchParams = angular.copy(expectedParams);
      expectedSearchParams.rows = ['30'];

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedSearchParams))
        .respond(200, mockResults);

      var called = 0;
      searcher.search().then(function() {
        called++;
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
      expect(called).toBe(1);
    });

    it('makes querydocs with document url with NO facet', function() {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      $httpBackend.expectJSONP(
        urlContainsParams(mockSolrUrl, expectedParams)
       ).respond(200, mockResults);

      searcher.search().then(function() {
        var solrDocs = searcher.docs;

        // To confirm that we no longer construct a _url with facet parameters.
        var expectedFacetField = {
          'facet.field': ['field1', 'field']
        };
        angular.forEach(solrDocs, function(doc) {
          expect(urlContainsParams(mockSolrUrl, expectedFacetField).test(doc._url('id', '12'))).toBeFalsy();

          expect(doc._url('id', '12').indexOf('wt=json')).not.toBe(-1);
        });
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('escapes ids passed into url', function() {
      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search().then(function() {
        var solrDocs = searcher.docs;
        angular.forEach(solrDocs, function(doc) {
          var tokenUrl = doc._url('id', 'http://12');
          expect(tokenUrl.indexOf('http://12')).toBe(-1);
          var encId = encodeURIComponent('http\\://12');
          expect(tokenUrl.indexOf(encId)).not.toBe(-1);
        });
      });
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('linkurl has wt=json', function() {
      var fieldSpecWithScore = fieldSpecSvc.createFieldSpec('field field1 score');
      var searcher = searchSvc.createSearcher(fieldSpecWithScore, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      expect(searcher.linkUrl.indexOf('wt=json')).not.toBe(-1);
    });

    it('linkurl has wt=json even when specified as wt=xml', function() {
      var fieldSpecWithScore = fieldSpecSvc.createFieldSpec('field field1 score');
      var mockSolrParams = {
        q: ['#$query##'],
        fq: ['field:value', 'field1:value', 'field2:#$query##'],
        wt: 'xml'
      };
      var searcher = searchSvc.createSearcher(fieldSpecWithScore, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      expect(searcher.linkUrl.indexOf('wt=json')).not.toBe(-1);
    });

    it('sanitizes solr arguments', function() {
      var fieldSpecWithScore = fieldSpecSvc.createFieldSpec('field field1 score');
      var mockUncleanSolrParams = angular.copy(mockSolrParams);
      // make it filthy with these params we need to strip out!
      mockUncleanSolrParams.wt = ['xml'];
      mockUncleanSolrParams.rows = ['20'];
      mockUncleanSolrParams.debug = ['true'];
      var searcher = searchSvc.createSearcher(
        fieldSpecWithScore,
        mockSolrUrl,
        mockUncleanSolrParams,
        mockQueryText
      );
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('doesnt sanitize solr arguments when told not to', function() {
      var fieldSpecWithScore = fieldSpecSvc.createFieldSpec('field field1 score');
      var mockUncleanSolrParams = {};
      // make it filthy with these params we need to strip out!
      mockUncleanSolrParams.rows = ['20'];
      var searcher = searchSvc.createSearcher(
        fieldSpecWithScore,
        mockSolrUrl,
        mockUncleanSolrParams,
        mockQueryText,
        { sanitize: false }
      );
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, mockUncleanSolrParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('searches with fl == *', function() {
      var fieldSpec = fieldSpecSvc.createFieldSpec('*');
      var searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  {'q': ['*:*']}, mockQueryText);
      var testSolrParams = {'fl': ['*']};
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, testSolrParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('escape special chars in queryText', function() {
      var thisExpectedParams    = angular.copy(expectedParams);
      var queryWithSpecialChars = '+-!(){}[]^"~*?:\\';
      var escapedQuery          = '\\+\\-\\!\\(\\)\\{\\}\\[\\]\\^\\\"\\~\\*\\?\\:\\\\';
      thisExpectedParams.q[0]   = encodeURIComponent(escapedQuery);
      thisExpectedParams.fq[2]  = 'field2:' + encodeURIComponent(escapedQuery);

      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        queryWithSpecialChars,
        {
          escapeQuery: true,
        }
      );

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, thisExpectedParams))
        .respond(200, mockResults);

      searcher.search();

      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });
  });

  describe('group-by', function() {
    var simpleGroupedSolrResponse = {
      "responseHeader": {
        "status": 0,
        "QTime": 17
      },
      "grouped": {
        "BUS_LISTING_ID": {
          "matches": 19,
          "ngroups": 6,
          "doclist": {
            "numFound": 19,
            "start": 0,
            "docs": [{
              "id": "58356",
              "BUS_LISTING_ID": "1"
            }, {
              "id": "86192",
              "BUS_LISTING_ID": "2"
            }, {
              "id": "158752",
              "BUS_LISTING_ID": "3"
            }, {
              "id": "190993",
              "BUS_LISTING_ID": "4"
            }, {
              "id": "156334",
              "BUS_LISTING_ID": "5"
            }, {
              "id": "45291",
              "BUS_LISTING_ID": "6"
            }]
          }
        }
      },
      "facet_counts": {
        "facet_queries": {},
        "facet_fields": {
          "BUS_GROUP_ID": ["222221", 12, "168504", 2, "359033", 2, "832532", 1, "840097", 1, "956094", 1],
          "BUS_LISTING_ID": ["222221", 12, "168504", 2, "359033", 2, "832532", 1, "840097", 1, "956094", 1],
          "BUS_BUSINESS_NAME_FIRSTCHR": ["a", 16, "r", 2, "h", 1],
          "BUS_FEATURES": ["Ads", 3, "Business Hours", 3, "Business Information", 3, "Website", 3],
          "BUS_CITY_EXACT": ["Prince Albert", 13, "Beauval Forks", 2, "Saskatoon", 2, "Humboldt", 1, "Indian Head", 1],
          "BUS_HEADING_CODE": ["000000", 9, "005120", 4, "023200", 4, "018360", 1, "020350", 1],
          "BUS_HEADING_RELATED_CATEGORIES": ["Delicatessens", 8, "Halls & Auditoriums", 8, "Hotel & Motel Equipment & Supplies", 8, "Restaurant Equipment & Supplies", 8, "Hotels", 5, "Caterers", 4, "Chairs Renting", 4, "Chinese Foods", 4, "Coffee Houses", 4, "Dinner Theatres", 4, "Doughnuts", 4, "Fish & Chips", 4, "Food Products", 4, "Food Service Management & Supplies", 4, "Foods Ready To Serve", 4, "Gourmet Shops", 4, "Health Food Products", 4, "Maid Service", 4, "Night Clubs", 4, "Party Planning Service", 4, "Pizza", 4, "Restaurants", 4, "Sandwiches", 4, "Tea Rooms", 4, "Wedding Planning, Supplies & Service", 4, "Hotels & Motels Reservations Out of Town", 1, "Nursing Homes", 1]
        },
        "facet_dates": {},
        "facet_ranges": {},
        "facet_intervals": {},
        "facet_heatmaps": {}
      },
      "highlighting": {
        "58356": {},
        "86192": {},
        "158752": {},
        "190993": {},
        "156334": {},
        "45291": {}
      }
    };

    var groupedSolrResp = {
      responseHeader:{
          'status':0,
          'QTime':3
      },
        'grouped':{
          'catch_line':{
            'matches':20148,
            'groups':[{
                'groupValue':'would',
                'doclist':{'numFound':547,'start':0,'docs':[
                    {
                      'id':'l_510',
                      'catch_line':'doug put this here'}]
                }}]},
          'text':{
            'matches':20148,
            'groups':[{
                'groupValue':'would',
                'doclist':{'numFound':547,'start':0,'docs':[
                    {
                      'id':'l_11730',
                      'catch_line':'Definitions.'},
                    {
                      'id':'l_22002',
                      'catch_line':'(Effective until October 1, 2012) Frequency of inspection; scope of inspection.'},
                    {
                      'id':'l_3845',
                      'catch_line':'Alternate procedure for sale of real estate of person under disability.'}]
                }},
              {
                'groupValue':'within',
                'doclist':{'numFound':1471,'start':0,'docs':[
                    {
                      'id':'l_5780',
                      'catch_line':'Approved plan required for issuance of grading, building, or other permits; security for performance.'},
                    {
                      'id':'l_16271',
                      'catch_line':'Consultation with health regulatory boards.'},
                    {
                      'id':'l_20837',
                      'catch_line':'Powers, duties and responsibilities of the Inspector.'}]
                }}]}},
        'highlighting':{
          'l_11730':{},
          'l_22002':{},
          'l_3845':{},
          'l_5780':{},
          'l_16271':{},
          'l_20837':{}},
        'debug':{
          'rawquerystring':'*:*',
          'querystring':'*:*',
          'parsedquery':'MatchAllDocsQuery(*:*)',
          'parsedquery_toString':'*:*',
          'explain':{
            'l_11730':{
              'match':true,
              'value':1.0,
              'description':'MatchAllDocsQuery, product of:',
              'details':[{
                  'match':true,
                  'value':1.0,
                  'description':'queryNorm'}]},
            'l_22002':{
              'match':true,
              'value':1.0,
              'description':'MatchAllDocsQuery, product of:',
              'details':[{
                  'match':true,
                  'value':1.0,
                  'description':'queryNorm'}]},
            'l_3845':{
              'match':true,
              'value':1.0,
              'description':'MatchAllDocsQuery, product of:',
              'details':[{
                  'match':true,
                  'value':1.0,
                  'description':'queryNorm'}]},
            'l_5780':{
              'match':true,
              'value':1.0,
              'description':'MatchAllDocsQuery, product of:',
              'details':[{
                  'match':true,
                  'value':1.0,
                  'description':'queryNorm'}]},
            'l_16271':{
              'match':true,
              'value':1.0,
              'description':'MatchAllDocsQuery, product of:',
              'details':[{
                  'match':true,
                  'value':1.0,
                  'description':'queryNorm'}]},
            'l_20837':{
              'match':true,
              'value':1.0,
              'description':'MatchAllDocsQuery, product of:',
              'details':[{
                  'match':true,
                  'value':1.0,
                  'description':'queryNorm'}]}},
          'QParser':'LuceneQParser',
          'timing':{
            'time':3.0,
            'prepare':{
              'time':0.0,
              'query':{
                'time':0.0},
              'facet':{
                'time':0.0},
              'mlt':{
                'time':0.0},
              'highlight':{
                'time':0.0},
              'stats':{
                'time':0.0},
              'expand':{
                'time':0.0},
              'debug':{
                'time':0.0}},
            'process':{
              'time':3.0,
              'query':{
                'time':1.0},
              'facet':{
                'time':0.0},
              'mlt':{
                'time':0.0},
              'highlight':{
                'time':2.0},
              'stats':{
                'time':0.0},
              'expand':{
                'time':0.0},
              'debug':{
                'time':0.0}}}}};

    var fieldSpec = null;
    var searcher = null;

    beforeEach(function() {
      fieldSpec = fieldSpecSvc.createFieldSpec('id catch_line');
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                              mockSolrParams, mockQueryText);
    });

    it('parses an simple grouped response', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, simpleGroupedSolrResponse);
      var called = 0;
      var q = searcher.search().then(function () {
          expect(searcher.docs.length).toEqual(6);
          expect(searcher.grouped.hasOwnProperty('BUS_LISTING_ID')).toBeTruthy();
          var gpd = searcher.grouped;
          expect(gpd['BUS_LISTING_ID'][0].value).toEqual('1');
        });
      $httpBackend.flush();
    });

    it('parses a grouped response', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, groupedSolrResp);
      var called = 0;
      searcher.search()
      .then(function() {
        expect(searcher.docs.length).toEqual(7);
        expect(searcher.grouped.hasOwnProperty('text')).toBeTruthy();
        expect(searcher.grouped.hasOwnProperty('catch_line')).toBeTruthy();
        var gpd = searcher.grouped;
        expect(gpd.text[0].value).toEqual('would');
        expect(gpd.text[0].docs.length).toEqual(3);
        expect(gpd.text[0].docs[0].origin().id).toEqual('l_11730');
        expect(gpd.text[0].docs[0].group()).toEqual('would');
        expect(gpd.text[0].docs[1].origin().id).toEqual('l_22002');
        expect(gpd.text[0].docs[1].group()).toEqual('would');
        expect(gpd.text[0].docs[2].origin().id).toEqual('l_3845');
        expect(gpd.text[0].docs[2].group()).toEqual('would');
        angular.forEach(gpd.text[0].docs, function(doc) {
          expect(doc.group()).toEqual('would');
          expect(doc.groupedBy()).toEqual('text');
        });

        expect(gpd.text[1].value).toEqual('within');
        expect(gpd.text[1].docs.length).toEqual(3);
        expect(gpd.text[1].docs[0].origin().id).toEqual('l_5780');
        expect(gpd.text[1].docs[1].origin().id).toEqual('l_16271');
        expect(gpd.text[1].docs[2].origin().id).toEqual('l_20837');
        angular.forEach(gpd.text[1].docs, function(doc) {
          expect(doc.group()).toEqual('within');
          expect(doc.groupedBy()).toEqual('text');
        });

        /*jshint camelcase: false */
        angular.forEach(gpd.catch_line[0].docs, function(doc) {
          expect(doc.group()).toEqual('would');
          expect(doc.groupedBy()).toEqual('catch_line');
        });
        called++;
      });
      $httpBackend.flush();
      expect(called).toBe(1);
    });
  });

  describe('vars', function() {
    it('does full replacement', function() {
      var mockQueryText = 'burrito taco';
      var mockSolrParams = {
        q: ['#$query##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = encodeURIComponent(mockQueryText);

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('does keyword replacement', function() {
      var mockQueryText = 'burrito taco';
      var mockSolrParams = {
        q: ['#$keyword1## query #$keyword2##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = 'burrito query taco';

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('extra keyword replacements turns to empty quotes', function() {
      var mockQueryText = 'burrito taco';
      var mockSolrParams = {
        q: ['#$keyword1## query #$keyword2## nothing #$keyword3##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = 'burrito query taco nothing ""';

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('custom defaults', function() {
      var mockQueryText = 'burrito taco';
      var mockSolrParams = {
        q: ['#$keyword1## query #$keyword2## nothing #$keyword3|someDefault##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = 'burrito query taco nothing someDefault';

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('many custom defaults', function() {
      var mockQueryText = 'burrito taco';
      var mockSolrParams = {
        q: ['#$keyword1## query #$keyword2## nothing #$keyword3|someDefault## #$keyword3|otherDefaults## #$keyword2##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = 'burrito query taco nothing someDefault otherDefaults taco';

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('many custom defaults, others not customized', function() {
      var mockQueryText = 'burrito taco';
      var mockSolrParams = {
        q: ['#$keyword1## query #$keyword2## nothing #$keyword3|someDefault## #$keyword3|otherDefaults## #$keyword3## #$keyword2##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = 'burrito query taco nothing someDefault otherDefaults "" taco';

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('super long query', function() {
      var mockQueryText = 'burrito taco nacho bbq turkey donkey michelin stream of consciousness taco bell cannot run away from me crazy muhahahaa peanut';
      var mockSolrParams = {
        q: ['#$keyword1## query #$keyword2## nothing #$keyword3##'],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.q[0] = 'burrito query taco nothing nacho';

      var searcher = searchSvc.createSearcher(mockFieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, mockResults);
      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('handles all types of vars', function() {
      // Start off with a simple phrase and make sure the replacement
      // gets handled correctly here
      var mockQueryText = 'burrito taco nacho bbq turkey donkey michelin stream of consciousness taco bell cannot run away from me crazy muhahahaa peanut';
      var mockSolrParams = {
        phrase: [
          'bowl:("#$keyword1## #$keyword2##" OR "#$keyword2## #$keyword3##")'
        ],
        q: [
          '_val_:"product($texmexFunc,1)"'
        ],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.phrase[0] = 'bowl:("burrito taco" OR "taco nacho")';

      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, mockResults);

      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();

      // Add more params
      var mockSolrParams = {
        phrase: [
          'bowl:("#$keyword1## #$keyword2##" OR "#$keyword2## #$keyword3##")'
        ],
        keywords: [
          '{!edismax qf="bowl^10 sofritas" tie=1.0}#$query##'
        ],
        texmexFunc: [
          'if(query($phrase),1.5,1)'
        ],
        q: [
          '_val_:"product($texmexFunc,1)"'
        ],
        fq: [
          '{!edismax qf="bowl sofritas"}#$query##'
        ],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.phrase[0] = 'bowl:("burrito taco" OR "taco nacho")';
      expectedParams.keywords[0] = '{!edismax qf="bowl^10 sofritas" tie=1.0}' + encodeURIComponent(mockQueryText);
      expectedParams.fq[0] = '{!edismax qf="bowl sofritas"}' + encodeURIComponent(mockQueryText);

      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, mockResults);

      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();

      // Add the rest of the params
      var mockSolrParams = {
        phrase: [
          'bowl:("#$keyword1## #$keyword2##" OR "#$keyword2## #$keyword3##")'
        ],
        keywords: [
          '{!edismax qf="bowl^10 sofritas" tie=1.0}#$query##'
        ],
        phraseScore: [
          'div(product(sum(##k##,1),query($phrase)),product(query($phrase),##k##))'
        ],
        texmexFunc: [
          'if(query($phrase),1.5,1)'
        ],
        q: [
          '_val_:"product($texmexFunc,1)"'
        ],
        fq: [
          '{!edismax qf="bowl sofritas"}#$query##'
        ],
      };
      var expectedParams = angular.copy(mockSolrParams);
      expectedParams.phrase[0] = 'bowl:("burrito taco" OR "taco nacho")';
      expectedParams.keywords[0] = '{!edismax qf="bowl^10 sofritas" tie=1.0}' + encodeURIComponent(mockQueryText);
      expectedParams.fq[0] = '{!edismax qf="bowl sofritas"}' + encodeURIComponent(mockQueryText);

      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, mockResults);

      searcher.search();
      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });
  });

  describe('errors', function() {
    var fieldSpec = null;
    var searcher = null;

    beforeEach(function() {
      fieldSpec = fieldSpecSvc.createFieldSpec('id:path content');
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
    });

    it('adds searchError text', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(-1);
      var errorCnt = 0;
      searcher.search().then(function() {
        errorCnt--;
      },
      function error(msg) {
        errorCnt++;
        expect(msg.searchError.length).toBeGreaterThan(1);
      });
      $httpBackend.flush();
      expect(errorCnt).toBe(1);
    });
  });

  describe('paging', function() {
    var fullSolrResp = {'responseHeader':{
      'status':0,
      'QTime':1,
      'params':{
          'df':'content',
          'echoParams':'all',
          'rows':'2',
          'debugQuery':'true',
          'fl':'path content',
          'indent':['true',
            'true'],
          'q':'*:*',
          'wt':'json',
        }
      },
      'response':{'numFound':21,'start':0,'docs':[
          {
            'content':'stuff',
            'path':'http://larkin.com/index/'
          },
          {
            'content':'more stuff',
            'path':'http://www.rogahnbins.com/main.html'
          }
        ]
      }};

    var fieldSpec = null;
    var searcher = null;

    beforeEach(function() {
      fieldSpec = fieldSpecSvc.createFieldSpec('id:path hl:content');
      searcher = searchSvc.createSearcher(fieldSpec, mockSolrUrl,
                                                  mockSolrParams, mockQueryText);
    });

    it("does not escapes the query if escapeQuery is false", function () {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText,
        {
          escapeQuery: false,
        }
      );

      // get page 2
      var nextSearcher = searcher.pager();
      expect(nextSearcher.config.escapeQuery).toBeFalse();
    });

    it('pages on page', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                              .respond(200, fullSolrResp);
      searcher.search();
      $httpBackend.flush();

      // get page 2
      var nextSearcher = searcher.pager();
      var expectedPageParams = angular.copy(expectedParams);
      expectedPageParams.rows = ['10'];
      expectedPageParams.start = ['10'];
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedPageParams))
                              .respond(200, fullSolrResp);
      nextSearcher.search();
      $httpBackend.flush();

      // get page 3
      nextSearcher = nextSearcher.pager();
      expectedPageParams.rows = ['10'];
      expectedPageParams.start =['20'];
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedPageParams))
                              .respond(200, fullSolrResp);
      nextSearcher.search();
      $httpBackend.flush();

      // done
      nextSearcher = nextSearcher.pager();
      expect(nextSearcher).toBe(null);
    });

    it('accounts for custom rows count', function() {
      var solrRespCustRows = angular.copy(fullSolrResp)
      solrRespCustRows.response.numFound = 61;

      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText,
        { numberOfRows: 30 }
      );

      var expectedPageParams = angular.copy(expectedParams);
      expectedPageParams.rows = ['30'];

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedPageParams))
        .respond(200, solrRespCustRows);

      searcher.search();
      $httpBackend.flush();

      // get page 2
      var nextSearcher = searcher.pager();
      var expectedPageParams = angular.copy(expectedParams);
      expectedPageParams.rows = ['30'];
      expectedPageParams.start = ['30'];

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedPageParams))
        .respond(200, solrRespCustRows);

      nextSearcher.search();
      $httpBackend.flush();

      // get page 3
      nextSearcher = nextSearcher.pager();
      expectedPageParams.rows = ['30'];
      expectedPageParams.start =['60'];

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedPageParams))
        .respond(200, solrRespCustRows);

      nextSearcher.search();
      $httpBackend.flush();

      // done
      nextSearcher = nextSearcher.pager();
      expect(nextSearcher).toBe(null);
    });

    it('highlights new page', function() {
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
                  .respond(200, fullSolrResp);
      searcher.search();
      $httpBackend.flush();

      // get page 2
      var nextSearcher        = searcher.pager();
      var expectedPageParams  = angular.copy(expectedParams);

      expectedPageParams.rows       = ['10'];
      expectedPageParams.start      = ['10'];
      expectedPageParams.hl         = ['true'];
      expectedPageParams.hl.simple  = {
        pre:  [searchSvc.HIGHLIGHTING_PRE],
        post: [searchSvc.HIGHLIGHTING_POST],
      };

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedPageParams))
                              .respond(200, fullSolrResp);
      nextSearcher.search();

      $httpBackend.flush();
      $httpBackend.verifyNoOutstandingExpectation();
    });
  });

  describe('explain other', function() {
    var mockSolrResp = {
      response: {
        numFound: 2,
        docs : [
          {id: 'doc1', title: 'title1'},
          {id: 'doc2', title: 'title2'}
        ]
      }
    };

    var explOtherDoc1 = {
      match:       false,
      value:       0.0,
      description: 'no matching term'
    };

    var explOtherDoc2 = {
      match:        true,
      value:        3.3733945,
      description:  'weight(catch_line:law in 4487) [DefaultSimilarity], result of:',
      details: [
        {
          match:        true,
          value:        3.3733945,
          description:  'fieldWeight in 4487, product of:',
          details :[
            {
              match:        true,
              value:        1.0,
              description:  'tf(freq=1.0), with freq of:',
              details:[
                {
                  match:        true,
                  value:        1.0,
                  description:  'termFreq=1.0'
                }
              ]
            },
            {
              match:        true,
              value:        5.3974314,
              description:  'idf(docFreq=247, maxDocs=20148)'
            },
            {
              match:        true,
              value:        0.625,
              description:  'fieldNorm(doc=4487)'
            }
          ]
        }
      ]
    };

    var mockSolrExplOtherResp = {
      response: {
        numFound: 2,
        docs : [
          {id: 'not_doc1', title: 'title1'},
          {id: 'not_doc2', title: 'title2'}
        ]
      },
      debug: {
        explainOther: {
          'doc1': explOtherDoc1,
          'doc2': explOtherDoc2
        }
      }
    };

    it('passes two solr queries one explains the other', function() {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      var expectedParams = {
        q: ['title:doc1']
      };

      var expectedExplOtherParams = {
        explainOther: ['title:doc1']
      };

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedExplOtherParams))
        .respond(200, mockSolrExplOtherResp);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, mockSolrResp);

      searcher.explainOther('title:doc1', mockFieldSpec);

      $httpBackend.flush();

      expect(searcher.docs.length).toBe(2);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('highlights explain other', function() {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      var expectedParams = {
        q: ['title:doc1'],
        hl: ['true'],
        'hl.simple.pre': [searchSvc.HIGHLIGHTING_PRE],
        'hl.simple.post': [searchSvc.HIGHLIGHTING_POST]
      };

      var expectedExplOtherParams = {
        explainOther: ['title:doc1']
      };

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedExplOtherParams))
        .respond(200, mockSolrExplOtherResp);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, mockSolrResp);

      searcher.explainOther('title:doc1', mockFieldSpec);

      $httpBackend.flush();

      expect(searcher.docs.length).toBe(2);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('does not throw an error if both queries are empty', function () {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        ''
      );

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl))
        .respond(200, mockSolrExplOtherResp);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl))
        .respond(200, mockSolrResp);

      searcher.explainOther('', mockFieldSpec);

      $httpBackend.flush();
      expect(searcher.docs.length).toBe(2);
      $httpBackend.verifyNoOutstandingExpectation();
    });

    it('paginates for explain other seraches', function() {
      var searcher = searchSvc.createSearcher(
        mockFieldSpec,
        mockSolrUrl,
        mockSolrParams,
        mockQueryText
      );

      searcher.numFound = 100;
      searcher = searcher.pager();

      var expectedParams = {
        q:      ['title:doc1'],
        start:  ['10'],
        rows:   ['10']
      };

      var expectedExplOtherParams = {
        explainOther: ['title:doc1']
      };

      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedExplOtherParams))
        .respond(200, mockSolrExplOtherResp);
      $httpBackend.expectJSONP(urlContainsParams(mockSolrUrl, expectedParams))
        .respond(200, mockSolrResp);

      searcher.explainOther('title:doc1', mockFieldSpec);

      $httpBackend.flush();

      expect(searcher.docs.length).toBe(2);
      $httpBackend.verifyNoOutstandingExpectation();
    });
  });
});

redpajama_set_name: RedPajamaGithub


A 72-year-old woman was referred to our hospital for a persistent right upper abdominal pain after a fall three weeks prior. An ultrasound was performed. This exam demonstrated a heterogeneous cystic mass in the right hepatic lobe, just under the right hemidiaphragm, measuring 11 cm in diameter, with multiple mobile septa (Figure 1) and a hyperechogenic inferior compartment. There was no calcification and the Color Doppler US showed no Doppler signal.
A CT scan without and after contrast enhancement showed a voluminous cystic lesion of 13 × 11 × 11 cm, with regular contours occupying the right hepatic dome. However, the multiple hyperechogenic mobile septa detected on ultrasonography (Figure 2a) were not visualized, even with enhanced CT (Figure 2b). As in the ultrasound examination, there was a non-enhancing gravity-dependent hyperdensity (33 Hounsfield unit), corresponding to a blood clot (Figure 2b). These findings are typical of a hemorrhagic hepatic cyst (HHC).
An MRI performed two months after initial assessment demonstrated a significant volume decrease of this hemorrhagic cyst. Changes of the cyst content signal confirmed its hemorrhagic nature: hyperintense on T1-weighted sequences without and with fat saturation, with a fluid-fluid level (Figure 3a). On T2-weighted images, the major portion in the superior part showed an intermediate signal, whereas the lower part is hypointense, suggesting a blood clot. The cyst is surrounded by a rim of hypointensity on T2- and T2*-weighted sequences corresponding to haemosiderin (Figure 3b). After the administration of Gadolinium, there is no enhancement.
Hemorrhage into a simple hepatic cyst results in the development of a complex cystic lesion, which may be indistinguishable from a cystic tumor and, as a consequence, may result in a broad differential diagnosis, e.g. simple cysts, infectious or inflammatory conditions (hepatic abscess, amoebic hepatic abscess, hepatic hydatid cyst), neoplastic or tumorous (biliary cystadenoma or cystadenocarcinoma, cystic hepatic metastases, cystic cavernous haemangioma), and others (liquified hepatic haematoma, infected cyst, biloma).
During physiological clot lysis the presence of multiple septa and vegetations, mural nodules, and thickened cyst wall may be observed . A liquid-liquid level is possible. The principal challenge is to differentiate simple hepatic cyst complicated by intracystic hemorrhage from cystic neoplasms. US imaging plays an important role in achieving a correct diagnosis of a hemorrhagic cyst when it demonstrates the mobility of the septa. These irregular mobile septa visualized on US imaging are not found on CT. While cystadenocarcinoma is characterized by thick septa visible both on US and on CT. This discordance between US and CT findings is an important element for differential diagnosis between HHC versus cystadenocarcinoma. However, a cystic tumorous lesion may show similar findings when it is mainly composed of a cyst with prominent intracystic hemorrhage.
Contrast-enhanced US improve the sensibility showing microbubbles oozing from the cyst wall into the cyst cavity when there is intracystic bleeding and revealing no enhancement of the intracystic structures, then suggesting intracystic clot. Signal intensities and the MRI characteristic on follow-up examinations may be also helpful to demonstrate the hemorrhagic nature of a cystic lesion and to differentiate it from other mucinous cyst on MRI.
Imaging may fail to differentiate hepatic simple cysts from malignant or premalignant mucinous cystic lesions such as biliary cystadenomas. Hepatic simple cysts can be treated conservatively, whereas malignant or premalignant cysts require complete resection. The concentration of TAG-72 in cyst fluid accurately differentiate simple cyst from mucinous cysts requiring complete resection .
The therapeutic approach for HHC has varied from simple observation to more invasive approaches. HHC that are mildly symptomatic or asymptomatic can be initially treated by conservative approach with a series of imaging control to monitor the evolution. If there is a deterioration or persistence of symptoms, a laparoscopic or open de-roofing with cyst wall biopsy or enuclation is indicated. When there is spontaneous resolution, a follow-up by US is sufficient.
In conclusion, hemorrhagic hepatic simple cyst represent a difficult diagnosis because of its imaging similarities with other cystic or mucinous hepatic lesions. The mobility of septa on US imaging, when not found on CT images, is suggestive of an hemorrhagic content. Enhancement of thick septa, mural nodules or thickened wall are typically found in malignant lesions. MRI signal intensities help to differentiate hemorrhagic content of a cyst from other mucinous cyst. All these elements may lead to the accurate diagnosis and guide appropriate therapeutic decisions.
Precetti, S, Gandon, Y and Vilgrain, V (2007). Imagerie des lésions kystiques du foie. J Radiol 88: 1061–72. DOI: JR-7-8-2007-88-7-8-C2-0221-0363-101019-200702727.


text:
The Google Affiliate Network was the affiliate marketing company, specifically affiliate network, formerly known as Doubleclick Performics, which was bought by Google in 2007. On April 16, 2013, Google announced the closure of the Google Affiliate Network.

History
DoubleClick announced the acquisition of DoubleClick (including Performics) by Google for $3.1 Billion in April 2007. The acquisition was finalized in March 2008 after the approval of the Department of Justice antitrust authorities in the United States and the Brussels-based European Commission, the antitrust authority of the European Union.
The search engine marketing and optimization part of Performics was acquired by Publicis in 2008, after the purchase of DoubleClick by Google (NASDAQ: GOOG) had been finalized. The affiliate network part of DoubleClick Performics remained with Google and was re-branded Google Affiliate Network.
On April 17, 2013, Google announced plans to retire the Google Affiliate Network on July 31, 2013.

See also
Affiliate marketing
Affiliate programs directories
Affiliate network

References

External links
Google Affiliate Network Website
Google AdPlanner (beta) - Complimentary tool
Google Homepage (corporate website)

Online advertising services and affiliate networks
Affiliate marketing
Companies based in Mountain View, California
Marketing companies established in 1998

redpajama_set_name: RedPajamaWikipedia


7/1-7/7 – Jazz Maui events – Some free concerts, mostly on the West Side. Free Fourth of July Concert, Lahaina.
7/4 - Fourth of July Farm Tour at Sacred Earth Farm, Haiku. 10 am and 4 pm. By donation.
7/4-7/7 – Makawao Rodeo. One of the biggest upcountry events. Some rodeo days are free, others have an admission fee. Make sure to click on "See more…" to see the schedule for Friday, Saturday, and Sunday.
7/5 – First Friday in Wailuku, Town Party.
7/5 - Hana First Friday! First ever First Friday in Hana to be celebrated at Mile marker 31. Also, there's a flyer on Flyers Up.
7/5 - Astronomy lecture: "The Orbital Perspective" by astronaut Ron Garan on his time in space. Institute for Astronomy, Pukalani. 6:30 pm.
7/6 – Makawao Fourth of July Parade. 9 am. Free. Read about the parade two years ago.
7/6 – For the Love of Maui (Fundraiser to Support Community Work Day), Kapalua. $25 Community Work Day is an amazing nonprofit and organizes the Art of Trash, offers free paint, has school garden projects, etc.
7/11 - All About Tomatoes - Lecture on growing tomatoes in Hawaii (actually a very tricky thing). Lumeria Maui, Makawao. 5:30-7:30 pm. $15.
7/19 – Third Friday in Makawao, Town Party. Featuring Maui Classic Cruisers and Rock n Roll. Free.
A small section of the pie-heaped table at the Kula Pie Tweetup last summer.
***7/20 – Kula Pie Tweetup – Details TBA in early July – visit Kupu Maui. This is an amazing and fun pie potluck.*** Free.
7/20 - Maui Singalong Circle. Folk song group. Informal, free. 3-4:30 pm. Sacred Garden of Maliko, Makawao/Haiku.
7/20 - Sensationism - Artist reception and video showing of a film on Maui artist Taryn Alessandro at Turnbull Studios, Paia, 5 - 8 pm. If you missed the short film, it's on youtube. Here's a recent post on Taryn by Maui Made Blog.
7/23 – Maui Farmers Union Potluck and Meeting. Free.
7/25 - Power of the Soil. Talk by Graeme Sait. Sait will present on multiple aspects of soil, human and planetary health, including numerous health tips and strategies. Graeme Sait's presentations have been described as life changing. Free. 6:30 -9:30 pm. UH Maui Campus, Pilina Building's Multi-purpose room.
7/25 - The Art of Cooking with Essential Oils with Deborah Maghen. Wailuku, 6-8 pm. Vegan, raw, gluten free. $25 (forgot to mention that earlier!) Contact info in the box below.
7/26 – Fourth Friday in Kihei, Town Party. Free.
7/27 - Niu (Coconut) Festival at the Grand Wailea. 4 - 8 pm. Learn all about coconut usage and history.
7/27 - Family Day at the Hui No'eau Visual Arts Center. 10am - 2 pm. Makawao. Scavenger Hunt (1st 50 participants only), face painting, kite flying, art workshop.
7/27 - Hanzawa's Store Grand Re-Opening, 10 am - 2 pm. Haiku. Give aways, live music, pony rides.
7/28 - Beach Clean up at Kanaha Beach near campsite #1 by Opala Holla. 9:30am - noon.
7/30 - Ag4Maui. Learn about Agricultural and Farming Opportunities on Maui at UH Maui Campus. 6 pm.
7/31 - Growing Roses in the Home Landscape. Roses are tricky to grow on Maui. Bugs, humidity, different diseases. $15 at Lumeria Maui, Makawao. 5:30 - 7:30 pm.
P.S. A friend's partner's mother (this is Maui...) needs a kidney. Her friend in Pennsylvania has one to donate. Here's the link, if you're interested in donating any amount.


ZIPSER called me on 6/1/1976 at around 6:20 p.m. and informed me of his presence. We arranged to meet on 6/3/1976. He called at around 11:30 a.m. from Ulrich PLENZDORF's and came to see me at around 6:30 p.m. From our place we drove to have dinner at Hotel "Stadt-Berlin," where he is also staying.
He told me he wants to stay in Berlin until 6/11/1976 or so, and then stay until 6/15/1976 or so in Hotel "Warnow" in Rostock.
With regard to his intentions, I am aware that he wants to continue with the interviews he began doing in fall 1975. I do not know the date of his entry.
He is entertaining the idea of going to visit Ulrich PLENZDORF, etc., at his country cottage in [blacked out], on the weekend of 6/5-7/1976.
He was planning to do an interview with Volker BRAUN on 6/4/1976, around midday, and to dine with Ms. Sarah KIRSCH in "Ganymed" on 6/5/1976.
D. Zipser commented on the 10th Parliament to the effect that he finds it beyond belief to see so many police and Free German Youth [socialist youth organization of the GDR] marshals on all street corners. He observed that, if we can manage to carry out such an elaborate operation, we probably have too large a workforce.


text:
What is the opposite of breeze? |
The opposite of breeze is a gale.
The "opposite of breeze wind" is a word that describes the opposite of what we typically think of as "breeze." It is often used in sports to describe how strong the wind is.
The antonym of advance or move fast. crawl. creep. dawdle, poke, poke, dawdle, dawdle, daw
In this case, what is the antonym of breeze?
Breeze nuisance, toughie, stinker, stumper, bother, calm, difficulty, poser, brainteaser, sticky wicket, discomfort are all antonyms for breeze annoyance.
What exactly is the polar opposite of crisp? Crisp(adj) is a pleasant combination of firmness and freshness. Straight, hot, tough, prolix, stale, indistinct are synonyms for "crisp lettuce."
The issue therefore becomes, what is a synonym for breeze?
zephyr, air, gentle gale, mild wind, light wind are all synonyms for zephyr. breeze(n.) Disagreement, commotion, noise, tumult, uproar, stir, agitation are all synonyms for quarrel.
What words would you use to describe the breeze?
Here are a few adjectives that describe breeze: heavy tiny, thin, highland, mild western, unnoticed horrible, closest vagrant, still cold and wet, steady but very soft, recent stiff, low, fragrant, chilly, unsteady, hollow idle, gently moist, crisp occasional, strong early-morning, brisk autumnal, small and welcome,
What exactly does it mean to "wiff"?
whiff. A whiff may refer to a faint scent of whatever you're smelling. When you drive by a sewage treatment facility and your automobile windows suddenly roll up, it's generally because you've detected the plant's distinct stench. Whiff may be used as a noun or a verb, and it refers to a quick puff or smell.
What is the meaning of the term "breeze"?
The term "breeze" refers to a light breeze that has a relaxing effect, particularly on a hot and humid day. Simply said, breeze refers to wind that blows at a given pace. The two sides of the same coin are wind and breeze.
What is the best way to utilize the word breeze in a sentence?
Examples of Breeze Sentences
Her cheeks and neck were brushed by a chilly air.
On a hot summer day, it's like a cool breeze.
Her cheeks were warmed by a chilly air.
The flower swayed as if it had been caught in a wind rather than an earthquake.
The fan's artificial wind only gave momentary respite.
How do you say "breezes"?
Here are four suggestions to help you pronounce 'breezes' correctly:
Break down "breezes" into sounds: [BREEZ] + [IZ] – repeat it out loud and emphasize the sounds until you can generate them consistently.
Make a video of yourself saying 'breezes' in complete phrases, then watch and listen to yourself.
What does it mean to have a cool breeze?
A breeze is a gentle, refreshing breeze. The soft breeze off the sea is one of the best parts about being at the beach on a hot summer day. One kind of wind is the one that blows your hair about and rustles the foliage.
What is the name for a strong wind?
The passage of gases on a big scale is referred to as wind. Gusts are short bursts of high-speed wind. Squalls are strong winds with a short duration (about one minute). Long-duration winds are referred to by a variety of titles depending on their average intensity, including breeze, gale, storm, and hurricane.
What is another word for flurry?
flurry(n.) agitation, flutter, ruffle, hurry-skurry are synonyms for agitation, haste, bustle, chaos, commotion, perturbation, disturbance, flutter, ruffle, and hurry-skurry.
What is the opposite of strong wind?
a blast, a flurry, a gale, a gust, a headwind, a squall, a tailwind, a tempest, a tornado, and a windstorm zephyr, zephyr, zephyr, zephyr, zephyr, zephyr, zephyr, ze
What does it imply when the air is crisp?
Many people use the term "crisp" to describe chilly air, but what exactly does it mean? We mean clear, clean, and dry when we say the weather is crisp. Crisp, chilly air is stimulating and rejuvenating for many individuals! Because there isn't enough water vapor in the air when it's chilly outside, it seems dry!
What do the terms "crisp" and "clear" mean?
a sharp adjective (CLEAR)
It's highly obvious when there's a clean sound or image: The new speakers provide a very clean sound. Snappy is a rapid, confident, and effective method of speaking, writing, or behaving: a crisp response.
What is a synonym for the word "clean"?
washing, scrubbing, cleansing, cleaning, and polishing immaculate, pristine, speckless, dirt-free, spotless, unsoiled, unstained, unspotted, unsullied, unblemished, spotless, blemished, blemished, blemished, blemished, blemished, blemished, blemished, blemished, sterile, aseptic, decontaminated, hygienic, sanitary, disinfected, sterilized whiter than white, pure, pure, pure, pure, pure, pure, pure, pure, pure, pure, laundered.
What is the opposite of the word lady?
Noble, Lord, and nobleman are antonyms. Doll, noblewoman, chick, peeress, ma'am, madam, wench, skirt, bird, brothel keeper, gentlewoman, dame. Synonyms: doll, noblewoman, chick, peeress, ma'am, madam, wench, skirt, bird, brothel keeper, gentlewoman, dame.
What is another word for crunchy?
Crunchy Synonyms and Near Synonyms crusty, crackly, crisped, crisped, crisped, crisped, crisped, crisped, crisped
Is Breeze a noun or an adjective?
What adjective would you use to describe a breeze? The past participle and present participle forms of the verb breeze are shown here, and they may be used as adjectives in specific situations. breezy. It's delightfully windy when there's a breeze blowing, when there's a lively wind blowing.
What exactly does the phrase "should be breeze" imply?
to be extremely simple is an informal phrase The test appeared to be a breeze to everyone. Simple to do and simple to be: simple, convenient
How would you describe the sensation of wind on your face?
We may say the wind is nibbling at my face or the wind is biting my face if the wind is really chilly (commonly referred to as "biting" cold). "A chilly wind is blowing on my face," we remark as well. 2. You feel good if a cold wind gently brushes over your face on a hot summer day.
What does it mean to "strike the breeze"?
Let let all hang out. Shoot or toss the bull as well. They've been lounging on the porch for hours, just shooting the breeze, or The men have been tossing the bull around the locker room. The earliest of these slang words was reported in 1919, and it referred to talking into the wind.
Previous: What is the most pitches thrown in a game?
Next: What is the opposite progress? |
fourteen − one =

redpajama_set_name: RedPajamaCommonCrawl


Dubai offers a high standard of living to expats, who flock there for the opportunity to live and work in this rapidly developing economy. In fact, with a whole host of family friendly attractions, Dubai attracts everyone from highly paid execs, to young professionals, families and students. If you're coming to Dubai to study, you'll find that there are strong local universities such as the University of Dubai (UD), as well as a large number of campuses affiliated to other universities from around the globe.
The lifestyle on offer means that Dubai can be a fantastic expat destination, but it comes at a cost. Renting a one bedroom apartment in the city centre will cost, on average, €1766, or €1209 outside of the city centre. This puts it on a par with London - and means that renting in Dubai is some 60% more expensive than finding a home in Paris. Naturally, what you pay in rent will vary enormously based on location, and some people choose to swap the inner city for smaller outlying communities, where villas are more readily available.
In general terms, the rental market in Dubai is fairly well stocked and regulated. However, it can feel quite alien to a newcomer, and like anywhere there are unethical landlords and agents, so you should be wary. If you have any issues the government agency set up to help is the Real Estate Regulatory Agency (Rera), and they can offer advice and arbitration should you need it.
If you're just making plans, it's important to take into account all the costs associated with your move. Compare the cost of living in Dubai with that of your home town using a comparison site such as Numbeo, and check out this quick guide to renting in Dubai to find the perfect place for you.
What are my housing options in Dubai?
Although there are several different options when it comes to housing in Dubai, what suit you will depend on your lifestyle and budget. Property options basically break down to villas or flats, both of which have their advantages and disadvantages. Villas, for example, will have more space and usually a private garden, but can be much more costly and time consuming to maintain. Apartments, on the other hand, can mean you have to compromise on space, but give you access to shared facilities such as a pool and gym, and tend to come with much lower utility bills.
Some real estate agents are specialists in specific areas of Dubai, so if you've narrowed down your choice of location, it's worth checking if there's a realtor with inside knowledge on your chosen area. The Dubai Land Department has a list of approved Dubai real estate brokers, which you should always use when looking for a realtor.
Agents will charge a fee for their services, which is usually around 5% of the annual rent of the property. However, some agents put their fees much higher, so make sure you know in advance what the charges are going to be. Also, some realtors will write a clause in tenancy agreements which means that you have to pay some form of fee every time the contract is renewed. This is something you can negotiate about, or move onto a new agent if you're unhappy with the terms on offer.
The Dubai rental market is pretty active and well stocked. Lots of expats means that renting is common, and so, there's a huge range of options. Options range from completely unfurnished places to others which come complete with all furnishing and services such as security and cleaning thrown in. It's worth considering what you need in advance, as some areas will have a larger stock of one accommodation type. Therefore, the type of home you're looking for is also likely to influence the location you end up in.
If you're only in Dubai for a relatively short time, there are fully furnished short term rents available, although these tend to cost a lot more.
A notable difference about renting in Dubai, is that subletting in a place that's already rented by someone else might cause you a problem. This is because the law frowns upon unmarried males and females living together. Dubai police tend to be pragmatic but it's unlikely to be a huge issue for a foreigner, unless you find yourself in contact for the police for some other misdemeanor.
How you proceed is a personal choice, although Dubai is still a place where it pays to have a healthy respect for the law. All that said, there are lots of rooms available on Dubizzle if this is what you want to arrange.
If you're coming to Dubai to study, most of the universities will be able to help with advice and support to help you find a place - especially as an international student newly arrived in the Emirate. Not all university campuses have onsite accommodation for students, however, so this might push your budget up a little for housing.
Naturally, where you choose to rent in Dubai will be largely dictated by the location of your job. It's worth also taking into consideration the school you choose if you're going to live in Dubai with kids, as traffic at peak times can be congested. Different communities in Dubai have very distinct characteristics, and your personal preferences, as well as your budget will dictate what's best for you. As you might expect, in general terms, the further away from the heart of town you go, the more affordable the rents. So you can get more for your money if you're prepared to have a bit of a journey into the city. However, some communities outside the centre have higher end prices because of their reputation or other facilities, so check out what you're getting for your money before you commit.
The centre of Dubai includes many landmarks which are globally recognisable - such as the Dubai Mall (the largest and most visited on the planet), the Burj Khalifa (tallest building) and the world's tallest hotel, Dubai's JW Marriott Marquis. When it comes to a place to live, the most desirable places in Dubai tend to be close to the centre of all the action, and of course the beach. Jumeirah, which includes developments like The Palm and Dubai Marina are among the most popular with price tags to reflect this. Emirates Hills, a gated community named after Beverly Hills, is at the centre of several other distinct and attractive central communities, such as The Meadows, The Lakes and The Springs.
It's worth considering what you want from your home in Dubai, as the centre of town offers fantastic activities, restaurants, shops and nightlife, but can be congested with traffic. And while most expats looking for a place in the centre of Dubai choose one of the more recently developed areas, you can also look at somewhere like Old Dubai if you want something a little different.
It's possible to live outside of the Emirate of Dubai to reduce your housing costs significantly, in areas such as Ras Al-Khaimah. However, congested traffic in the city means that commuting times could be very long. Driving to the centre of Dubai from Ras Al-Khaimah as an example, will take one and a half hours each way in average traffic, making it a pretty steep price to trade off against lower housing prices.
A better choice might be one of the communities which are outside of the city, but not as distant. Arabian ranches, some half an hour drive time from the centre, is an option popular with expats, as it has a reputation for good design and is quite a large community in its own right. Prices, however, are correspondingly relatively high.
If you're looking for student accommodation, then your best bet is to ask your university for their advice on reputable agencies, if they don't provide on campus accommodation. Because flatsharing can prove problematic under local law, you should ask your university what they recommend within your chosen budget and location.
Property Finder is one of the largest property sites in the UAE, and they offer everything from homes and apartments to rent and buy, to commercial and business property.
Just Property is a similar umbrella site where you can find lots of accommodation throughout the area.
Dubizzle is a classified site operating throughout the UAE and beyond. You can search for homes and apartments to rent, which are either through agents or direct from the landlord.
Technically, flatsharing might be problematic, as the rules about unmarried males and females living together are strict. However, there are lots of rooms available on Dubizzle if this is what you want to arrange.
It can feel daunting if you're just setting about finding the right place in another country and culture. Here are some of the things that can help you be more prepared.
What language will be used when I arrange my new home?
Although Arabic is the official language of the UAE, English is actually the language most commonly spoken in Dubai. As such, you'll find most accommodation offered online is available with English descriptions, and rental agents will usually speak English, often in addition to other major world languages. All of the agents and umbrella sites listed above are in English, and the laws around tenancy agreements and rent are also published online in English by the Dubai Land Authority.
When you agree to a property in Dubai, you should always ask for a contract in writing. This will also need to be registered to give you your full legal rights. Your contract will be agreed between you and your landlord, sometimes with a broker acting as an intermediary. There isn't a standard contract, and as long as you comply with tenancy regulations you can tailor the contract terms to suit your situation.
You should know that it's fairly common for landlords to ask for significant amounts of the annual rent upfront. Until recently it was the norm to be asked for the whole year's rental costs in one go, or to be asked to make out a series of post-dated cheques which the landlord can then cash at various points during the year. This means you're paying an entire year's rent in only a very small number of installments. If you're used to paying a monthly rent, this can feel very alien.
However, since more rental property has become available in Dubai over recent years, many landlords realise that to be competitive they must also be flexible with their payment terms. You might even find landlords willing to accept monthly rent, but make sure you tell your agent if this is an absolute necessity for you so they can negotiate with landlords on your behalf.
When you agree a rental, you'll be given a blue tenancy contract by the broker. However, this isn't legally valid unless it's registered with Ejari (which is the Arabic word for 'my rent'). You can read all about the process in English, and register your tenancy online.
Although good landlords are the majority in Dubai, the rental market is changing rapidly, and like anywhere else, a growing market will attract its share of unethical owners and agents. Choose a reputable agent who is registered by Rera, and don't hand over any money without getting a receipt and being clear about what it's for. It's not unheard of for scam agents to take the security money of a would-be tenant and disappear.
It's good to know that landlords can't just arbitrarily raise rents in Dubai. They must give tenants 90 days notice, and the new rent must be based on the rental index published every quarter by Rera. If you're paying under the market rent for a similar property, your landlord can legally raise your rent according to a formula, which will gradually bring the rent back into line with the market. However, with rental prices on the rise in some areas, unethical landlords might still try to steeply hike their rents, in the hope that sitting tenants move out, allowing them to remarket the property at a much higher rental cost.
As long as your tenancy is properly registered you have strong rights in Dubai. That said, it's always a good idea to try to solve any issues amicably in the first instance. However, if you have any problems you can't resolve directly with your landlord, then Rera is the place to look. The Dubai Land Authorities have much of the information you'll need in English to help you understand your rights and how to resolve issues like unfair rent rises.
Usually the deposit you have to pay will be in the region of four weeks of rent. However, unlike some other countries, this might have to be given to the agent when you reserve the property.
Because you're handing over payment before moving in, you need to make sure you're protected. Both the blue contract from, which you'll be given at the point of making the reservation by your agent, and the Ejari record you'll get when you register your tenancy, should include a record of the deposit that you have paid to the landlord. Naturally, you must also make sure you use a reputable broker and get a receipt.
If you're just planning your move to Dubai then you might find that you need to make a deposit payment before you have opened a local bank account, or even arrived in the country. If you do, it's worth remembering that your home bank might not offer the best value when it comes to making an international money transfer. Often banks will add hidden fees by using a poor exchange rate, even with their own account holders.
To get the best deal possible, consider using an exchange service like TransferWise to make your payment directly to your new landlord or agent. TransferWise applies the same mid-market rate you'll find on Google, and the charges the lowest possible fees.
Be wary of common scams, such as properties offered for rental without proper contracts, or landlords or agents who ask for fees for a service you don't want or need. However, the good news is that the rights of a tenant renting in Dubai are well protected by law. Make sure that you register properly with Ejari to get your full rights. This is simple, and you can even register your tenancy online.
Renting in Dubai is something of an adventure - not least because of the dizzying array of choices open to new arrivals. It's worth getting to know the area a little before you commit to a property, and using a reputable agent if your budget allows. The system isn't hugely complex but can feel alien to a newly arrived expat. However, if you take some local advice and are clear on what you want from your new pad, you'll find your dream place in Dubai in no time. Good luck!


Step 6: Confirm your new account with the email address you provided. Longer Explanation and visual guides for Setting up a Google Account with a non-Gmail Email: Step 1: Log out of any Gmail account(s) you�re currently logged in to, then open https://accounts.google.com . how to add epub files to kobo glo Step 6: Confirm your new account with the email address you provided. Longer Explanation and visual guides for Setting up a Google Account with a non-Gmail Email: Step 1: Log out of any Gmail account(s) you�re currently logged in to, then open https://accounts.google.com .
Step 6: Confirm your new account with the email address you provided. Longer Explanation and visual guides for Setting up a Google Account with a non-Gmail Email: Step 1: Log out of any Gmail account(s) you�re currently logged in to, then open https://accounts.google.com . how to create a google group email list Step 6: Confirm your new account with the email address you provided. Longer Explanation and visual guides for Setting up a Google Account with a non-Gmail Email: Step 1: Log out of any Gmail account(s) you�re currently logged in to, then open https://accounts.google.com .
Step 6: Confirm your new account with the email address you provided. Longer Explanation and visual guides for Setting up a Google Account with a non-Gmail Email: Step 1: Log out of any Gmail account(s) you�re currently logged in to, then open https://accounts.google.com .


Sand specifically chosen for its wide variety of minerals, crystals and shell fragments. Ideal for close-up study with a magnifying glass (8x magnification is best) or with a dissecting microscope (up to 20x magnification). Sort the different types of minerals and describe. Colourful and varied.


text:
namespace Google.Cloud.AIPlatform.V1.Snippets
{
    // [START aiplatform_v1_generated_JobService_CancelDataLabelingJob_sync_flattened_resourceNames]
    using Google.Cloud.AIPlatform.V1;

    public sealed partial class GeneratedJobServiceClientSnippets
    {
        /// <summary>Snippet for CancelDataLabelingJob</summary>
        /// <remarks>
        /// This snippet has been automatically generated and should be regarded as a code template only.
        /// It will require modifications to work:
        /// - It may require correct/in-range values for request initialization.
        /// - It may require specifying regional endpoints when creating the service client as shown in
        ///   https://cloud.google.com/dotnet/docs/reference/help/client-configuration#endpoint.
        /// </remarks>
        public void CancelDataLabelingJobResourceNames()
        {
            // Create client
            JobServiceClient jobServiceClient = JobServiceClient.Create();
            // Initialize request argument(s)
            DataLabelingJobName name = DataLabelingJobName.FromProjectLocationDataLabelingJob("[PROJECT]", "[LOCATION]", "[DATA_LABELING_JOB]");
            // Make the request
            jobServiceClient.CancelDataLabelingJob(name);
        }
    }
    // [END aiplatform_v1_generated_JobService_CancelDataLabelingJob_sync_flattened_resourceNames]
}