text:
Coral Springs officer accused of soliciting a child for sex
Teens in convertible shot at in fit of road rage on I-95
Palm Beach County readies for Trump's arrival; traffic restrictions start tonight
Kelly: Miami Dolphins' superlatives for the 2020 season | Commentary
Hyde10: Ten thoughts on Dolphins dramatic win over Rams
By Dave Hyde
Omar Kelly and Chris Perkins talk about the Dolphins' comeback victory over the Rams.
For more than three quarters, this was one of the most unwatchable games you've suffered through. But then came an electric ending to this Dolphins' 14-10 win over Los Angeles that shows why this season keeps looking different than recent years.
Five straight wins? That doesn't even make the lead paragraph of this comeback from down 10-0 midway through the fourth quarter and showing no signs of life to running off the field thinking playoffs.
Here are 10 thoughts on the win:
1. Player of the game: Ryan Tannehill. For so much this game, everything fell apart for the Dolphins quarterback. His line. His momentum. His offense was 0-for-8 on third downs. It looked to be another game that would define the quarterback. And it did. Boy, did it ever. In one mighty stretch in the game's final six minutes, Tannehill lifted this offense for two touchdowns and the win. Forget his stats: 24 of 34 for 172 yards, two touchdowns and an interception. On the first touchdown drive that made it 10-7, he completed seven of eight passes fo 62 yards, including the 10-yard TD to Jarvis Landry. On the game-winning drive, Tannehill completed all five passes for 53 yards, including a perfectly thrown 9-yard touchdown to DeVante Parker. So do the math. For more than three quarters encompassing 11 drives, Tannehill had 57 yards passing. He somehow found a spark inside him to stay with the day and then complete 12 of 13 passes for 115 yards and two touchdowns in the final minutes to win the game.
2. Quote of the day: "To take them down the field for that winning drive, (Tannehill) has shown he's a franchise quarterback." – Jimmy Johnson on the FOX post-game TV show.
3. Play of the game: It's tempting to say Jeff Fisher not going for it on fourth-and-1, the Rams plunking a 48-yard field goal attempt off the goalpost and little-used Dolphin Leon Orr getting a personal foul for helmet-butting an opponent after the play. That kind of summed up what was an unwatchable game for so long. But, no, the play of the day was Tannehill's game-winning throw low and in the corner of the end zone to Parker for the win. Perfect throw. Perfect catch. Perfectly dramatic way for this comeback to be complete.
4. The Dolphins offense in a word? "Disgusting," was the one coach Adam Gase chose at half, according to Fox TV. It had 118 total yards and an anemic 2.2 yards per pass at that point. (To tell what kind of game this was, the Rams had even less with 108 yards at the half). But if you're picking a word for the offense on Sunday, the word was, "Dramatic." Down 10-0 with 6:38 left, Tannehill drove for 77 yards in eight plays for the first score. He then drove 75 yards in seven plays for the winning touchdown. That's 152 yards of offense for a team that had done nothing to that point. Look at their drive charge on the day: Punt, punt, punt, punt, punt, punt, punt, interception, punt, punt, punt touchdown, touchdown.
5. Jared Goff got his first start and the top draft pick was OK by first-start standards. He completed 17 of 31 for 134 yards. But , really, the singular thing Goff did well is he threw no interceptions. He didn't cost them the game. He saw blitzes coming and found a quick target. Then again, all he was asked to do was throw quickly all day. In other words, he never did much of anything but accompany the Rams to what looked to be a good win for them. As it was, Goff showed exactly why the Dolphins had a chance with him starting his first game.
6. When Laremy Tunsil went to the locker room in the first half, that represented a one-week decimation of the engine that changed the Dolphins season a month ago. The offensive line's three best players were lost to various injuries – Branden Albert (wrist), Mike Pouncey (hip) and Tunsil (shoulder). In some form, it's right to wonder how bad luck plays into any season. But in the cases of Albert and especially Pouncey with his hip there were fingers crossed they'd stay healthy for the remainder of the season. These are, like it or not, fragile players. Pouncey's hips are especially worrisome considering he hasn't played a full season in four years and has only played in five of 10 games this year. In place of two Pro Bowl-caliber players and a rookie rated the second-best in the draft, the Dolphins had Sam Young at left tackle, Kraig Urbik at left guard and Andrew Steen at center. Not surprisingly, the pocket that was clean during the Dolphins good run wasn't there for much of Sunday.
7. So what happened in the AFC playoff picture? Kansas City was beat by Tampa Bay, and losses by AFC West are good for the Dolphins. It's too early to get into must-have games. But Baltimore and Tennessee losing helped, too. Here's the updated picture (four division winners plus two wild-cards make the playoffs):
New England Patriots (8-2)
Oakland Raiders (7-2)
Houston Texans (6-3)
Baltimore Ravens (5-5)
Kansas City (7-3)
Denver Broncos (7-3)
Miami Dolphins (6-4)
Pittsburgh Steelers (5-5)
Buffalo Bills (5-5)
Cincinnati Bengals (3-6-1)
San Diego Chargers (4-6)
We'll see where this goes. The idea for now is to keep winning.
Latest Dave Hyde
Hyde5: Deshaun Watson expresses more displeasure with Texans - Dolphins listening?
Hyde5: Andre Johnson rips Texans, tells Deshaun Watson to stand his ground
Hyde10: Ten thoughts on Dolphins' 56-26 debacle in Buffalo
8. Where was Jarvis Landry until the end? He had two catches for 1 yard when the Dolphins got the ball with 6:38 left. He's had a shoulder injury, so maybe that played into it. But then came that ensuing drive in which he caught the first third-down conversion of the day (5 yards), 12 yards for another first down and 10 yards in which he stayed alive long enough to be pushed into the end zone by most of the offense. So on that drive Landry had three catches for 27 yards, two first downs and a touchdown. When he found the ball, the offense found some life.
9. Something that caught my ear weeks ago did more often Sunday: Tannehill was barking, "Omaha," at the line of scrimmage. Homage to Peyton Manning? That's the kind of fun that would seem to fit Gase's personality. Gase coached Manning in Denver. Manning helped Tannehill this off-season. Omaha? Why not?
10. Next week: San Francisco at Dolphins. This is as easy as it gets in the season. Of course, the last time the Dolphins had a gimme game was against Cleveland back in September and they needed three missed field goals by the Browns' emergency kicker to win that. That was way back when the Dolphins season wasn't rejuvenated by their back-to-healthy offensive line. Well, the line isn't healthy again. But the Dolphins are riding a five-game win streak and more momentum than in years.
Follow me on Twitter here or get my articles on Facebook here.
DeVante Parker
Laremy Tunsil
Most Read • Dave Hyde
Hyde5: Where Russell Wilson ranks on Dolphins' top 10 QB misses; Gase gazing — Five Dolphins thoughts
Read Today's Newspaper


More than 100 students from 32 universities gathered at Northwestern to use human-centered design innovation to address mental health, community mentorship and career awareness and readiness in high schools.
The high school students, teachers, and experts interviewed by the Design for America team all agreed: anxiety and access to mental health services was a key barrier to learning. Anxiety about school violence, peer perceptions, social media, and expectations from family and friends played a major role in students' ability to excel.
But what, one of the Leadership Studio sprint teams wondered, could they design that hadn't already been done?
It's a seemingly monumental problem with no easy solution, but that didn't stop college and high school students at the 2018 Design for America Leadership Studio from using design-thinking skills to come up with ways to help young people live their best lives and prepare for the future.
The annual event, made possible by Artefact, Archeworks, Macmillan Learning, CPS Lives, Project Osmosis, Civic Tech Collective and 3M, brought together more than 100 students from 32 colleges across the country to learn about design and leadership — all through the lens of Design for America, a grassroots network of 38 colleges launched at Northwestern University that shapes the next generation of social innovators through design in their local communities.
The two-day sprint was part of a larger five-day DFA Summit, which included the Create Impact Conference for alumni and young professionals and the DFA Symposium workshops for DFA mentors, design educators, and industry professionals. Each aimed to strengthen DFA's network by connecting with alumni and the design community at large, said Rob Calvey, DFA instructional coordinator.
They then began a two-day design sprint that guided them through the DFA design process — identify, immerse, reframe, ideate, build, and test.
One team, whose members included students from Rice University, Duke University, Michigan State University, and two local high schools, decided to focus on mental health. Not so far removed from high school themselves, the students knew one big issue preventing students from seeking mental health help at school was trust.
One of the first steps of the design process, interviewing community members who would potentially use their designs, confirmed this.
"I don't know any people who would go to teachers for help," said Lily, a recent local high school graduate. Many students are worried that teachers or counselors will email their parents about their problems, she said.
Anna, a local high school teacher, agreed that it seemed difficult for students to ask for support, but said she was shattered to hear about her students' personal problems outside school. "We ask, are we doing enough to support the community?" she said.
After bouncing around several ideas, the team gravitated toward developing an event where students (or actors) could perform monologues, plays, and dances about real experiences that happened to them. That way, other students could realize they aren't alone in their struggles, and teachers, counselors, and the community at large would get a better sense of what students are going through.
"We want to start the conversation, take down barriers, and remove the stigma," said Angelo Ragan, a Spanish, Portuguese, and Latin American Studies major from Rice University. The performance could be followed by a fair, where students could connect with mental health services. When the DFA team presented their ideas to high school students and teachers the next day, the community members reacted positively to the idea, and the final result had only a few minor tweaks.
Growth Lab - A center inside a high school that offers three services: career advising, visits from local professionals who give presentations on their careers, and field trips to local companies.
Men-Tour - An app that matches mentors with mentees. Each potential match has a profile of their bio, values, strengths, hobbies, and availability. This would allow mentors and mentees to find each other organically, and then report back how the experience worked out.
A mentorship program that trains upperclassmen to become mentors to younger students, giving younger students a peer they could trust at school.


With the AMD Ryzen 7 2700 down to as little as $255, now is the time for us to discuss exactly what the benefits, if any, there are to purchasing the 2700 rather than its more expensive 2700X. If you consider yourself a computer hardware enthusiast, and are building a new system any time soon, you will want to give this a read.
The AMD Ryzen 7 2700 is the non-X version of the 2700X. So what does the 2700 not have that the 2700X does?
The simple takeaway is that the 2700 is clocked a bit lower, and is rated at a much lower TDP of 65W compared to the 105W of the 2700X. The 2700 still has a full 8 cores and 16 threads at your disposal.
We have written extensively about AMD's Precision Boost 2 and how it works with the 2700X and have a good handle on what exactly it does for its user. When you slide down the product stack to the Ryzen 7 2700, that can surely save you a few bucks, what is the overclocking enthusiast giving up in terms of performance, if any?
As mentioned in the intro, we have seen the Ryzen 7 2700 priced as low as $255, which will certainly get a lot of folks attention. The 2700X is priced at $320, and comes with a bit better HSF cooler than the 2700.
We did a standalone AMD Wraith Prism CPU Air Cooler Review just to see how it stood up against other titans in the market, and while it did not exactly shine, you can see in our PB2 Deep Dive, if you keep your case very cool, it is certainly a viable CPU cooler option. However there are many of us, that are not going to use the included cooler, ever. So if you are not going to use the included cooler with the 2700X, is there also a value in going with the 2700 rather than the 2700X?
Through all our reviewing and data collection over the last couple of months, we have come to love the 2700X and its Precision Boost 2. But we really wanted to see if we could save some money and get performance on parity with the 2700X if you are overclocking the 2700.
On the following pages we compare the Ryzen 2700 using Precision Boost 2 with the 2700X and its Precision Boost 2 implementation. Then we manually overclock the 2700 to 4.2GHz, with a 3400MHz RAM clock, and see how it stands up to the 2700X and PB2.


