Как постранично (порционно) листать результат запроса в 1С (ака LIMIT x,y в MySQL)

Большая беда MSSQL и как следствие 1С — отсутствие возможности порционно листать записи результата запроса как в MySQL. В результате рождаются такие монстроузные алгоритмы как ниже (код не мой):

Функция GetNewsList(body, answer) Экспорт
	
	answer.error = Истина;
	answer.errortext = "Что-то пошло не так..";
	answer.result = "";
	
	Попытка
		page = ?(ЗначениеЗаполнено(body.page), Число(body.page), 1);
		Если page < 1 Тогда
			page = 1;
		КонецЕсли;
		
		nums = ?(ЗначениеЗаполнено(body.nums), Число(body.nums), 5);
		Если nums < 5 Тогда
			nums = 5;
		КонецЕсли;
		
		ПредДата = ТекущаяДата();
		ПредКод = "";
		Если page > 1 Тогда
			Запрос = Новый Запрос;
			Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
			               |	Хрюкости.Дата КАК Дата,
			               |	Хрюкости.Код КАК Код
			               |ПОМЕСТИТЬ тПредыдущих
			               |ИЗ
			               |	Справочник.ПоследниеСплетни КАК Хрюкости
			               |
			               |УПОРЯДОЧИТЬ ПО
			               |	Хрюкости.Дата УБЫВ,
			               |	Хрюкости.Код УБЫВ
			               |;
			               |
			               |////////////////////////////////////////////////////////////////////////////////
			               |ВЫБРАТЬ ПЕРВЫЕ 1
			               |	тПредыдущих.Дата КАК Дата,
			               |	тПредыдущих.Код КАК Код
			               |ИЗ
			               |	тПредыдущих КАК тПредыдущих
			               |
			               |УПОРЯДОЧИТЬ ПО
			               |	тПредыдущих.Дата,
			               |	тПредыдущих.Код";
			Запрос.Текст = СтрЗаменить(Запрос.Текст, "100", Формат((page - 1) * nums, "ЧДЦ=0; ЧН=; ЧГ="));
			Выборка = Запрос.Выполнить().Выбрать();
			Если Выборка.Следующий() Тогда
				ПредДата = Выборка.Дата;
				ПредКод = Выборка.Код;
			КонецЕсли;
		КонецЕсли;
		
		Запрос = Новый Запрос;
		Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 100
		               |	Хрюкости.Код КАК news_code,
		               |	Хрюкости.Дата КАК date,
		               |	Хрюкости.Наименование КАК name,
		               |	Хрюкости.Содержание КОНЕЦ КАК content,
		               |	Хрюкости.Изображение КАК image
		               |ИЗ
		               |	Справочник.ПоследниеСплетни КАК Хрюкости
		               |ГДЕ
		               |	(Хрюкости.Дата < &ПредДата)
		               |	ИЛИ
					   |	(Хрюкости.Дата = &ПредДата И Хрюкости.Код < &ПредКод)
		               |
		               |УПОРЯДОЧИТЬ ПО
		               |	Хрюкости.Дата УБЫВ,
		               |	Хрюкости.Код УБЫВ";
		Запрос.Текст = СтрЗаменить(Запрос.Текст, "100", Формат(nums, "ЧДЦ=0; ЧН=; ЧГ="));
		Запрос.УстановитьПараметр("ПредДата", ПредДата);
		Запрос.УстановитьПараметр("ПредКод", ПредКод);
		Выборка = Запрос.Выполнить().Выбрать();
		
		РезМассив = Новый Массив;
		Пока Выборка.Следующий() Цикл
			РезСтрукт = Новый Структура("news_code, date, datestr, name, content, image");
			ЗаполнитьЗначенияСвойств(РезСтрукт, Выборка);
			РезСтрукт.datestr = Формат(Выборка.date, "ДФ='dd.MM.yyyy HH:mm:ss'");
			РезМассив.Добавить(РезСтрукт);
		КонецЦикла;
		
		ЕстьЕще = Ложь;
		Если РезМассив.Количество() > 0 Тогда
			КрайняяНовость = РезМассив[РезМассив.Количество() - 1];
			Запрос = Новый Запрос;
			Запрос.Текст = "ВЫБРАТЬ ПЕРВЫЕ 1
			               |	Хрюкости.Код КАК news_code
			               |ИЗ
			               |	Справочник.ПоследниеСплетни КАК Хрюкости
			               |ГДЕ
			               |	(Хрюкости.Дата < &ПредДата)
			               |	ИЛИ
						   |	(Хрюкости.Дата = &ПредДата И Хрюкости.Код < &ПредКод)
			               |
			               |УПОРЯДОЧИТЬ ПО
			               |	Хрюкости.Дата УБЫВ,
			               |	Хрюкости.Код УБЫВ";
			Запрос.УстановитьПараметр("ПредДата", КрайняяНовость.date);
			Запрос.УстановитьПараметр("ПредКод", КрайняяНовость.news_code);
			ЕстьЕще = НЕ Запрос.Выполнить().Пустой();
		КонецЕсли;
		
		answer.result = Новый Структура("portion, havingmore", РезМассив, ЕстьЕще);
		answer.error = Ложь;
		answer.errortext = "";
		
	Исключение
		answer.errortext = ОписаниеОшибки();
	КонецПопытки;
	
	Возврат answer;
	