We are proud of the passionate role we have established in the online sample frame arena and the quality metrics we have created for all users of online research. The Sample Source Auditors/Mktg, Inc. are recognized globally and asked to speak at numerous industry events.
It all started with a massive endeavor well known globally as the Grand Mean Project®, where we have studied hundreds of panels around the world. We examine panel consistency from many different angles and certify panels for different levels of consistency and quality.
This inside frame work has empowered us with the ability to manage sample frames. Our diligent work and analysis has documented the rise of professional respondents around the world. We are the ones who have proven that various forms of survey taking hyperactivity change data. We have created behavioral sampling methods that transcend the differences between panels and now we became the sample frame company.
It has taken us a few years to achieve this position and we use our collected knowledge to help panel companies and market research companies obtain actionable answers.
Clients need to know that changes in the data they are seeing are real and not shifts in the underlying sample frame.
Contact us now and let us advise you on the challenges of online quality data and the methods of a proper sample frame.


Cohérent avec le fait que ce site utilise WordPress comme un CMS pour afficher du contenu plutôt statique.
Les pages permettent une gestion fine des hiérarchies (page principale et sous pages sur plusieurs niveaux).
Ce grand nombre de page pose cependant un problème de navigation. Dans mon exemple le menu horizontal principal du haut liste les pages du sommet de la hiérarchie et les sous pages sont affichées au survol (menu déroulant). Cela fonctionne bien et quand on descend dans l'arborescence, un fil d'ariane permet de remonter vers la sortie (ou du moins vers les pages précédentes).
Les autres pages du même niveau hiérarchique dans l'arborescence.
Les pages filles de la page actuelle si elles existent.
Les plugins de gestion des pages sont très nombreux dans WordPress, voici mes notes sur ceux que j'aurai testé avant de trouver mon bonheur.
Ce widget affiche l'ensemble des pages du site. On peut exclure certaines pages si l'on veut. L'affichage obtenu n'est absolument pas contextuel et tout à fait inadapté à notre besoin.
Le plugin Sub Page Widget.
Voici sa page chez Extend. Ce plugin a l'air de ne plus être maintenu.
Normalement ce plugin permet d'afficher les sous pages de la page actuelle dans une colonne latérale. Il ne s'affiche pas quand la page est une page sans sous page.
Après test ce plugin ne permet pas d'afficher les pages du même niveau hiérarchiques et je n'ai pas du tout réussi à faire ce que je voulais.
Voici sa page chez Extend et celle de son auteur Srini.
Juste un regret : pas moyen de ne pas afficher les autres pages du premier niveau hiérarchique (celles sans parent) quand on est dans l'arborescence.
Bien que la requête « display page widget » renvoie plus de 1000 résultats dans les plugins de WordPress, je vais en rester là dans mon article puisque le plugin « Flexi » fonctionne très bien.
Bonjour j'ai un probleme avec flexi pages qui m'affiche un lien alors que j'ai une page vide (qui sert car elle a des sous pages).
tuto. And I actually do have 2 questions for you if it's allright.
Could it be simply me or does it look as if like a few of these comments appear like coming from brain dead individuals?
People across the globe are able to team up, build, fight, and compete.
Don't hesitate to contact the seller with any questions you might have.
trees and shrubs and animals running around about.
pre-order price tag to join the mix of retailers.
sensing controller. Walmart's site has also jumped in with a $399 pre-order price tag to join the mix of retailers.
selection of much less than $40 bucks per game.
Especially if you haven't got something incredible to tell them EVERY time.
by being posted on Ovi Share. know what it takes to design and build superior concession trailers.
the Gemini mind-numbingly bored and impatiently disgusted.
nudies. shippers shipping shippons shipside shipways shipworm shipyard shirkers.
The next time you decide to go shopping for new clothes visit your closet instead. I believe I had a spiritual experience Saturday. Instead of spending a ton of money online or at the mall, I decided to visit my closet.
Shopping online at favorite websites seemed like a fun way to spend Saturday morning. There was a ton of new clothes already in my shopping cart when I had to make a trip to my closet to get a trouser size. The shopping cart had James Perse T-shirts and cargo pants, Vince sweaters and Juicy Couture Bermuda shorts. I was having a ball as I usually do when I find a good sale or bargain.
I was going to buy a new pair of James Perse parachute cargo pants when I needed to verify my size. So, low-and-behold, I walked into my closet to see which size I bought last month. That's when I decided to take a closer look at the clothes hanging neatly in sections of pants, shorts, capris, blouses, dresses, T-shirts, jackets and coats. Actually, my closet looks like a well-organized section of a high-end department store. I'm in the designer handbag and purse business, so I make it a habit of collecting high-end fashion from every cool website and boutique possible.
My shoes are all neatly organized by Designer names and color-labeled on the outside of the box. My favorite sneaker collection is the Nike Rift in wild colors and patterns. Camper leather shoes are very comfortable so I have many neatly arranged red boxes on the shelves. Prada Sport shoes range from flat to platform, and they are all color marked and labeled. Hermes dress shoes get worn less, but nonetheless, they are neatly arranged on the shelf.
I have a soft-spot for boots, so my collection of Henry Cuir, Prada, Ann Demeulemeester, Mosquito, Robert Clergerie, Camper, Miu Miu, Diesel, Michael KORS, UGG, and Ralph Lauren are all neatly labeled and waiting to be worn. They range from ankle height to over-the-knee style, and I wear them with just about anything when I'm in the mood for boots. My favorites are a new gaucho style from Brazil. And, of course, you can't beat the light weight of Henry Cuir for warm weather.
My closet is really a fun place to visit and keep organized. All the Hermes designer purses are neatly stored in their orange boxes and labeled on the outside. Of course, my favorite of all the Hermes designer handbags are the impossible to source Birkin bags. The Hermes Market Bag is also a fun medium style and great to grab for daytime or evening wear.
As I stood looking for the James Perse cargo pant size, I realized I had several things I had not worn with tags still attached. So, I began pulling items and holding them next to each other. Then, without hesitation, I began coordinating outfits from the closet's contents. I found tops I forgot I had. I found double James Perse T-shirts in the same color and style! I was having the time of my life. All of a sudden I realized home shopping had a new meaning. Balenciaga and Dries Van Noten blouses were funkier than ever! Marc Jacobs, Yves Saint Laurent and Eskandar jackets were fashionable, timeless pieces. Robert Rodriguez skirts, crochet tops and gaucho pants had never looked so beautiful.
Can I simply just say what a comfort to uncover somebody who really understands what they're talking about over the internet.
Playing water using Banzai water slide is much safer than bringing your children to swimming pool or even beach, this is the second reason you can count on.
Furthermore, the third reason that you can count is that while your children playing Banzai slide, you can do your house tasks because you can place the slide in the backyard of your house.
The Banzai falls water slide only has less than three meters height and that would be very safe to your children.
The materials used in the Banzai products making are the best materials that are rust free and have high durability. The Banzai product is movable and if you want to move it to other places you can do it by simply drag it to the new place by previously empty the water. Those are the reason number four and five.
If you want to buy Banzai falls water slide, you can directly open the internet and search it. Many stores on the internet sell the water slide with various models. You can buy Double Drops Falls, Canon Blast Slide, and many other Banzai product types. All types of water slides are made by putting attention in the children safety. You should consider seriously to buy this product and make your children happy, that's the biggest reason why you should by it.
For affordable marine binos then look no further than the Oceana series Celestrom binoculars which come with a range finding dial and compass. However, if you want truly top notch marine binoculars then don't make a purchase before checking out the Steiner Commander series which are salt water resistant, protected against environmental pressures, waterproof to 10 mtrs, long-life rubber armoured, auto focusing and guaranteed for 30 years, truly special.
In this digital era, no range would be complete without digital binoculars. The Celestron Vistapix allows you to store pictures, download them onto a TV or laptop and print quickly and easily starting from around ?50.
With compact binoculars Celestron do have some strong competitors, even in the low price range including Nikon, Pentax and Olympus (who offer the widest choice), all good makes and all worth a look at. Canon do a compact IS binocular and Steiner make some excellent high quality compact binoculars ranging from about ?50 – ?300.
If you want to get into astronomy but don't want to spend a fortune Celestron do a range of affordable binoculars to get you started. The Skymaster series are priced as low as ?50 or, if you want a telescope then Celestron has a vast selection of low cost beginner models right up through to the top of the range.
Cheap cookware sets are good because they do what they are made or designed to do, which is to cook the food. A food cooked in this type of sets would taste the same if you cooked the food in another sets. The sets you use don't affect the taste of food. The taste of food depends on the cook. That is if the cook is good, the food would taste good. But if the cook is a bad cook, the food would taste horrible. So to make a food taste good, the cook has to add the different and right amount of spices. Then the cook has to stir the food properly to make sure that the spices mixes are dissipated around the food. it is not good if one part of the food has too much spice, and another part has little or no spice. This would leave a negative impression in the mind of the guest.
that is a surprise. He was the second in line in a series of great centers for the Raiders.
The AFL was only in its' infancy having been started in 1960.
Hacienda del Sol Guest Ranch Resort is located at: 5501 N.
recently saw them get blasted by the Giants at home on Monday Night Football.
Just ask the Tampa Bay Derby Darlins' Sasha Haughtbich.
The class costs $25 (price covers tequila, appetizers, and instruction) and is hosted in the Salud lobby lounge.
Les autres pages du même chaussures Timberland niveau hiérarchique dans l'arborescence.
are likely to be $10 off of an $25 purchase.
I will attempt to outline some of the misconceptions, obstacles, causes and remedies that I have encountered.
Thank you, I have just been looking for information about this topic for a long time and yours is the greatest I've discovered till now. However, what concerning the conclusion? Are you positive concerning the source?|What i don't realize is in reality how you are no longer really much more well-appreciated than you may be right now. You're so intelligent.
Ultimately when you http://www.tifosibianconeri.fr 'pier' at the Pirotan Island it's wise to be careful when you jump-off the water craft.


text:
HomeCommunity LifeRoadtestRoadtest: Where to get your Zine Fix
Roadtest: Where to get your Zine Fix
April 28, 2017 Roadtest
Curious about zines? The following Inner West outlets sell or display zines for your reading pleasure.
The Rizzeria
Community spirit is the backbone behind this non-for-profit workshop and retail outlet. Formed nine years ago by a volunteer group of artists who purchased a risograph printer for public use, The Rizzeria has become a haven for Inner Westies wanting to print posters, invitations, zines, graphic design pieces and much more. Jo from The Rizzeria explains: "The risograph printer produces a bit of a different look – it's not black and white. The colours are really bright, so it looks different to digital printing".
While it doesn't stock a large range of zines, The Rizzeria is a place where people can print their own zines, and they'll then try to stock a few copies. If you're interested in creating zines, The Rizerria runs workshops. "We show samples of zines, talk about the different things you can put into zines, look at different styles and formats, and everyone can make their own zine and then print them," says Jo.
Shop 2/359 Illawarra Road Marrickville
Repressed Records
Repressed Records specialises in DIY, punk and alternative music, and zines. Their big selling zines include the Sydney-based Unbelievable Bad, Distort Zine from Melbourne, and American MAXIMUM ROCKNROLL. Their diverse clientele has their interests catered for, whether it be punk, blues, jazz or hip hop. Certain zines have attracted regular customers; for example, some Sydneysiders have purchased MAXIMUM ROCKNROLL every month since 1995.
Ravi from Repressed Records is a fan of zines: "Zines are great. And it's fantastic when people put in the effort to create them. We're fortunate enough to have some zines incorporate Repressed Records into the narrative through artwork or events."
413 King Street, Newtown
Red Eye Records
Red Eye Records, while not strictly within the Inner West jurisdiction, stocks a swag of music-related zines. The number of zines they have in stock depends on how many are brought in. According to Red Eye, some zines attract a cult following and sell well. Others are the result of individuals simply wanting to create zines and share their work. "We like to support people's passions", Red Eye Records told Ciao. They most likely have something for everyone, with a diverse clientele that ranges from teenagers to 80-year-olds, and everyone in between. What to zines offer to the music community, according to Red Eye? Fun.
143 York Street, Sydney
Verge Gallery
A non-for-profit exhibition space located the University of Sydney's Darlington campus, Verge Gallery has over 80 titles in their zine collection and offers visitors a reading room space to enjoy publications. It's worth checking out Verge's selected issues by The Refugee Art Project, which includes first-hand accounts, drawings, poems, and interviews with children and adults in Villawood detention centre. "Zines are a product of this intersect between art-making and publishing…It's important to exhibit zines in this creative environment because it promotes a do-it-yourself culture, creating alternative media platforms, sharing ideas and experiences, and connecting with others," says Director Sian McIntyre.
Jane Foss Russell Plaza, City Road, Darlington
Roadtest: Inner West Bookshops
Things we love – 226

redpajama_set_name: RedPajamaCommonCrawl


text:
Soviet Troops Roll Into Baltic Republics, Seize Key Media, Government Installations
TROOPS loyal to the Soviet Union's new hard-line government seized key installations in the Latvian capital of Riga on Aug. 19. They killed a minibus driver and wounded one of his passengers, the republic's radio reported.The shooting, the only death reported since the Kremlin takeover, came as the Soviet military staged a show of strength in the three separatist Baltic republics. Troops took control of Latvia's interior ministry and television center, and about 40 military vehicles rolled past the Lithuanian parliament, heavily barricaded since clashes last January which left 13 people dead. Troops set up a camp outside the capital, Vilnius. Troops also seized Lithuania's only remaining television tower, in the city of Kaunas, as well as the television studios there and the international telephone exchange. "We are now broadcasting only from our antenna in parliament," a parliamentary spokeswoman said. Two large columns were also spotted in Estonia, the third of the Baltic republics seeking to reclaim the independence they enjoyed before-World War II. The Estonian news agency ETA said Gen. Fyodor Kuzmin, appointed military commandant in the Baltic district, ordered separatist Estonian President Arnold Ruutel to dissolve all military formations and ban demonstrations. Ruutel had refused. Latvian radio reportedly quoted eyewitnesses as saying the two bus victims were shot by men in assault troopers' uniforms and black berets - a reference to elite troops under the jurisdiction of the Soviet interior ministry. The ministry was not immediately available for comment on the allegation. Leaders in all three Baltic republics denounced the takeover of power in the Soviet Union by the hard-line State of Emergency Committee, but other republics were more cautious. Lithuania's mass Sajudis nationalist movement said it would back a general strike in the republic - as called for by Russian leader Boris Yeltsin - if Mikhail Gorbachev's removal were followed by an attempt to oust the Vilnius government. From his barricaded parliament, nationalist Lithuanian President Vytautas Landsbergis urged peaceful resistance.
US is reported to be moving heavy arms to Baltic, Eastern Europe
Focus Baltic nations offer ex-Soviet states a Western model
Obama to Europe: NATO will oppose Russian aggression


text:
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2014-2022 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Andrey Abramov
/// @author Vasily Nabatchikov
////////////////////////////////////////////////////////////////////////////////

#include "IResearchFeature.h"

#include "Basics/DownCast.h"
#include "Basics/StaticStrings.h"

// otherwise define conflict between 3rdParty\date\include\date\date.h and
// 3rdParty\iresearch\core\shared.hpp
#if defined(_MSC_VER)
#include "date/date.h"
#endif

#include "search/scorers.hpp"
#include "utils/async_utils.hpp"
#include "utils/log.hpp"
#include "utils/file_utils.hpp"

#include "ApplicationServerHelper.h"
#include "Aql/AqlFunctionFeature.h"
#include "Aql/AqlValue.h"
#include "Aql/AqlValueMaterializer.h"
#include "Aql/ExpressionContext.h"
#include "Aql/Function.h"
#include "Aql/Functions.h"
#include "Basics/application-exit.h"
#include "Basics/ConditionLocker.h"
#include "Basics/NumberOfCores.h"
#include "Basics/StringUtils.h"
#include "Basics/application-exit.h"
#include "Cluster/ClusterFeature.h"
#include "Cluster/ClusterInfo.h"
#ifdef USE_ENTERPRISE
#include "Cluster/ClusterMethods.h"
#endif
#include "Cluster/ServerState.h"
#include "ClusterEngine/ClusterEngine.h"
#include "Containers/SmallVector.h"
#include "Metrics/GaugeBuilder.h"
#include "Metrics/MetricsFeature.h"
#include "IResearch/Containers.h"
#include "IResearch/IResearchCommon.h"
#include "IResearch/IResearchFilterFactory.h"
#include "IResearch/IResearchLinkCoordinator.h"
#include "IResearch/IResearchLinkHelper.h"
#include "IResearch/IResearchRocksDBLink.h"
#include "IResearch/IResearchRocksDBRecoveryHelper.h"
#include "IResearch/IResearchView.h"
#include "IResearch/IResearchViewCoordinator.h"
#include "IResearch/Search.h"
#include "IResearch/VelocyPackHelper.h"
#include "Logger/LogMacros.h"
#include "RestServer/DatabaseFeature.h"
#include "RestServer/DatabasePathFeature.h"
#include "RestServer/FlushFeature.h"
#include "RestServer/UpgradeFeature.h"
#include "RestServer/ViewTypesFeature.h"
#include "RocksDBEngine/RocksDBEngine.h"
#include "RocksDBEngine/RocksDBLogValue.h"
#include "StorageEngine/EngineSelectorFeature.h"
#include "StorageEngine/StorageEngine.h"
#include "StorageEngine/TransactionState.h"
#include "Transaction/Methods.h"
#include "VocBase/LogicalCollection.h"
#include "VocBase/LogicalDataSource.h"
#include "VocBase/LogicalView.h"

#include <absl/strings/str_cat.h>

using namespace std::chrono_literals;

DECLARE_GAUGE(arangodb_search_num_out_of_sync_links, uint64_t,
              "Number of arangosearch links/indexes currently out of sync");

#ifdef USE_ENTERPRISE
DECLARE_GAUGE(arangodb_search_columns_cache_size, int64_t,
              "ArangoSearch columns cache usage in bytes");
#endif

namespace arangodb::aql {
class Query;
}  // namespace arangodb::aql

namespace arangodb::iresearch {
namespace {

// Log topic implementation for IResearch
class IResearchLogTopic final : public LogTopic {
 public:
  explicit IResearchLogTopic(std::string const& name)
      : LogTopic(name, kDefaultLevel) {
    setIResearchLogLevel(kDefaultLevel);
  }

  virtual void setLogLevel(LogLevel level) override {
    LogTopic::setLogLevel(level);
    setIResearchLogLevel(level);
  }

 private:
  static LogLevel const kDefaultLevel = LogLevel::INFO;

  typedef std::underlying_type<irs::logger::level_t>::type irsLogLevelType;
  typedef std::underlying_type<LogLevel>::type arangoLogLevelType;

  static_assert(static_cast<irsLogLevelType>(irs::logger::IRL_FATAL) ==
                        static_cast<arangoLogLevelType>(LogLevel::FATAL) - 1 &&
                    static_cast<irsLogLevelType>(irs::logger::IRL_ERROR) ==
                        static_cast<arangoLogLevelType>(LogLevel::ERR) - 1 &&
                    static_cast<irsLogLevelType>(irs::logger::IRL_WARN) ==
                        static_cast<arangoLogLevelType>(LogLevel::WARN) - 1 &&
                    static_cast<irsLogLevelType>(irs::logger::IRL_INFO) ==
                        static_cast<arangoLogLevelType>(LogLevel::INFO) - 1 &&
                    static_cast<irsLogLevelType>(irs::logger::IRL_DEBUG) ==
                        static_cast<arangoLogLevelType>(LogLevel::DEBUG) - 1 &&
                    static_cast<irsLogLevelType>(irs::logger::IRL_TRACE) ==
                        static_cast<arangoLogLevelType>(LogLevel::TRACE) - 1,
                "inconsistent log level mapping");