КонецФункции

Если вкратце, то алгоритм следующий:

  1.  Делаем выборку ВСЕХ записей, определяя, с какой записи было начало предыдущей страницы
  2. Начиная с этой записи, делаем выборку N записей
  3. Передаем результат

Интересно будет посмотреть как этот алгоритм будет вести себя при миллионах записей..

 

PHP: определение языка пользователя сайта

В ранние годы, чаще всего определяли языка пользователя на основании его IP. Да и до исх пор так часто делают. И всё чаще ошибаются из-за широкого распространения VPN и всяческих аномайзеров. Поэтом правильнее будет полагаться на стандарт W3C, согласно которому браузер должен передавать на сервер в заголовке HTTP заполненую переменную HTTP_ACCEPT_LANGUAGE. Собстевенно в PHP оно попадает в $_SERVER[‘HTTP_ACCEPT_LANGUAGE’]. Далее остается распрасить переменную с сортировкой по «весам»:

        if (($list = strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']))) {
                    if (preg_match_all('/([a-z]{1,8}(?:-[a-z]{1,8})?)(?:;q=([0-9.]+))?/', $list, $list)) {
                        $language = array_combine($list[1], $list[2]);
                        foreach ($language as $n => $v)
                            $language[$n] = $v ? $v : 1;
                        arsort($language, SORT_NUMERIC);
                    }
        } else $language = array();

Получаем массив вида:

Array
(
    [ru-ru] => 1
    [ru] => 0.8
    [en-us] => 0.6
    [en] => 0.4
)

Android Studio: glUtilsParamSize: unknow param 0x000085b5

При отладке приложений в эмуляторе под Android API<30 стала выскакивать эта ошибка, засоряющая лог Logcat. Легкий гуглинг дал информацию, что это из-за эмулятора: OpenGL  не нравиться андроиду как эмулируется. Чтобы отключить вывод мусорного лога, нужно добавить фильтр в Logcat

А именно Regex выражение ^(?!eglCodecCommon)

JavaScript именованные массивы как набор записей

Обычно для этой цели используют конструкцию Map, однако лично мне  не нравится его синтаксис, когда для доступа необходимо использовать get /set. Поэтому я обычно использую создание объекта. Т.е. получается что-то вроде:

// набор записей
TBokings=new Object();
TBokings={
  x:0,
  x1:0,
  starttime:"12:00",
  endtime:"13:00",
  status:"busy"
};
// сам массив
ArrBooking=new Array();

///добавление в массив
  TBokings.x=startRectX;
  TBokings.x1=EndRectX;
  TBokings.starttime=item.DtFrom_UTC;
  TBokings.endtime=item.DtTo_UTC;
  TBokings.status="busy";
  ArrBooking.push(Object.assign({}, TBokings));      

// перебор массива

ArrBooking.forEach(function(item){
	console.log(item);
});