  static void log_appender(void* context, const char* function,
                           const char* file, int line,
                           irs::logger::level_t level, const char* message,
                           size_t message_len);
  static void setIResearchLogLevel(LogLevel level) {
    if (level == LogLevel::DEFAULT) {
      level = kDefaultLevel;
    }

    auto irsLevel = static_cast<irs::logger::level_t>(
        static_cast<arangoLogLevelType>(level) - 1);  // -1 for DEFAULT

    irsLevel = std::max(irsLevel, irs::logger::IRL_FATAL);
    irsLevel = std::min(irsLevel, irs::logger::IRL_TRACE);
    irs::logger::output_le(irsLevel, log_appender, nullptr);
  }
};

IResearchLogTopic LIBIRESEARCH("libiresearch");

std::string const THREADS_PARAM("--arangosearch.threads");
std::string const THREADS_LIMIT_PARAM("--arangosearch.threads-limit");
std::string const COMMIT_THREADS_PARAM("--arangosearch.commit-threads");
std::string const COMMIT_THREADS_IDLE_PARAM(
    "--arangosearch.commit-threads-idle");
std::string const CONSOLIDATION_THREADS_PARAM(
    "--arangosearch.consolidation-threads");
std::string const CONSOLIDATION_THREADS_IDLE_PARAM(
    "--arangosearch.consolidation-threads-idle");
std::string const FAIL_ON_OUT_OF_SYNC(
    "--arangosearch.fail-queries-on-out-of-sync");
std::string const SKIP_RECOVERY("--arangosearch.skip-recovery");
std::string const CACHE_LIMIT("--arangosearch.columns-cache-limit");

aql::AqlValue dummyFunc(aql::ExpressionContext*, aql::AstNode const& node,
                        std::span<aql::AqlValue const>) {
  THROW_ARANGO_EXCEPTION_FORMAT(
      TRI_ERROR_NOT_IMPLEMENTED,
      "ArangoSearch function '%s' is designed to be used only within a "
      "corresponding SEARCH statement of ArangoSearch view. Please ensure "
      "function signature is correct.",
      getFunctionName(node).data());
}

aql::AqlValue offsetInfoFunc(aql::ExpressionContext* ctx,
                             aql::AstNode const& node,
                             std::span<aql::AqlValue const> args) {
#ifdef USE_ENTERPRISE
  return dummyFunc(ctx, node, args);
#else
  return aql::functions::NotImplementedEE(ctx, node, args);
#endif
}

// Function body for ArangoSearch context functions ANALYZER/BOOST.
// Just returns its first argument as outside ArangoSearch context
// there is nothing to do with search stuff, but optimization could roll.
aql::AqlValue contextFunc(aql::ExpressionContext* ctx, aql::AstNode const&,
                          std::span<aql::AqlValue const> args) {
  TRI_ASSERT(ctx);
  TRI_ASSERT(!args.empty());  // ensured by function signature

  aql::AqlValueMaterializer materializer(&ctx->trx().vpackOptions());
  return aql::AqlValue{materializer.slice(args[0], true)};
}

// Register invalid argument warning
inline aql::AqlValue errorAqlValue(aql::ExpressionContext* ctx,
                                   char const* afn) {
  aql::registerInvalidArgumentWarning(ctx, afn);
  return aql::AqlValue{aql::AqlValueHintNull{}};
}

// Executes STARTS_WITH function with const parameters locally the same way
// it will be done in ArangoSearch at runtime
// This will allow optimize out STARTS_WITH call if all arguments are const
aql::AqlValue startsWithFunc(aql::ExpressionContext* ctx, aql::AstNode const&,
                             std::span<aql::AqlValue const> args) {
  static char const* AFN = "STARTS_WITH";

  auto const argc = args.size();
  TRI_ASSERT(argc >= 2 && argc <= 4);  // ensured by function signature
  auto& value = args[0];

  if (!value.isString()) {
    return errorAqlValue(ctx, AFN);
  }
  auto const valueRef = value.slice().stringView();

  auto result = false;

  auto& prefixes = args[1];
  if (prefixes.isArray()) {
    auto const size = static_cast<int64_t>(prefixes.length());
    int64_t minMatchCount = FilterConstants::DefaultStartsWithMinMatchCount;
    if (argc > 2) {
      auto& minMatchCountValue = args[2];
      if (!minMatchCountValue.isNumber()) {
        return errorAqlValue(ctx, AFN);
      }
      minMatchCount = minMatchCountValue.toInt64();
      if (minMatchCount < 0) {
        return errorAqlValue(ctx, AFN);
      }
    }
    if (0 == minMatchCount) {
      result = true;
    } else if (minMatchCount <= size) {
      int64_t matchedCount = 0;
      for (int64_t i = 0; i < size; ++i) {
        auto mustDestroy = false;
        auto prefix = prefixes.at(i, mustDestroy, false);
        aql::AqlValueGuard guard{prefix, mustDestroy};
        if (!prefix.isString()) {
          return errorAqlValue(ctx, AFN);
        }
        if (valueRef.starts_with(prefix.slice().stringView()) &&
            ++matchedCount == minMatchCount) {
          result = true;
          break;
        }
      }
    }
  } else {
    if (!prefixes.isString()) {
      return errorAqlValue(ctx, AFN);
    }
    result = valueRef.starts_with(prefixes.slice().stringView());
  }
  return aql::AqlValue{aql::AqlValueHintBool{result}};
}

/// Executes MIN_MATCH function with const parameters locally the same way
/// it will be done in ArangoSearch at runtime
/// This will allow optimize out MIN_MATCH call if all arguments are const
aql::AqlValue minMatchFunc(aql::ExpressionContext* ctx, aql::AstNode const&,
                           std::span<aql::AqlValue const> args) {
  static char const* AFN = "MIN_MATCH";

  TRI_ASSERT(args.size() > 1);  // ensured by function signature
  auto& minMatchValue = args.back();
  if (ADB_UNLIKELY(!minMatchValue.isNumber())) {
    return errorAqlValue(ctx, AFN);
  }

  auto matchesLeft = minMatchValue.toInt64();
  const auto argsCount = args.size() - 1;
  for (size_t i = 0; i < argsCount && matchesLeft > 0; ++i) {
    auto& currValue = args[i];
    if (currValue.toBoolean()) {
      matchesLeft--;
    }
  }

  return aql::AqlValue(aql::AqlValueHintBool(matchesLeft == 0));
}

aql::AqlValue dummyScorerFunc(aql::ExpressionContext*, aql::AstNode const& node,
                              std::span<aql::AqlValue const>) {
  THROW_ARANGO_EXCEPTION_FORMAT(
      TRI_ERROR_NOT_IMPLEMENTED,
      "ArangoSearch scorer function '%s' are designed to "
      "be used only outside SEARCH statement within a context of ArangoSearch "
      "view. Please ensure function signature is correct.",
      aql::getFunctionName(node).data());
}

uint32_t computeIdleThreadsCount(uint32_t idleThreads,
                                 uint32_t threads) noexcept {
  if (0 == idleThreads) {
    return std::max(threads / 2, 1U);
  } else {
    return std::min(idleThreads, threads);
  }
}

uint32_t computeThreadsCount(uint32_t threads, uint32_t threadsLimit,
                             uint32_t div) noexcept {
  TRI_ASSERT(div);
  // arbitrary limit on the upper bound of threads in pool
  constexpr uint32_t MAX_THREADS = 8;
  constexpr uint32_t MIN_THREADS = 1;  // at least one thread is required

  return std::max(
      MIN_THREADS,
      std::min(threadsLimit ? threadsLimit : MAX_THREADS,
               threads ? threads : uint32_t(NumberOfCores::getValue()) / div));
}

bool upgradeArangoSearchLinkCollectionName(
    TRI_vocbase_t& vocbase, velocypack::Slice const& /*upgradeParams*/) {
  using application_features::ApplicationServer;
  if (!ServerState::instance()->isDBServer()) {
    return true;  // not applicable for other ServerState roles
  }
  auto& selector = vocbase.server().getFeature<EngineSelectorFeature>();
  auto& clusterInfo =
      vocbase.server().getFeature<ClusterFeature>().clusterInfo();
  // persist collection names in links
  for (auto& collection : vocbase.collections(false)) {
    auto indexes = collection->getIndexes();
    std::string clusterCollectionName;
    if (!collection->shardIds()->empty()) {
      unsigned tryCount{60};
      do {
        LOG_TOPIC("423b3", TRACE, arangodb::iresearch::TOPIC)
            << " Checking collection '" << collection->name()
            << "' in database '" << vocbase.name() << "'";
        // we use getCollectionNameForShard as getCollectionNT here is still not
        // available but shard-collection mapping is loaded eventually
        clusterCollectionName =
            clusterInfo.getCollectionNameForShard(collection->name());
        if (!clusterCollectionName.empty()) {
          break;
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
      } while (--tryCount);
    } else {
      clusterCollectionName = collection->name();
    }
    if (!clusterCollectionName.empty()) {
      LOG_TOPIC("773b4", TRACE, arangodb::iresearch::TOPIC)
          << " Processing collection " << clusterCollectionName;
#ifdef USE_ENTERPRISE
      ClusterMethods::realNameFromSmartName(clusterCollectionName);
#endif
      for (auto& index : indexes) {
        if (index->type() == Index::IndexType::TRI_IDX_TYPE_IRESEARCH_LINK) {
          auto indexPtr = dynamic_cast<IResearchLink*>(index.get());
          if (indexPtr) {
            LOG_TOPIC("d6edb", TRACE, arangodb::iresearch::TOPIC)
                << "Checking collection name '" << clusterCollectionName
                << "' for link " << indexPtr->id().id();
            if (indexPtr->setCollectionName(clusterCollectionName)) {
              LOG_TOPIC("b269d", INFO, arangodb::iresearch::TOPIC)
                  << "Setting collection name '" << clusterCollectionName
                  << "' for link " << indexPtr->id().id();
              if (selector.engineName() == RocksDBEngine::kEngineName) {
                auto& engine = selector.engine<RocksDBEngine>();
                auto builder = collection->toVelocyPackIgnore(
                    {"path", "statusString"}, LogicalDataSource::Serialization::
                                                  PersistenceWithInProgress);
                auto res = engine.writeCreateCollectionMarker(
                    vocbase.id(), collection->id(), builder.slice(),
                    RocksDBLogValue::Empty());
                if (res.fail()) {
                  LOG_TOPIC("50ace", WARN, arangodb::iresearch::TOPIC)
                      << "Unable to store updated link information on upgrade "
                         "for collection '"
                      << clusterCollectionName << "' for link "
                      << indexPtr->id().id() << ": " << res.errorMessage();
                }
#ifdef ARANGODB_USE_GOOGLE_TESTS
              } else if (selector.engineName() !=
                         "Mock") {  // for unit tests just ignore write to
                                    // storage
#else
              } else {
#endif
                TRI_ASSERT(false);
                LOG_TOPIC("d6edc", WARN, arangodb::iresearch::TOPIC)
                    << "Unsupported engine '" << selector.engineName()
                    << "' for link upgrade task";
              }
            }
          }
        }
      }
    } else {
      LOG_TOPIC("d61d3", WARN, arangodb::iresearch::TOPIC)
          << "Failed to find collection name for shard '" << collection->name()
          << "'!";
    }
  }
  return true;
}

bool upgradeSingleServerArangoSearchView0_1(
    TRI_vocbase_t& vocbase, velocypack::Slice const& /*upgradeParams*/) {
  using application_features::ApplicationServer;

  if (!ServerState::instance()->isSingleServer() &&
      !ServerState::instance()->isDBServer()) {
    return true;  // not applicable for other ServerState roles
  }

  for (auto& view : vocbase.views()) {
    if (!basics::downCast<IResearchView>(view.get())) {
      continue;  // not an IResearchView
    }

    velocypack::Builder builder;

    builder.openObject();
    // get JSON with meta + 'version'
    Result res = view->properties(
        builder, LogicalDataSource::Serialization::Persistence);
    builder.close();

    if (!res.ok()) {
      LOG_TOPIC("c5dc4", WARN, arangodb::iresearch::TOPIC)
          << "failure to generate persisted definition while upgrading "
             "IResearchView from version 0 to version 1";

      return false;  // definition generation failure
    }

    auto versionSlice =
        builder.slice().get(arangodb::iresearch::StaticStrings::VersionField);

    if (!versionSlice.isNumber<uint32_t>()) {
      LOG_TOPIC("eae1c", WARN, arangodb::iresearch::TOPIC)
          << "failure to find 'version' field while upgrading IResearchView "
             "from version 0 to version 1";

      return false;  // required field is missing
    }

    auto const version = versionSlice.getNumber<uint32_t>();

    if (0 != version) {
      continue;  // no upgrade required
    }

    builder.clear();
    builder.openObject();
    // get JSON with end-user definition
    res =
        view->properties(builder, LogicalDataSource::Serialization::Properties);
    builder.close();

    if (!res.ok()) {
      LOG_TOPIC("d6e30", WARN, arangodb::iresearch::TOPIC)
          << "failure to generate persisted definition while upgrading "
             "IResearchView from version 0 to version 1";

      return false;  // definition generation failure
    }

    std::filesystem::path dataPath;

    auto& server = vocbase.server();
    if (!server.hasFeature<DatabasePathFeature>()) {
      LOG_TOPIC("67c7e", WARN, arangodb::iresearch::TOPIC)
          << "failure to find feature 'DatabasePath' while upgrading "
             "IResearchView from version 0 to version 1";

      return false;  // required feature is missing
    }
    auto& dbPathFeature = server.getFeature<DatabasePathFeature>();

    // original algorithm for computing data-store path
    dataPath = std::filesystem::path(dbPathFeature.directory());
    dataPath /= "databases";
    dataPath /= "database-";
    dataPath += std::to_string(vocbase.id());
    dataPath /= arangodb::iresearch::StaticStrings::ViewArangoSearchType;
    dataPath += "-";
    dataPath += std::to_string(view->id().id());

    res = view->drop();  // drop view (including all links)

    if (!res.ok()) {
      LOG_TOPIC("cb9d1", WARN, arangodb::iresearch::TOPIC)
          << "failure to drop view while upgrading IResearchView from version "
             "0 to version 1";

      return false;  // view drom failure
    }

    // .........................................................................
    // non-recoverable state below here
    // .........................................................................

    // non-version 0 IResearchView implementations no longer drop from vocbase
    // on db-server, do it explicitly
    if (ServerState::instance()->isDBServer()) {
      res = storage_helper::drop(*view);

      if (!res.ok()) {
        LOG_TOPIC("bfb3d", WARN, arangodb::iresearch::TOPIC)
            << "failure to drop view from vocbase while upgrading "
               "IResearchView from version 0 to version 1";

        return false;  // view drom failure
      }
    }

    if (ServerState::instance()->isSingleServer() ||
        ServerState::instance()->isDBServer()) {
      bool exists;

      // remove any stale data-store
      if (!irs::file_utils::exists_directory(exists, dataPath.c_str()) ||
          (exists && !irs::file_utils::remove(dataPath.c_str()))) {
        LOG_TOPIC("9ab42", WARN, arangodb::iresearch::TOPIC)
            << "failure to remove old data-store path while upgrading "
               "IResearchView from version 0 to version 1, view definition: "
            << builder.slice().toString();

        return false;  // data-store removal failure
      }
    }

    if (ServerState::instance()->isDBServer()) {
      continue;  // no need to recreate per-cid view
    }

    // recreate view
    res = arangodb::iresearch::IResearchView::factory().create(
        view, vocbase, builder.slice(), true);

    if (!res.ok()) {
      LOG_TOPIC("f8d20", WARN, arangodb::iresearch::TOPIC)
          << "failure to recreate view while upgrading IResearchView from "
             "version 0 to version 1, error: "
          << res.errorNumber() << " " << res.errorMessage()
          << ", view definition: " << builder.slice().toString();

      return false;  // data-store removal failure
    }
  }

  return true;
}

void registerFilters(aql::AqlFunctionFeature& functions) {
  using arangodb::iresearch::addFunction;

  constexpr auto flags = aql::Function::makeFlags(
      aql::Function::Flags::Deterministic, aql::Function::Flags::Cacheable,
      aql::Function::Flags::CanRunOnDBServerCluster,
      aql::Function::Flags::CanRunOnDBServerOneShard,
      aql::Function::Flags::CanUseInAnalyzer);

  constexpr auto flagsNoAnalyzer = aql::Function::makeFlags(
      aql::Function::Flags::Deterministic, aql::Function::Flags::Cacheable,
      aql::Function::Flags::CanRunOnDBServerCluster,
      aql::Function::Flags::CanRunOnDBServerOneShard);

  // (attribute, ["analyzer"|"type"|"string"|"numeric"|"bool"|"null"]).
  // cannot be used in analyzers!
  addFunction(functions, {"EXISTS", ".|.,.", flagsNoAnalyzer, &dummyFunc});

  // (attribute, [ '[' ] prefix [, prefix, ... ']' ] [,
  // scoring-limit|min-match-count ] [, scoring-limit ])
  addFunction(functions, {"STARTS_WITH", ".,.|.,.", flags, &startsWithFunc});

  // (attribute, input [, offset, input... ] [, analyzer])
  // cannot be used in analyzers!
  addFunction(functions, {"PHRASE", ".,.|.+", flagsNoAnalyzer, &dummyFunc});

  // (filter expression [, filter expression, ... ], min match count)
  addFunction(functions, {"MIN_MATCH", ".,.|.+", flags, &minMatchFunc});

  // (filter expression, boost)
  addFunction(functions, {"BOOST", ".,.", flags, &contextFunc});

  // (filter expression, analyzer)
  // cannot be used in analyzers!
  addFunction(functions, {"ANALYZER", ".,.", flagsNoAnalyzer, &contextFunc});
}

namespace {
template<typename T>
void registerSingleFactory(
    std::map<std::type_index, std::shared_ptr<IndexTypeFactory>> const& m,
    ArangodServer& server) {
  TRI_ASSERT(m.find(std::type_index(typeid(T))) != m.end());
  IndexTypeFactory& factory = *m.find(std::type_index(typeid(T)))->second;
  if (server.hasFeature<T>()) {
    auto& engine = server.getFeature<T>();
    auto& engineFactory = const_cast<IndexFactory&>(engine.indexFactory());
    Result res = engineFactory.emplace(
        std::string{arangodb::iresearch::StaticStrings::ViewArangoSearchType},
        factory);
    if (!res.ok()) {
      THROW_ARANGO_EXCEPTION_MESSAGE(
          res.errorNumber(),
          basics::StringUtils::concatT(
              "failure registering IResearch link factory with index "
              "factory from feature '",
              engine.name(), "': ", res.errorMessage()));
    }
  }
}

}  // namespace

void registerFunctions(aql::AqlFunctionFeature& functions) {
  arangodb::iresearch::addFunction(
      functions,
      {"OFFSET_INFO", ".,.",
       aql::Function::makeFlags(aql::Function::Flags::Deterministic,
                                aql::Function::Flags::Cacheable,
                                aql::Function::Flags::CanRunOnDBServerCluster,
                                aql::Function::Flags::CanRunOnDBServerOneShard,
                                aql::Function::Flags::NoEval),
       &offsetInfoFunc});
}

void registerIndexFactory(
    std::map<std::type_index, std::shared_ptr<IndexTypeFactory>>& m,
    ArangodServer& server) {
  m.emplace(
      std::type_index(typeid(ClusterEngine)),
      arangodb::iresearch::IResearchLinkCoordinator::createFactory(server));
  registerSingleFactory<ClusterEngine>(m, server);
  m.emplace(std::type_index(typeid(RocksDBEngine)),
            arangodb::iresearch::IResearchRocksDBLink::createFactory(server));
  registerSingleFactory<RocksDBEngine>(m, server);
}

void registerScorers(aql::AqlFunctionFeature& functions) {
  // positional arguments (attribute [<scorer-specific properties>...]);
  std::string_view constexpr args(".|+");

  irs::scorers::visit(
      [&functions, &args](std::string_view name,
                          irs::type_info const& args_format) -> bool {
        // ArangoDB, for API consistency, only supports scorers configurable via
        // jSON
        if (irs::type<irs::text_format::json>::id() != args_format.id()) {
          return true;
        }

        auto upperName = static_cast<std::string>(name);

        // AQL function external names are always in upper case
        std::transform(upperName.begin(), upperName.end(), upperName.begin(),
                       ::toupper);

        // scorers are not usable in analyzers
        arangodb::iresearch::addFunction(
            functions, {std::move(upperName), args.data(),
                        aql::Function::makeFlags(
                            aql::Function::Flags::Deterministic,
                            aql::Function::Flags::Cacheable,
                            aql::Function::Flags::CanRunOnDBServerCluster,
                            aql::Function::Flags::CanRunOnDBServerOneShard),
                        &dummyScorerFunc});

        LOG_TOPIC("f42f9", TRACE, arangodb::iresearch::TOPIC)
            << "registered ArangoSearch scorer '" << upperName << "'";

        return true;
      });
}

void registerUpgradeTasks(ArangodServer& server) {
  if (!server.hasFeature<UpgradeFeature>()) {
    return;  // nothing to register with (OK if no tasks actually need to be
             // applied)
  }
  auto& upgrade = server.getFeature<UpgradeFeature>();

  // move IResearch data-store from IResearchView to IResearchLink
  {
    methods::Upgrade::Task task;

    task.name = "upgradeArangoSearch0_1";
    task.description =
        "store ArangoSearch index on per linked collection basis";
    task.systemFlag = methods::Upgrade::Flags::DATABASE_ALL;
    task.clusterFlags =
        methods::Upgrade::Flags::CLUSTER_DB_SERVER_LOCAL  // db-server
        | methods::Upgrade::Flags::CLUSTER_NONE           // local server
        | methods::Upgrade::Flags::CLUSTER_LOCAL;
    task.databaseFlags = methods::Upgrade::Flags::DATABASE_UPGRADE |
                         // seal the task after execution
                         methods::Upgrade::Flags::DATABASE_ONLY_ONCE;
    task.action = &upgradeSingleServerArangoSearchView0_1;
    upgrade.addTask(std::move(task));
  }

  // store collection name in IResearchLinkMeta for cluster
  {
    methods::Upgrade::Task task;

    task.name = "upgradeArangoSearchLinkCollectionName";
    task.description = "store collection name in ArangoSearch Link`s metadata";
    task.systemFlag = methods::Upgrade::Flags::DATABASE_ALL;
    // will be run only by cluster bootstrap and database init (latter case it
    // will just do nothing but flags don`t allow to distinguih cases)
    task.clusterFlags = methods::Upgrade::Flags::CLUSTER_DB_SERVER_LOCAL |
                        methods::Upgrade::Flags::CLUSTER_LOCAL;  // db-server
    task.databaseFlags = methods::Upgrade::Flags::DATABASE_EXISTING |
                         // seal the task after execution
                         methods::Upgrade::Flags::DATABASE_ONLY_ONCE;
    task.action = &upgradeArangoSearchLinkCollectionName;
    upgrade.addTask(std::move(task));
  }
}

void registerViewFactory(ArangodServer& server) {
  Result r;
  auto check = [&] {
    if (!r.ok()) {
      THROW_ARANGO_EXCEPTION_MESSAGE(
          r.errorNumber(),
          absl::StrCat("failure registering arangosearch view factory: ",
                       r.errorMessage()));
    }
  };
  // DB server in custer or single-server
  auto& viewTypes = server.getFeature<ViewTypesFeature>();
  if (ServerState::instance()->isCoordinator()) {
    r = viewTypes.emplace(
        arangodb::iresearch::StaticStrings::ViewArangoSearchType,
        IResearchViewCoordinator::factory());
    check();
    r = viewTypes.emplace(
        arangodb::iresearch::StaticStrings::ViewSearchAliasType,
        Search::factory());
  } else if (ServerState::instance()->isSingleServer()) {
    r = viewTypes.emplace(
        arangodb::iresearch::StaticStrings::ViewArangoSearchType,
        IResearchView::factory());
    check();
    r = viewTypes.emplace(
        arangodb::iresearch::StaticStrings::ViewSearchAliasType,
        Search::factory());
  } else if (ServerState::instance()->isDBServer()) {
    r = viewTypes.emplace(
        arangodb::iresearch::StaticStrings::ViewArangoSearchType,
        IResearchView::factory());
  } else {
    THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_FAILED,
                                   "Invalid role for view creation.");
  }
  check();
}

Result transactionDataSourceRegistrationCallback(LogicalDataSource& dataSource,
                                                 transaction::Methods& trx) {
  if (LogicalView::category() != dataSource.category()) {
    return {};  // not a view
  }
  // TODO FIXME find a better way to look up a LogicalView
  auto* view = basics::downCast<LogicalView>(&dataSource);
  if (!view) {
    LOG_TOPIC("f42f8", WARN, arangodb::iresearch::TOPIC)
        << "failure to get LogicalView while processing a TransactionState by "
           "IResearchFeature for name '"
        << dataSource.name() << "'";

    return {TRI_ERROR_INTERNAL};
  }

  if (view->type() == ViewType::kSearchAlias) {
    auto& impl = basics::downCast<Search>(*view);
    return {impl.apply(trx) ? TRI_ERROR_NO_ERROR : TRI_ERROR_INTERNAL};
  } else if (view->type() == ViewType::kArangoSearch) {
    auto& impl = basics::downCast<IResearchView>(*view);
    return {impl.apply(trx) ? TRI_ERROR_NO_ERROR : TRI_ERROR_INTERNAL};
  }
  return {};  // not a needed view
}

void registerTransactionDataSourceRegistrationCallback() {
  if (ServerState::instance()->isSingleServer()) {
    transaction::Methods::addDataSourceRegistrationCallback(
        &transactionDataSourceRegistrationCallback);
  }
}

void IResearchLogTopic::log_appender(void* /*context*/, const char* function,
                                     const char* file, int line,
                                     irs::logger::level_t level,
                                     const char* message, size_t message_len) {
  auto const arangoLevel = static_cast<LogLevel>(level + 1);
  std::string msg(message, message_len);
  Logger::log("9afd3", function, file, line, arangoLevel, LIBIRESEARCH.id(),
              msg);
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
/// @class IResearchAsync
/// @brief helper class for holding thread groups
////////////////////////////////////////////////////////////////////////////////
class IResearchAsync {
 public:
  using ThreadPool = irs::async_utils::thread_pool;

  ~IResearchAsync() { stop(); }

  ThreadPool& get(ThreadGroup id)
#ifndef ARANGODB_ENABLE_FAILURE_TESTS
      noexcept
#endif
  {
    TRI_IF_FAILURE("IResearchFeature::testGroupAccess") {
      THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
    }

    TRI_ASSERT(static_cast<size_t>(id) < 2);
    return (ThreadGroup::_0 == id) ? _0 : _1;
  }

  void stop() noexcept {
    try {
      _0.stop(true);
    } catch (...) {
    }
    try {
      _1.stop(true);
    } catch (...) {
    }
  }

 private:
  ThreadPool _0{0, 0, IR_NATIVE_STRING("ARS-0")};
  ThreadPool _1{0, 0, IR_NATIVE_STRING("ARS-1")};
};  // IResearchAsync

bool isFilter(aql::Function const& func) noexcept {
  return func.implementation == &dummyFunc ||
         func.implementation == &contextFunc ||
         func.implementation == &minMatchFunc ||
         func.implementation == &startsWithFunc ||
         func.implementation == &aql::functions::MinHashMatch ||
         func.implementation == &aql::functions::GeoContains ||
         func.implementation == &aql::functions::GeoInRange ||
         func.implementation == &aql::functions::GeoIntersects ||
         func.implementation == &aql::functions::GeoDistance ||
         func.implementation == &aql::functions::LevenshteinMatch ||
         func.implementation == &aql::functions::Like ||
         func.implementation == &aql::functions::NgramMatch ||
         func.implementation == &aql::functions::InRange;
}

bool isScorer(aql::Function const& func) noexcept {
  return func.implementation == &dummyScorerFunc;
}

bool isOffsetInfo(aql::Function const& func) noexcept {
  return func.implementation == &offsetInfoFunc;
}

IResearchFeature::IResearchFeature(Server& server)
    : ArangodFeature{server, *this},
      _async(std::make_unique<IResearchAsync>()),
      _running(false),
      _failQueriesOnOutOfSync(false),
      _consolidationThreads(0),
      _consolidationThreadsIdle(0),
      _commitThreads(0),
      _commitThreadsIdle(0),
      _threads(0),
      _threadsLimit(0),
      _outOfSyncLinks(server.getFeature<metrics::MetricsFeature>().add(
          arangodb_search_num_out_of_sync_links{}))
#ifdef USE_ENTERPRISE
      ,
      _columnsCacheMemoryUsed(server.getFeature<metrics::MetricsFeature>().add(
          arangodb_search_columns_cache_size{}))
#endif
{
  setOptional(true);
  startsAfter<application_features::V8FeaturePhase>();
  startsAfter<IResearchAnalyzerFeature>();
  startsAfter<aql::AqlFunctionFeature>();
}

void IResearchFeature::beginShutdown() { _running.store(false); }

void IResearchFeature::collectOptions(
    std::shared_ptr<options::ProgramOptions> options) {
  _running.store(false);
  options->addSection("arangosearch", std::string{name()}.append(" feature"));

  options
      ->addOption(THREADS_PARAM,
                  "The exact number of threads to use for asynchronous "
                  "tasks (0 = auto-detect).",
                  new options::UInt32Parameter(&_threads))
      .setDeprecatedIn(30705)
      .setLongDescription(R"(From version 3.7.5 on, you should set the commit
and consolidation thread counts separately via the following options instead:

- `--arangosearch.commit-threads`
- `--arangosearch.commit-threads-idle`
- `--arangosearch.consolidation-threads`
- `--arangosearch.consolidation-threads-idle`

If either `--arangosearch.commit-threads` or
`--arangosearch.consolidation-threads` is set, then `--arangosearch.threads` and
`arangosearch.threads-limit` are ignored. If only the legacy options are set,
then the commit and consolidation thread counts are calculated as follows:

- Maximum: The smaller value out of `--arangosearch.threads` and
  `arangosearch.threads-limit` divided by 2, but at least 1.
- Minimum: the maximum divided by 2, but at least 1.\n)");

  options
      ->addOption(
          THREADS_LIMIT_PARAM,
          "The upper limit to the auto-detected number of threads to use "
          "for asynchronous tasks (0 = use default).",
          new options::UInt32Parameter(&_threadsLimit))
      .setDeprecatedIn(30705)
      .setLongDescription(R"(From version 3.7.5 on, you should set the commit
and consolidation thread counts separately via the following options instead:

- `--arangosearch.commit-threads`
- `--arangosearch.commit-threads-idle`
- `--arangosearch.consolidation-threads`
- `--arangosearch.consolidation-threads-idle`

If either `--arangosearch.commit-threads` or
`--arangosearch.consolidation-threads` is set, then `--arangosearch.threads` and
`arangosearch.threads-limit` are ignored. If only the legacy options are set,
then the commit and consolidation thread counts are calculated as follows:

- Maximum: The smaller value out of `--arangosearch.threads` and
  `arangosearch.threads-limit` divided by 2, but at least 1.
- Minimum: the maximum divided by 2, but at least 1.)");

  options
      ->addOption(
          CONSOLIDATION_THREADS_PARAM,
          "The upper limit to the allowed number of consolidation threads "
          "(0 = auto-detect).",
          new options::UInt32Parameter(&_consolidationThreads))
      .setIntroducedIn(30705)
      .setLongDescription(R"(The option value must fall in the range
`[ 1..arangosearch.consolidation-threads ]`. Set it to `0` to automatically
choose a sensible number based on the number of cores in the system.)");

  options
      ->addOption(
          CONSOLIDATION_THREADS_IDLE_PARAM,
          "The upper limit to the allowed number of idle threads to use "
          "for consolidation tasks (0 = auto-detect).",
          new options::UInt32Parameter(&_consolidationThreadsIdle))
      .setIntroducedIn(30705);

  options
      ->addOption(COMMIT_THREADS_PARAM,
                  "The upper limit to the allowed number of commit threads "
                  "(0 = auto-detect).",
                  new options::UInt32Parameter(&_commitThreads))
      .setIntroducedIn(30705)
      .setLongDescription(R"(The option value must fall in the range
`[ 1..4 * NumberOfCores ]`. Set it to `0` to automatically choose a sensible
number based on the number of cores in the system.)");

  options
      ->addOption(
          COMMIT_THREADS_IDLE_PARAM,
          "The upper limit to the allowed number of idle threads to use "
          "for commit tasks (0 = auto-detect)",
          new options::UInt32Parameter(&_commitThreadsIdle))
      .setIntroducedIn(30705)
      .setLongDescription(R"(The option value must fall in the range
`[ 1..arangosearch.commit-threads ]`. Set it to `0` to automatically choose a
sensible number based on the number of cores in the system.)");

  options
      ->addOption(
          SKIP_RECOVERY,  // TODO: Move parts of the descriptions to
                          // longDescription?
          "Skip the data recovery for the specified View link or inverted "
          "index on startup. The value for this option needs to have the "
          "format '<collection-name>/<index-id>' or "
          "'<collection-name>/<index-name>'. You can use the option multiple "
          "times, for each View link and inverted index to skip the recovery "
          "for. The pseudo-value 'all' disables the recovery for all View "
          "links and inverted indexes. The links/indexes skipped during the "
          "recovery are marked as out-of-sync when the recovery completes. You "
          "need to recreate them manually afterwards.\n"
          "WARNING: Using this option causes data of affected links/indexes to "
          "become incomplete or more incomplete until they have been manually "
          "recreated.",
          new options::VectorParameter<options::StringParameter>(
              &_skipRecoveryItems))
      .setIntroducedIn(30904);

  options
      ->addOption(FAIL_ON_OUT_OF_SYNC,
                  "Whether retrieval queries on out-of-sync "
                  "View links and inverted indexes should fail.",
                  new options::BooleanParameter(&_failQueriesOnOutOfSync))
      .setIntroducedIn(30904)
      .setLongDescription(R"(If set to `true`, any data retrieval queries on
out-of-sync links/indexes fail with the error 'collection/view is out of sync'
(error code 1481).

If set to `false`, queries on out-of-sync links/indexes are answered normally,
but the returned data may be incomplete.)");

#ifdef USE_ENTERPRISE
  options
      ->addOption(CACHE_LIMIT,
                  "The limit (in bytes) for ArangoSearch columns cache "
                  "(0 = no caching).",
                  new options::UInt64Parameter(&_columnsCacheLimit),
                  arangodb::options::makeDefaultFlags(
                      arangodb::options::Flags::DefaultNoComponents,
                      arangodb::options::Flags::OnSingle,
                      arangodb::options::Flags::OnDBServer,
                      arangodb::options::Flags::Enterprise))
      .setIntroducedIn(30905);
#endif
}

void IResearchFeature::validateOptions(
    std::shared_ptr<options::ProgramOptions> options) {
  // validate all entries in _skipRecoveryItems for formal correctness
  for (auto const& item : _skipRecoveryItems) {
    if (item != "all" && basics::StringUtils::split(item, '/').size() != 2) {
      LOG_TOPIC("b9f28", FATAL, arangodb::iresearch::TOPIC)
          << "invalid format for '" << SKIP_RECOVERY
          << "' parameter. expecting '"
          << "<collection-name>/<index-id>' or "
             "'<collection-name>/<index-name>' or "
          << "'all', got: '" << item << "'";
      FATAL_ERROR_EXIT();
    }
  }

  auto const& args = options->processingResult();
  bool const threadsSet = args.touched(THREADS_PARAM);
  bool const threadsLimitSet = args.touched(THREADS_LIMIT_PARAM);
  bool const commitThreadsSet = args.touched(COMMIT_THREADS_PARAM);
  bool const commitThreadsIdleSet = args.touched(COMMIT_THREADS_IDLE_PARAM);
  bool const consolidationThreadsSet =
      args.touched(CONSOLIDATION_THREADS_PARAM);
  bool const consolidationThreadsIdleSet =
      args.touched(CONSOLIDATION_THREADS_IDLE_PARAM);

  uint32_t threadsLimit = static_cast<uint32_t>(4 * NumberOfCores::getValue());

  if ((threadsLimitSet || threadsSet) && !commitThreadsSet &&
      !consolidationThreadsSet) {
    // backwards compatibility
    threadsLimit = std::min(threadsLimit, _threadsLimit);
    uint32_t const threads = computeThreadsCount(_threads, threadsLimit, 4);
    _commitThreads = std::max(threads / 2, 1U);
    _consolidationThreads = _commitThreads;
  } else {
    _commitThreads = computeThreadsCount(_commitThreads, threadsLimit, 6);
    _consolidationThreads =
        computeThreadsCount(_consolidationThreads, threadsLimit, 6);
  }

  _commitThreadsIdle =
      commitThreadsIdleSet
          ? computeIdleThreadsCount(_commitThreadsIdle, _commitThreads)
          : _commitThreads;

  _consolidationThreadsIdle =
      consolidationThreadsIdleSet
          ? computeIdleThreadsCount(_consolidationThreadsIdle,
                                    _consolidationThreads)
          : _consolidationThreads;

  _running.store(false);
}

void IResearchFeature::prepare() {
  TRI_ASSERT(isEnabled());

  _running.store(false);

  // load all known codecs
  ::irs::formats::init();

  // load all known scorers
  ::irs::scorers::init();

  // register 'arangosearch' index
  registerIndexFactory(_factories, server());

  // register 'arangosearch' view
  registerViewFactory(server());

  // register 'arangosearch' Transaction DataSource registration callback
  registerTransactionDataSourceRegistrationCallback();

  registerRecoveryHelper();

  // register filters
  if (server().hasFeature<aql::AqlFunctionFeature>()) {
    auto& functions = server().getFeature<aql::AqlFunctionFeature>();
    registerFilters(functions);
    registerScorers(functions);
    registerFunctions(functions);
  } else {
    LOG_TOPIC("462d7", WARN, arangodb::iresearch::TOPIC)
        << "failure to find feature 'AQLFunctions' while registering "
           "arangosearch filters";
  }

  // ensure no tasks are scheduled and no threads are started
  TRI_ASSERT(std::make_tuple(size_t(0), size_t(0), size_t(0)) ==
             stats(ThreadGroup::_0));
  TRI_ASSERT(std::make_tuple(size_t(0), size_t(0), size_t(0)) ==
             stats(ThreadGroup::_1));

  // submit tasks to ensure that at least 1 worker for each group is started
  if (ServerState::instance()->isDBServer() ||
      ServerState::instance()->isSingleServer()) {
    _startState = std::make_shared<State>();

    auto submitTask = [this](ThreadGroup group) {
      return queue(group, 0ms, [state = _startState]() noexcept {
        {
          std::lock_guard lock{state->mtx};
          ++state->counter;
        }
        state->cv.notify_one();
      });
    };

    if (!submitTask(ThreadGroup::_0) || !submitTask(ThreadGroup::_1)) {
      THROW_ARANGO_EXCEPTION_MESSAGE(
          TRI_ERROR_SYS_ERROR,
          "failed to initialize ArangoSearch maintenance threads");
    }

    TRI_ASSERT(std::make_tuple(size_t(0), size_t(1), size_t(0)) ==
               stats(ThreadGroup::_0));
    TRI_ASSERT(std::make_tuple(size_t(0), size_t(1), size_t(0)) ==
               stats(ThreadGroup::_1));
  }
}

void IResearchFeature::start() {
  TRI_ASSERT(isEnabled());

  // register tasks after UpgradeFeature::prepare() has finished
  registerUpgradeTasks(server());

  // ensure that at least 1 worker for each group is started
  if (ServerState::instance()->isDBServer() ||
      ServerState::instance()->isSingleServer()) {
    TRI_ASSERT(_startState);
    TRI_ASSERT(_commitThreads && _commitThreadsIdle);
    TRI_ASSERT(_consolidationThreads && _consolidationThreadsIdle);

    _async->get(ThreadGroup::_0).limits(_commitThreads, _commitThreadsIdle);
    _async->get(ThreadGroup::_1)
        .limits(_consolidationThreads, _consolidationThreadsIdle);

    LOG_TOPIC("c1b63", INFO, arangodb::iresearch::TOPIC)
        << "ArangoSearch maintenance: "
        << "[" << _commitThreadsIdle << ".." << _commitThreads
        << "] commit thread(s), "
        << "[" << _consolidationThreadsIdle << ".." << _consolidationThreads
        << "] consolidation thread(s)";

#ifdef USE_ENTERPRISE
    LOG_TOPIC("c2c74", INFO, arangodb::iresearch::TOPIC)
        << "ArangoSearch columns cache limit: " << _columnsCacheLimit;
#endif

    {
      std::unique_lock lock{_startState->mtx};
      if (!_startState->cv.wait_for(
              lock, 60s, [this]() { return _startState->counter == 2; })) {
        THROW_ARANGO_EXCEPTION_MESSAGE(
            TRI_ERROR_SYS_ERROR,
            "failed to start ArangoSearch maintenance threads");
      }
    }

    // this can destroy the state instance, so we have to ensure that our lock
    // on _startState->mutex is already destroyed here!
    _startState = nullptr;
  }

  _running.store(true);
}

void IResearchFeature::stop() {
  TRI_ASSERT(isEnabled());
  _async->stop();
  _running.store(false);
}

void IResearchFeature::unprepare() {
  TRI_ASSERT(isEnabled());
  _running.store(false);
}

void IResearchFeature::reportRecoveryProgress(arangodb::IndexId id,
                                              std::string_view phase,
                                              size_t current, size_t total) {
  TRI_ASSERT(total != 0);
  auto now = std::chrono::system_clock::now();

  if (id != _progressState.lastReportId ||
      now - _progressState.lastReportTime >= std::chrono::minutes(1)) {
    // report progress only when index/link id changes or one minute has passed

    auto progress = static_cast<size_t>(100.0 * current / total);
    LOG_TOPIC("d1f18", INFO, TOPIC)
        << "recovering arangosearch index " << id << ", " << phase
        << ": operation " << (current + 1) << "/" << total << " (" << progress
        << "%)...";

    _progressState.lastReportId = id;
    _progressState.lastReportTime = now;
  }
}

bool IResearchFeature::queue(ThreadGroup id,
                             std::chrono::steady_clock::duration delay,
                             std::function<void()>&& fn) {
  try {
#ifdef ARANGODB_ENABLE_FAILURE_TESTS
    TRI_IF_FAILURE("IResearchFeature::queue") {
      THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
    }

    switch (id) {
      case ThreadGroup::_0:
        TRI_IF_FAILURE("IResearchFeature::queueGroup0") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
        }
        break;
      case ThreadGroup::_1:
        TRI_IF_FAILURE("IResearchFeature::queueGroup1") {
          THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
        }
        break;
      default:
        TRI_ASSERT(false);
        break;
    }
#endif

    if (_async->get(id).run(std::move(fn), delay)) {
      return true;
    }
  } catch (std::exception const& e) {
    LOG_TOPIC("c1b64", WARN, arangodb::iresearch::TOPIC)
        << "Caught exception while sumbitting a task to thread group '"
        << std::to_string(std::underlying_type_t<ThreadGroup>(id))
        << "' error '" << e.what() << "'";
  } catch (...) {
    LOG_TOPIC("c1b65", WARN, arangodb::iresearch::TOPIC)
        << "Caught an exception while sumbitting a task to thread group '"
        << std::to_string(std::underlying_type_t<ThreadGroup>(id)) << "'";
  }

  if (!server().isStopping()) {
    // do not log error at shutdown
    LOG_TOPIC("c1b66", ERR, arangodb::iresearch::TOPIC)
        << "Failed to submit a task to thread group '"
        << std::to_string(std::underlying_type_t<ThreadGroup>(id)) << "'";
  }

  return false;
}

std::tuple<size_t, size_t, size_t> IResearchFeature::stats(
    ThreadGroup id) const {
  return _async->get(id).stats();
}

std::pair<size_t, size_t> IResearchFeature::limits(ThreadGroup id) const {
  return _async->get(id).limits();
}

bool IResearchFeature::linkSkippedDuringRecovery(
    arangodb::IndexId id) const noexcept {
  if (_recoveryHelper != nullptr) {
    return _recoveryHelper->wasSkipped(id);
  }
  return false;
}

void IResearchFeature::trackOutOfSyncLink() noexcept { ++_outOfSyncLinks; }

void IResearchFeature::untrackOutOfSyncLink() noexcept {
  uint64_t previous = _outOfSyncLinks.fetch_sub(1);
  TRI_ASSERT(previous > 0);
}

bool IResearchFeature::failQueriesOnOutOfSync() const noexcept {
  TRI_IF_FAILURE("ArangoSearch::FailQueriesOnOutOfSync") {
    // here to test --arangosearch.fail-queries-on-out-of-sync
    return true;
  }
  return _failQueriesOnOutOfSync;
}

void IResearchFeature::registerRecoveryHelper() {
  if (!_skipRecoveryItems.empty()) {
    LOG_TOPIC("e36f2", WARN, arangodb::iresearch::TOPIC)
        << "arangosearch recovery explicitly disabled via the '"
        << SKIP_RECOVERY << "' startup option for the following links/indexes: "
        << _skipRecoveryItems
        << ". all affected links/indexes that are touched during "
           "recovery will be marked as out of sync and should be recreated "
           "manually when the recovery is finished.";
  }

  _recoveryHelper = std::make_shared<IResearchRocksDBRecoveryHelper>(
      server(), _skipRecoveryItems);
  auto res = RocksDBEngine::registerRecoveryHelper(_recoveryHelper);
  if (res.fail()) {
    THROW_ARANGO_EXCEPTION_MESSAGE(
        res.errorNumber(),
        absl::StrCat("failed to register RocksDB recovery helper: ",
                     res.errorMessage()));
  }
}

#ifdef USE_ENTERPRISE
#ifdef ARANGODB_USE_GOOGLE_TESTS
int64_t IResearchFeature::columnsCacheUsage() const noexcept {
  return _columnsCacheMemoryUsed.load();
}
#endif
bool IResearchFeature::trackColumnsCacheUsage(int64_t diff) noexcept {
  bool done = false;
  int64_t current = _columnsCacheMemoryUsed.load(std::memory_order_relaxed);
  do {
    const auto newValue = current + diff;
    if (newValue <= static_cast<int64_t>(_columnsCacheLimit)) {
      TRI_ASSERT(newValue >= 0);
      done = _columnsCacheMemoryUsed.compare_exchange_weak(current, newValue);
    } else {
      return false;
    }
  } while (!done);
  return true;
}
#endif

template<typename Engine, typename std::enable_if_t<
                              std::is_base_of_v<StorageEngine, Engine>, int>>
IndexTypeFactory& IResearchFeature::factory() {
  TRI_ASSERT(_factories.find(std::type_index(typeid(Engine))) !=
             _factories.end());
  return *_factories.find(std::type_index(typeid(Engine)))->second;
}
template IndexTypeFactory& IResearchFeature::factory<ClusterEngine>();
template IndexTypeFactory& IResearchFeature::factory<RocksDBEngine>();

}  // namespace arangodb::iresearch

redpajama_set_name: RedPajamaGithub


text:
SNPs Array Karyotyping in Non-Hodgkin Lymphoma
Microarray-Based Comparative Genomic and Transcriptome Analysis of Borrelia burgdorferi
Analysis of Reverse Phase Protein Array Data: From Experimental Design towards Targeted Biomarker Discovery
Integrated Microfluidic Nucleic Acid Isolation, Isothermal Amplification, and Amplicon Quantification
Microarrays
10.3390/microarrays4040540
Januszyk, M.
Rennert, R. C.
Sorkin, M.
Maan, Z. N.
Wong, L. K.
Whittam, A. J.
Whitmore, A.
Duscher, D.
Gurtner, G. C.
Please note that this journal is no longer accepting submissions. All previous published papers will remain fully searchable on www.mdpi.com.
Evaluating the Effect of Cell Culture on Gene Expression in Primary Tissue Samples Using Microfluidic-Based Single Cell Transcriptional Analysis
Michael Januszyk
Robert C. Rennert
Zeshaan N. Maan
Lisa K. Wong
Alexander J. Whittam
Arnetha Whitmore
Dominik Duscher
Geoffrey C. Gurtner
Department of Surgery, Division of Plastic and Reconstructive Surgery, 257 Campus Drive West, Hagey Building GK-201, Stanford, CA 94305-5148, USA
Academic Editor: Zvi Loewy
Microarrays 2015, 4(4), 540-550; https://doi.org/10.3390/microarrays4040540
Received: 14 August 2015 / Revised: 9 October 2015 / Accepted: 16 October 2015 / Published: 4 November 2015
(This article belongs to the Special Issue Microfluidics Technology)
Significant transcriptional heterogeneity is an inherent property of complex tissues such as tumors and healing wounds. Traditional methods of high-throughput analysis rely on pooling gene expression data from hundreds of thousands of cells and reporting a population-wide average that is unable to capture differences within distinct cell subsets. Recent advances in microfluidic technology have permitted the development of large-scale single cell analytic methods that overcome this limitation. The increased granularity afforded by such approaches allows us to answer the critical question of whether expansion in cell culture significantly alters the transcriptional characteristics of cells isolated from primary tissue. Here we examine an established population of human adipose-derived stem cells (ASCs) using a novel, microfluidic-based method for high-throughput transcriptional interrogation, coupled with advanced bioinformatic analysis, to evaluate the dynamics of single cell gene expression among primary, passage 0, and passage 1 stem cells. We find significant differences in the transcriptional profiles of cells from each group, as well as a considerable shift in subpopulation dynamics as those subgroups better able to adhere and proliferate under these culture conditions gradually emerge as dominant. Taken together, these findings reinforce the importance of using primary or very early passage cells in future studies. View Full-Text
Keywords: microfluidics; singe-cell; transcriptional analysis; gene expression; bioinformatics; subpopulations; cell culture microfluidics; singe-cell; transcriptional analysis; gene expression; bioinformatics; subpopulations; cell culture
Graphical abstract
Supplementary (PDF, 1476 KiB)
Januszyk, M.; Rennert, R.C.; Sorkin, M.; Maan, Z.N.; Wong, L.K.; Whittam, A.J.; Whitmore, A.; Duscher, D.; Gurtner, G.C. Evaluating the Effect of Cell Culture on Gene Expression in Primary Tissue Samples Using Microfluidic-Based Single Cell Transcriptional Analysis. Microarrays 2015, 4, 540-550. https://doi.org/10.3390/microarrays4040540
Januszyk M, Rennert RC, Sorkin M, Maan ZN, Wong LK, Whittam AJ, Whitmore A, Duscher D, Gurtner GC. Evaluating the Effect of Cell Culture on Gene Expression in Primary Tissue Samples Using Microfluidic-Based Single Cell Transcriptional Analysis. Microarrays. 2015; 4(4):540-550. https://doi.org/10.3390/microarrays4040540
Januszyk, Michael, Robert C. Rennert, Michael Sorkin, Zeshaan N. Maan, Lisa K. Wong, Alexander J. Whittam, Arnetha Whitmore, Dominik Duscher, and Geoffrey C. Gurtner. 2015. "Evaluating the Effect of Cell Culture on Gene Expression in Primary Tissue Samples Using Microfluidic-Based Single Cell Transcriptional Analysis" Microarrays 4, no. 4: 540-550. https://doi.org/10.3390/microarrays4040540
Microarrays, EISSN 2076-3905, Published by MDPI Disclaimer
The statements, opinions and data contained in the journal Microarrays are solely those of the individual authors and contributors and not of the publisher and the editor(s). MDPI stays neutral with regard to jurisdictional claims in published maps and institutional affiliations.


MUST SEE! 2 bed 2 bath condo with updated bathrooms, a sunken living room with tall ceilings and a wood burning fireplace, laundry, patio and views of yard space from every window! Great, clean, community with pool, tennis court, and lots of parking. Walking distance to Whole Foods and more!
This data last updated on 4/23/19 12:29PM. Some properties which appear for sale on this web site may subsequently have sold or may no longer be available.


text:
Thomas F. Walsh, O.S.A.
1922 – 1986 (March 16)
Thomas F. Walsh, son of Thomas Walsh and Elizabeth Gilgun, was born on August 26, 1922 in Woburn, Massachusetts, and entered the Augustinian Novitiate in 1943, after two years at Augustinian Academy, Staten Island, New York. He was simply professed on September 10, 1944 and ordained to the Priesthood by Bishop McNamara in Washington, D.C. on June 5, 1951.
Father Walsh's first assignment, a very brief one, was in Cuba. In September of 1952 he began his priestly ministry in California at Our Mother of Good Counsel Church in Los Angeles. He moved to Saint Thomas Aquinas Church, Ojai in 1964 and remained there until 1970. After helping in formation work in San Francisco at Cole Street for a year, he moved to Modesto, CA and taught at Central Catholic High School from 1971 to 1974. He then returned to Ojai until 1979. At that time he returned to Our Mother of Good Counsel where he remained in "limited-service" until his death.
Following his Funeral Mass at Our Mother of Good Counsel Parish on March 19, 1986, Father Walsh was buried at Calvary Cemetery, Woburn, Massachusetts.
Newer Post Thomas F. Walsh, O.S.A.
Older Post John A.M. Walsh, O.S.A.


text:
chinese womens 1500 records
Thread: chinese womens 1500 records
Re: chinese womens 1500 records
Back on my 3-month hiatus!
It's obvious that NO ONE knows why these marks are so anomalous, but they are. Eliminating PEDs is as foolish as elimination of 'short-track' or falsified times as explanations. Because no one can now measure the tracks or time the videos, we're stuck with just a big :?: hovering over the marks. Very sad, but as gh says, it's T&FN's prerogative to accept or deny them. I agree with this and the FloJo stance.
I've been seeking for the complete results of Shanghai 1997. I even created a Wikipedia page for it, and the National Games in 1997 are even more stunning than the 1993 edition.
Here are the the results of the 1500m, compiled by myself
http://en.wikipedia.org/wiki/Athletics_ ... nal_Games_–_Women%27s_1500m
Jiang Bo was 20, broke into the limelight at 18 by winning the 5000m at the Chinese City Games the same year, ahead Wang Junxia.
Lang Yinglai was 16 when she joined Ma Junren's training group in 1995. She only competed in 1997 at the Chinese junior championships, clocking a 4:16ish. Then came the NG, with her 3:51 on 1500. She was 18 then.
Zhang Ling was 16 and her 3:54.52 still stands as the World youth best today.
And the performances were outstanding in every event at this competition.
-20 year-old Li Xuemei won the 100m and the 200m in 10.79 and 22.01, with her teammate Liu Xiaomei finishing twice second in 10.89 and 22.36 ! They later won the gold medal on the 4 x 100m, representing the Sichuan province. They clocked 42.23, and it was even not the national team.
-17 year-old Li Jing crossed the line in 50.01 on 400m. She had competed at the Goteborg WC in 1995, at 15. She never had a distinguished career after Shanghai 1997.
-On 5000m, Jiang Bo, Dong Yangmei and Liu Shixiang smashed Ribeiro's record. Bo's record was however beaten by Abeylegesse in 2004
-On 10000m, 6 women under 31:00. Wang actually did not compete at those Games, as she retired at the end of 1996.
Other dubious marks in the jumps and throws were set, and Shen Shengfei, a 16 year-old Zhejiang native, finished second of the heptathlon (senior, you have understood) with a 6185 points score.
As if those Chinese athletes of the 90's only trained for these National Games... That's simply weird.
Originally Posted by Cranberry1
Lang Yinglai was 16 when she joined Ma Junren's training group in 1995.
I have seen some really unbelievable things accomplished by athletes who fell under the spell of a Svengalian coach. The human mind is capable of creating some pretty amazing physical manifestations when it BELIEVES (a corollary of the placebo effect). There's no doubt that Ma's Army was under his spell. Is it POSSIBLE they really did all these things clean? Maybe . . . but Occam's Razor compels us to look at simpler explanations - PEDs, short track, falsified times, etc. I am naturally a skeptical sort, so I choose to believe the latter explanations.
Dutra5
One snippet of the 1500m available on yt shows the 300m mark being passed in right around 42 secs if we believe the time on the screen.
mikli
Worth spending the 15 minutes to read: http://www.rdasia.com/china_cleans_up_its_game
Originally Posted by Marlow
It's obvious that NO ONE knows why these marks are so anomalous, but they are.
Someone certainly knows.
Originally Posted by mikli
Indeed, which is why I am now further convinced in the first of my last three suppositions above. It's the most obvious, logical, rational explanation, given the circumstances and verifiability of other factors.
I think I've found something interesting. There were no pictures from the Shanghai National Games, and I've just randomly found some from the 5.000 metres final, including Dong Yanmei, the mysterious Liu Shixiang and the former world record holder Bo Jiang.
Right here:
http://www.reocities.com/Colosseum/7273/ma-97.html
uakari
can you clarify one thing though, are you saying some of these athletes never competed internationally? i mean, both wang junxia and qu yunxia did, so it's not like they were unicorns or other fabled creatures... i believe the sprinter li xuemei did too.
Frans Rutten
Originally Posted by gh
there's not necessarily anything wrong w/ the athletes, but there's most certainly something wrong with the marks. There's a massive difference between the two.
??!! I've never heard this line of reasoning before. Are you implying that the marks were falsified? There was no video to re-time the races? Or the track really was short?
The Chinese women's middle and long distance performances during the 1993 Stuttgart worlds were indication enough of things to come. Those performances, however, were (sur)real.
It took still 4 more years to hallucinate the world.