问:
How do you read data from firestore?
I'm trying to learn how to use firestore.

The google documentation says to try this format:

```<code>db.collection("users").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });
});
</code>```

So, I used that to do this (changing the db to fsDB and "users" to "newsletters"

```<code>fsDB.collection("newsletters").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });
});
</code>```

When I try this, I get an error that says querySnapshot is not defined. Screen shot of error message is attached.

I've seen this post and tried its suggestion as follows:

```<code>fsDB.collection("newsletters").query.get().then(function(querySnapshot) {

                            if (querySnapshot.empty) {
                                console.log('no documents found');
                            } else {
                                    querySnapshot.docs.map(function (documentSnapshot) {
                                        console.log(documentSnapshot.data().name);
                                    });
                            }

                        });
</code>```

This attempt generates a parsing error with the if statement, but I can't find a way to solve that either.

This must have a simple solution, but I can't figure out how to get a record from the database.

NEXT ATTEMPT

I tried moving the code above the return statement and putting in inside a variable as follows shown in the attached screen shot, but it still produces errors as shown. These errors are the same regardless of whether i keep or lose the brackets around querySnapshot.

ADD STATE

```<code>class Fndate extends React.Component {
    state = {
        options: [],
        anzic: [],
        country: [],
        region: [],

    }

    selectCountry (val) {
        this.setState({ country: val });
      }

      selectRegion (val) {
        this.setState({ region: val });
      }

    async componentDidMount() {
        // const fsDB = firebase.firestore(); // Don't worry about this line if it comes from your config.
        let options = [];
        await fsDB.collection("abs_for_codes").get().then(function (querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, ' => ', doc.data());
            options.push({
                value: doc.data().title.replace(/( )/g, ''),
                label: doc.data().title + ' - ABS ' + doc.id
            });
            });
        });

        let anzic = [];
        await fsDB.collection("anzic_codes").get().then(function (querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, ' => ', doc.data());
            anzic.push({
                value: doc.data().Title.replace(/( )/g, ''),
                label: doc.data().Title + ' - ANZIC ' + doc.id
            });
            });
        });

            await fsDB
            .collection("newsletter")
            .get().then((querySnapshot) => {
                querySnapshot.forEach((doc) => {
                console.log(`${doc.id} => ${doc.data().email}`);
                }
            );
            });

        this.setState({
            options,
            anzic
        });
    }
</code>```

5]5

答:
I believe you're using React, and I just realized that you're calling the method in question in the render method.

try doing it in componentDidMount. A reference can be found here

so your code would be like this:

```<code>class YourClass extends React.Component {
   componentDidMount(){
      fsDB.collection("newsletters").get().then((querySnapshot) => {
         querySnapshot.forEach((doc) => {
            console.log(`${doc.id} => ${doc.data()}`);
         });
      });
   }
   render(){
      return (....your existing jsx....)
   }
}
</code>```

Note that I don't know your class name or how you define your component. But I'm just saying that you need to move your code in the componentDidMount.

We couldn't see your entire file. But I'm sure that it's a syntax error (especially with JSX)

Title: How do you read data from firestore?

Body:
I'm trying to learn how to use firestore.

The google documentation says to try this format:

db.collection("users").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });
});

So, I used that to do this (changing the db to fsDB and "users" to "newsletters"

fsDB.collection("newsletters").get().then((querySnapshot) => {
    querySnapshot.forEach((doc) => {
        console.log(`${doc.id} => ${doc.data()}`);
    });
});

When I try this, I get an error that says querySnapshot is not defined. Screen shot of error message is attached.

I've seen this post and tried its suggestion as follows:

fsDB.collection("newsletters").query.get().then(function(querySnapshot) {

                            if (querySnapshot.empty) {
                                console.log('no documents found');
                            } else {
                                    querySnapshot.docs.map(function (documentSnapshot) {
                                        console.log(documentSnapshot.data().name);
                                    });
                            }

                        });

This attempt generates a parsing error with the if statement, but I can't find a way to solve that either.

This must have a simple solution, but I can't figure out how to get a record from the database.

NEXT ATTEMPT

I tried moving the code above the return statement and putting in inside a variable as follows shown in the attached screen shot, but it still produces errors as shown. These errors are the same regardless of whether i keep or lose the brackets around querySnapshot.

ADD STATE

class Fndate extends React.Component {
    state = {
        options: [],
        anzic: [],
        country: [],
        region: [],

    }

    selectCountry (val) {
        this.setState({ country: val });
      }

      selectRegion (val) {
        this.setState({ region: val });
      }

    async componentDidMount() {
        // const fsDB = firebase.firestore(); // Don't worry about this line if it comes from your config.
        let options = [];
        await fsDB.collection("abs_for_codes").get().then(function (querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, ' => ', doc.data());
            options.push({
                value: doc.data().title.replace(/( )/g, ''),
                label: doc.data().title + ' - ABS ' + doc.id
            });
            });
        });

        let anzic = [];
        await fsDB.collection("anzic_codes").get().then(function (querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, ' => ', doc.data());
            anzic.push({
                value: doc.data().Title.replace(/( )/g, ''),
                label: doc.data().Title + ' - ANZIC ' + doc.id
            });
            });
        });

            await fsDB
            .collection("newsletter")
            .get().then((querySnapshot) => {
                querySnapshot.forEach((doc) => {
                console.log(`${doc.id} => ${doc.data().email}`);
                }
            );
            });

        this.setState({
            options,
            anzic
        });
    }

5]5

Body:
I believe you're using React, and I just realized that you're calling the method in question in the render method.

try doing it in componentDidMount. A reference can be found here

so your code would be like this:

class YourClass extends React.Component {
   componentDidMount(){
      fsDB.collection("newsletters").get().then((querySnapshot) => {
         querySnapshot.forEach((doc) => {
            console.log(`${doc.id} => ${doc.data()}`);
         });
      });
   }
   render(){
      return (....your existing jsx....)
   }
}

Note that I don't know your class name or how you define your component. But I'm just saying that you need to move your code in the componentDidMount.

We couldn't see your entire file. But I'm sure that it's a syntax error (especially with JSX)


来源: stackexchange

问:
Display the saved values of in separate dropdown list
I have a dropdownlist in edit view that has a value from the database. What I want to do is to display the saved value in separate dropdown list. For example, I have saved two different data in database with same foreign key to determine that these two records are treated as one. (See below sample image)

https://imgur.com/ex57YTO

I am only using single-selection dropdown list and I am only looping the count of records to determine how many dropdown list to display in the edit page. So if I have "No harm event" and "Complaints" events, this must be displayed in separate dropdown list because what I did now is they are both displaying in one dropdown list so the result is it looks like the record is duplicated (see image below) but actually these two records are in each of the dropdown list.

https://imgur.com/YlVZHWx

https://imgur.com/FXYO4Tn

VIEW

```<code>//for loop to count records that will determine how many dropdown list to be displayed
@for (var i = 0; i < Model.SavedEventsToList.Where(a => a.incidentReportId == Model.IRId).Count(); i++)
 {
    <tr>
       <td style="border-bottom:none !important;border-top:none !important;">
          <div class="input-group">
              <select class="form-control pseEventDDLInEdit" id="pseEventListInEdit" name="pseAddedEvent">
                @{
                   foreach (var item in Model.SavedEventsToList)
                   {
                      if (item.selected == "yes")
                      {
                         if (item.incidentReportId == Model.IRId)   //this is the foreign key that determine these two records are as one
                         {
                            <option value=@item.pseEventsId selected>@item.pseEventsName</option>
                         }
                       }
                       else
                       {
                         <option value=@item.pseEventsId>@item.pseEventsName</option>
                       }
                    }
                  }
                </select>
            </div>
         </td>
     </tr>
  }
</code>```

CONTROLLER

```<code>public ActionResult Edit(Guid? id)
{
  IMRBusinessLogic imrLogic = new IMRBusinessLogic();
  var imrRepo = new IMRRepository();
  IMRDTO imr = imrRepo.GetIRDetailsForEdit(id);
  imr.SavedEventsToList = imrLogic.SavedEvents(id);

   return View(imr);
}

public List<PSESavedEventsDTO> SavedEvents(Guid? incidentReportId)
{
  using (IREntities db = new IREntities())
  {
     var events = (from a in db.SavedPatientSafetyEvents(incidentReportId)
                select new PSESavedEventsDTO
                {
                  pseSavedEventId = a.pse_saved_event_category_and_subcategory_id,
                  pseEventsId = a.pse_events_id,
                  pseEventsName = a.pse_events_name,
                  seqNum = a.seq_num,
                  incidentReportId = a.incident_report_id,
                  savedRowIndex = a.saved_row_index,
                  selected = a.selected
                }).ToList();
       return events;
      }
}
</code>```

I need to separate them so the user can still have an option to edit each of these two records.

This is the expected output I need: https://imgur.com/uwVjvkz

Can someone help me with this.
Thank you in advance.

答:
I already found the solution in this. I just use foreach instead of for loop, and I get the desired output I need.</p>

```<code>@foreach (var index in Model.SavedEventsToList.Where(a => a.savedRowIndex != 0))
{
<tr>
  <td style="border-bottom:none !important;border-top:none !important;">
     <div class="input-group">
        <select class="form-control pseEventDDLInEdit" id="pseEventListInEdit" name="pseAddedEvent">
        @{
           foreach (var item in Model.SavedEventsToList)
           {
              if (item.selected == "yes")
              {
                 if (item.incidentReportId == Model.IRId && item.savedRowIndex == index.savedRowIndex)
                 {
                    <option value=@item.pseEventsId selected>@item.pseEventsName</option>
                 }
              }
              else
              {
                 <option value=@item.pseEventsId>@item.pseEventsName</option>
              }
           }
         }
        </select>
        <span title="Patient Safety Events Description" class="input-group-addon" data-toggle="popover" data-container="body" data-placement="right" data-trigger="hover" data-html="true" href="#" id="login"><i class="fa fa-info-circle"></i></span>
     </div>
  </td>
</tr>
}
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I have a dropdownlist in edit view that has a value from the database. What I want to do is to display the saved value in separate dropdown list. For example, I have saved two different data in database with same foreign key to determine that these two records are treated as one. (See below sample image)

https://imgur.com/ex57YTO

I am only using single-selection dropdown list and I am only looping the count of records to determine how many dropdown list to display in the edit page. So if I have "No harm event" and "Complaints" events, this must be displayed in separate dropdown list because what I did now is they are both displaying in one dropdown list so the result is it looks like the record is duplicated (see image below) but actually these two records are in each of the dropdown list.

https://imgur.com/YlVZHWx

https://imgur.com/FXYO4Tn

VIEW

//for loop to count records that will determine how many dropdown list to be displayed
@for (var i = 0; i < Model.SavedEventsToList.Where(a => a.incidentReportId == Model.IRId).Count(); i++)
 {

              <select class="form-control pseEventDDLInEdit" id="pseEventListInEdit" name="pseAddedEvent">
                @{
                   foreach (var item in Model.SavedEventsToList)
                   {
                      if (item.selected == "yes")
                      {
                         if (item.incidentReportId == Model.IRId)   //this is the foreign key that determine these two records are as one
                         {
                            <option value=@item.pseEventsId selected>@item.pseEventsName</option>
                         }
                       }
                       else
                       {
                         <option value=@item.pseEventsId>@item.pseEventsName</option>
                       }
                    }
                  }
                </select>

  }

CONTROLLER

public ActionResult Edit(Guid? id)
{
  IMRBusinessLogic imrLogic = new IMRBusinessLogic();
  var imrRepo = new IMRRepository();
  IMRDTO imr = imrRepo.GetIRDetailsForEdit(id);
  imr.SavedEventsToList = imrLogic.SavedEvents(id);

   return View(imr);
}

public List<PSESavedEventsDTO> SavedEvents(Guid? incidentReportId)
{
  using (IREntities db = new IREntities())
  {
     var events = (from a in db.SavedPatientSafetyEvents(incidentReportId)
                select new PSESavedEventsDTO
                {
                  pseSavedEventId = a.pse_saved_event_category_and_subcategory_id,
                  pseEventsId = a.pse_events_id,
                  pseEventsName = a.pse_events_name,
                  seqNum = a.seq_num,
                  incidentReportId = a.incident_report_id,
                  savedRowIndex = a.saved_row_index,
                  selected = a.selected
                }).ToList();
       return events;
      }
}

I need to separate them so the user can still have an option to edit each of these two records.

This is the expected output I need: https://imgur.com/uwVjvkz

Can someone help me with this.
Thank you in advance.

Body:
I already found the solution in this. I just use foreach instead of for loop, and I get the desired output I need.

@foreach (var index in Model.SavedEventsToList.Where(a => a.savedRowIndex != 0))
{
<tr>
  <td style="border-bottom:none !important;border-top:none !important;">
     <div class="input-group">
        <select class="form-control pseEventDDLInEdit" id="pseEventListInEdit" name="pseAddedEvent">
        @{
           foreach (var item in Model.SavedEventsToList)
           {
              if (item.selected == "yes")
              {
                 if (item.incidentReportId == Model.IRId && item.savedRowIndex == index.savedRowIndex)
                 {
                    <option value=@item.pseEventsId selected>@item.pseEventsName</option>
                 }
              }
              else
              {
                 <option value=@item.pseEventsId>@item.pseEventsName</option>
              }
           }
         }
        </select>
        <span title="Patient Safety Events Description" class="input-group-addon" data-toggle="popover" data-container="body" data-placement="right" data-trigger="hover" data-html="true" href="#" id="login"><i class="fa fa-info-circle"></i></span>
     </div>
  </td>
</tr>
}


问:
Can't set two elements at the same horizontal level
https://jsfiddle.net/xtm5oqjh/
When you open my modal ("+" sign on the navbar) you see that the button "save changes" and the "priority" dropdown do not have the same height and are not at the same level horizontally.

After this:

```<code>.input-group {
    height: 31px;
    padding-bottom: 0;
    margin-bottom: 0;
}
</code>```

It does get she same height as the Save Changes button but it's still not at the same level horizontally as the margin is still there. I'm puzzled as to why this happen. Any clues?

答:
This element:

```<code><div class="input-group mb-3 w-50">
  ...
</div>
</code>```

The class mb-3 is adding margin-bottom to that group of elements, pushing it up higher than the "Save Changes" button you are trying to line it up with. Remove that class and you should be ok.

Body:
https://jsfiddle.net/xtm5oqjh/
When you open my modal ("+" sign on the navbar) you see that the button "save changes" and the "priority" dropdown do not have the same height and are not at the same level horizontally.

After this:

.input-group {
    height: 31px;
    padding-bottom: 0;
    margin-bottom: 0;
}

It does get she same height as the Save Changes button but it's still not at the same level horizontally as the margin is still there. I'm puzzled as to why this happen. Any clues?

Body:
This element:

<div class="input-group mb-3 w-50">
  ...
</div>

The class mb-3 is adding margin-bottom to that group of elements, pushing it up higher than the "Save Changes" button you are trying to line it up with. Remove that class and you should be ok.


问:
Changing the value for several keys in a map in Haskell
I need to change the value in a Map for several keys to a given value.

I have this code:

```<code>change :: Map.Map Integer Char -> [Integer] -> Char -> Map.Map Integer Char
change m ns c = foldr (\k mp -> Map.insert k c m) m ns
</code>```

Only the first key in the list is changed. I can think other ways to do it but I'm trying to understand folds better.

Sorry, I've corrected the code.

Here's a ghci session:

```<code>*Maps> m
fromList [(3,'?'),(5,'?'),(7,'?'),(9,'?'),(11,'?'),(13,'?'),(15,'?'),(17,'?'),(19,'?'),(21,'?'),(23,'?'),(25,'?'),(27,'?'),(29,'?')]
it :: (Ord k, Num k, Enum k) => Map.Map k Char
(0.02 secs, 149,192 bytes)
*Maps> ns
[9,15,21,27]
it :: Num a => [a]
(0.00 secs, 59,000 bytes)
*Maps> change m ns 'c'
fromList [(3,'?'),(5,'?'),(7,'?'),(9,'c'),(11,'?'),(13,'?'),(15,'?'),(17,'?'),(19,'?'),(21,'?'),(23,'?'),(25,'?'),(27,'?'),(29,'?')]
it :: Map.Map Integer Char
(0.02 secs, 149,752 bytes)
</code>```

Only the value for 9 is changed.

答:
Your code does not compile for me; you sure you pasted it correctly? If I switch the parameters for the lambda:

change m ns c = foldr (\k mp -> Map.insert k c mp) m ns
```

<p>or change the foldr to a foldl:</p>

<pre class="lang-hs prettyprint-override"><code>change m ns c = foldl (\mp k -> Map.insert k c mp) m ns
</code>```

the code compiles (and inserts all the keys) both ways.

Body:
I need to change the value in a Map for several keys to a given value.

I have this code:

change :: Map.Map Integer Char -> [Integer] -> Char -> Map.Map Integer Char
change m ns c = foldr (\k mp -> Map.insert k c m) m ns

Only the first key in the list is changed. I can think other ways to do it but I'm trying to understand folds better.

Sorry, I've corrected the code.

Here's a ghci session:

*Maps> m
fromList [(3,'?'),(5,'?'),(7,'?'),(9,'?'),(11,'?'),(13,'?'),(15,'?'),(17,'?'),(19,'?'),(21,'?'),(23,'?'),(25,'?'),(27,'?'),(29,'?')]
it :: (Ord k, Num k, Enum k) => Map.Map k Char
(0.02 secs, 149,192 bytes)
*Maps> ns
[9,15,21,27]
it :: Num a => [a]
(0.00 secs, 59,000 bytes)
*Maps> change m ns 'c'
fromList [(3,'?'),(5,'?'),(7,'?'),(9,'c'),(11,'?'),(13,'?'),(15,'?'),(17,'?'),(19,'?'),(21,'?'),(23,'?'),(25,'?'),(27,'?'),(29,'?')]
it :: Map.Map Integer Char
(0.02 secs, 149,752 bytes)

Only the value for 9 is changed.

Body:
Your code does not compile for me; you sure you pasted it correctly? If I switch the parameters for the lambda:

change m ns c = foldr (\k mp -> Map.insert k c mp) m ns

or change the foldr to a foldl:

change m ns c = foldl (\mp k -> Map.insert k c mp) m ns

the code compiles (and inserts all the keys) both ways.


问:
How to use Jquery to update textarea value in react app
I'm building a Chrome extension that layers over a 3rd party react website. I am attempting to update the value of a textarea within that app using the following code:

```<code>$('textarea').val("Text to go in textarea.");
</code>```

The code successfully updates the textarea however once the user clicks on the textarea, the DOM seems to regenerate and the value becomes blank.

What is the best way to update the value within the textarea so that it remains even once the user clicks and DOM regenerates? I am not a react expert however my guess is that the textarea is tied to the state. Is there any way to update that from my own jquery within my chrome extension?

Just to be clear, the textarea belongs to a 3rd party website/react app that I have no control over. I'm trying to manipulate it from my own google chrome extension. I thought the easiest way would be to somehow simulate actual typing in order to make the react app think the user typed my input however I searched around and could not find a way to do that.

答:
Try to use set value of DOM Html element:

```<code>document.getElementById("textarea").value = "Johnny Bravo";
</code>```

Body:
I'm building a Chrome extension that layers over a 3rd party react website. I am attempting to update the value of a textarea within that app using the following code:

$('textarea').val("Text to go in textarea.");

The code successfully updates the textarea however once the user clicks on the textarea, the DOM seems to regenerate and the value becomes blank.

What is the best way to update the value within the textarea so that it remains even once the user clicks and DOM regenerates? I am not a react expert however my guess is that the textarea is tied to the state. Is there any way to update that from my own jquery within my chrome extension?

Just to be clear, the textarea belongs to a 3rd party website/react app that I have no control over. I'm trying to manipulate it from my own google chrome extension. I thought the easiest way would be to somehow simulate actual typing in order to make the react app think the user typed my input however I searched around and could not find a way to do that.

Body:
Try to use set value of DOM Html element:

document.getElementById("textarea").value = "Johnny Bravo";


问:
Vary line color, alpha and width when drawing on canvas in JavaScript
I am testing this in Chrome. I tried a line thickness solution from StackOverflow here that did not work.

I have a object called redLine with a position and an array of offset positions. The only thing that is affected is the alpha value. Color and line thickness stays once it is set.

```<code>function renderRedLine(){

    context.beginPath();

    for(j=0; j<redLine.posArr.length; ++j){

        var startPoint

        if(j===0){
            startPoint = redLine.pos
        }else{
            startPoint = redLine.posArr[j-1]
        }

        var endPoint = redLine.posArr[j]

        let alpha = 1.0 - (j/(redLine.posArr.length-1))

        let g = 150 - (10*j)

        context.strokeStyle = 'rgba(255, ' + g + ', ' + 0 + ', ' + alpha + ')'
        context.lineWidth = j+1

        if(j===0){
            context.moveTo(startPoint.x, startPoint.y);
        }else{
            context.lineTo(endPoint.x, endPoint.y);
        }

        context.stroke();

    }

    context.closePath();

}
</code>```

答:
You need to call ctx.beginPath() after each ctx.stroke() otherwise, all the next lineTo() will be added to the one and only sub-path and when you'll call stroke() again with a thicker lineWidth, the whole sub-path will get redrawn, covering the thinner lines that were drawn before.

const context = canvas.getContext('2d');
const redLine = {
  posArr: Array.from({
    length: 12
  }).map(() => ({
    x: Math.random() * canvas.width,
    y: Math.random() * canvas.height
  })),
  pos: {
    x: canvas.width / 2,
    y: canvas.height / 2
  }
};
console.log(redLine);
renderRedLine();

function renderRedLine() {

  for (j = 0; j < redLine.posArr.length; ++j) {
    // at every iteration we start a new sub-path
    context.beginPath();

    let startPoint;
    if (j === 0) {
      startPoint = redLine.pos
    } else {
      startPoint = redLine.posArr[j - 1]
    }

    const endPoint = redLine.posArr[j]
    const alpha = 1.0 - (j / (redLine.posArr.length - 1))
    const g = 150 - (10 * j)

    context.strokeStyle = 'rgba(255, ' + g + ', ' + 0 + ', ' + alpha + ')'
    context.lineWidth = j + 1
    // since we start a new sub-path at every iteration
    // we need to moveTo(start) unconditionnaly
    context.moveTo(startPoint.x, startPoint.y);
    context.lineTo(endPoint.x, endPoint.y);

    context.stroke();
  }

  //context.closePath is only just a lineTo(path.lastMovedX, path.lastMovedY)
  // i.e not something you want here

}```
<pre class="snippet-code-html lang-html prettyprint-override"><code><canvas id="canvas"></canvas></code>```

Body:
I am testing this in Chrome. I tried a line thickness solution from StackOverflow here that did not work.

I have a object called redLine with a position and an array of offset positions. The only thing that is affected is the alpha value. Color and line thickness stays once it is set.

function renderRedLine(){

    context.beginPath();

    for(j=0; j<redLine.posArr.length; ++j){

        var startPoint

        if(j===0){
            startPoint = redLine.pos
        }else{
            startPoint = redLine.posArr[j-1]
        }

        var endPoint = redLine.posArr[j]

        let alpha = 1.0 - (j/(redLine.posArr.length-1))

        let g = 150 - (10*j)

        context.strokeStyle = 'rgba(255, ' + g + ', ' + 0 + ', ' + alpha + ')'
        context.lineWidth = j+1

        if(j===0){
            context.moveTo(startPoint.x, startPoint.y);
        }else{
            context.lineTo(endPoint.x, endPoint.y);
        }

        context.stroke();

    }

    context.closePath();

}

Body:
You need to call ctx.beginPath() after each ctx.stroke() otherwise, all the next lineTo() will be added to the one and only sub-path and when you'll call stroke() again with a thicker lineWidth, the whole sub-path will get redrawn, covering the thinner lines that were drawn before.

const context = canvas.getContext('2d');
const redLine = {
  posArr: Array.from({
    length: 12
  }).map(() => ({
    x: Math.random() * canvas.width,
    y: Math.random() * canvas.height
  })),
  pos: {
    x: canvas.width / 2,
    y: canvas.height / 2
  }
};
console.log(redLine);
renderRedLine();

function renderRedLine() {

  for (j = 0; j < redLine.posArr.length; ++j) {
    // at every iteration we start a new sub-path
    context.beginPath();

    let startPoint;
    if (j === 0) {
      startPoint = redLine.pos
    } else {
      startPoint = redLine.posArr[j - 1]
    }

    const endPoint = redLine.posArr[j]
    const alpha = 1.0 - (j / (redLine.posArr.length - 1))
    const g = 150 - (10 * j)

    context.strokeStyle = 'rgba(255, ' + g + ', ' + 0 + ', ' + alpha + ')'
    context.lineWidth = j + 1
    // since we start a new sub-path at every iteration
    // we need to moveTo(start) unconditionnaly
    context.moveTo(startPoint.x, startPoint.y);
    context.lineTo(endPoint.x, endPoint.y);

    context.stroke();
  }

  //context.closePath is only just a lineTo(path.lastMovedX, path.lastMovedY)
  // i.e not something you want here

}

<canvas id="canvas"></canvas>


问:
Problem when trying to wrap chains of width-constrained views
I'm trying to implement a very common portrait/landscape layout flexibility approach using newly-introduced ConstraintLayout Flow helper in chain wrapping mode.

I want to position two views automatically in line for landscape orientation and one under another for portrait, e.g. wrap to fit. I can achieve this already with FlexboxLayout but I prefer a flat structure and performance of ConstraintLayout.

```<code><androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#B0B0B0">

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:flow_wrapMode="chain"
        app:constraint_referenced_ids="view1,view2"
        android:layout_height="0dp" />

    <View
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintDimensionRatio="1:1"
        android:background="#808080"
        tools:ignore="MissingConstraints">
    </View>

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintDimensionRatio="1:1"
        android:background="#E0E0E0"
        tools:ignore="MissingConstraints">
    </View>

</androidx.constraintlayout.widget.ConstraintLayout>
</code>```

I get this for landscape, and it's fine:

But I get this for portrait:

If I set fixed width 200dp (or wrap_content for other cases also ok), everything works as expected:

Since ConstraintLayout 2.0.0 is in beta and recent changelog reports about fixes in wrap support, I suppose that it is a bug.

But maybe I'm missing something? Thank you

答:
The default orientation of the Flow widget is horizontal. Therefore, it needs to know layout_width values of its referenced widgets.

It seems that Flow can't calculate these values based on the app:layout_constraintDimensionRatio (at least, not in the Tools preview.. I did not test how it behaves at runtime).

In your code, you can swap the layout_width and layout_height values to achieve your desired results.

```<code><androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:ignore="MissingConstraints">

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:constraint_referenced_ids="view_red, view_blue"
        app:flow_wrapMode="chain"/>

    <View
        android:id="@+id/view_red"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:background="#C62828"
        app:layout_constraintDimensionRatio="1:1"/>

    <View
        android:id="@+id/view_blue"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:background="#1565C0"
        app:layout_constraintDimensionRatio="1:1"/>

</androidx.constraintlayout.widget.ConstraintLayout>
</code>```

However, keep in mind that chaining/wrapping only occurs if the referenced widgets do not fit in the specified orientation (default: horizontal). In my code, I had to set layout_width to 300dp for chaining to happen in the Tools preview.

So, if you're running on a tablet, for example, using this method will not guarantee that your widgets will be positioned vertically because there is more horizontal space to accommodate the widgets.

Body:
I'm trying to implement a very common portrait/landscape layout flexibility approach using newly-introduced ConstraintLayout Flow helper in chain wrapping mode.

I want to position two views automatically in line for landscape orientation and one under another for portrait, e.g. wrap to fit. I can achieve this already with FlexboxLayout but I prefer a flat structure and performance of ConstraintLayout.

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#B0B0B0">

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="0dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:flow_wrapMode="chain"
        app:constraint_referenced_ids="view1,view2"
        android:layout_height="0dp" />

    <View
        android:id="@+id/view1"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintDimensionRatio="1:1"
        android:background="#808080"
        tools:ignore="MissingConstraints">
    </View>

    <View
        android:id="@+id/view2"
        android:layout_width="0dp"
        android:layout_height="200dp"
        app:layout_constraintDimensionRatio="1:1"
        android:background="#E0E0E0"
        tools:ignore="MissingConstraints">
    </View>

</androidx.constraintlayout.widget.ConstraintLayout>

I get this for landscape, and it's fine:

But I get this for portrait:

If I set fixed width 200dp (or wrap_content for other cases also ok), everything works as expected:

Since ConstraintLayout 2.0.0 is in beta and recent changelog reports about fixes in wrap support, I suppose that it is a bug.

But maybe I'm missing something? Thank you

Body:
The default orientation of the Flow widget is horizontal. Therefore, it needs to know layout_width values of its referenced widgets.

It seems that Flow can't calculate these values based on the app:layout_constraintDimensionRatio (at least, not in the Tools preview.. I did not test how it behaves at runtime).

In your code, you can swap the layout_width and layout_height values to achieve your desired results.

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:ignore="MissingConstraints">

    <androidx.constraintlayout.helper.widget.Flow
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:constraint_referenced_ids="view_red, view_blue"
        app:flow_wrapMode="chain"/>

    <View
        android:id="@+id/view_red"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:background="#C62828"
        app:layout_constraintDimensionRatio="1:1"/>

    <View
        android:id="@+id/view_blue"
        android:layout_width="300dp"
        android:layout_height="0dp"
        android:background="#1565C0"
        app:layout_constraintDimensionRatio="1:1"/>

</androidx.constraintlayout.widget.ConstraintLayout>

However, keep in mind that chaining/wrapping only occurs if the referenced widgets do not fit in the specified orientation (default: horizontal). In my code, I had to set layout_width to 300dp for chaining to happen in the Tools preview.

So, if you're running on a tablet, for example, using this method will not guarantee that your widgets will be positioned vertically because there is more horizontal space to accommodate the widgets.


问:
How to divide each element in a row by corresponding row value?
(I want to divide each element in a row by corresponding row value. Denominator should the value of "Ac" when row element is present.</p>

```<code>Ac    V1  V2  V3   V4  V5  V6  V7
6.6  NA  NA  NA   NA   0  5.6  5.2
8.4  NA  0   82.5 31   0  0    1.1

Output:

V1 V2    V3        V4       V5                            V6               V7
NA 0/8.4 82.5/8.4 31/8.4  (0*6.6+0*6.6)/(6.6+8.4) (5.6*6.6+0*8.4)/(6.6+8.4) (5.2*6.6+1.1*8.4)/(6.6+8.4)
</code>```

答:
We could divide every row with the first value in the row and take column wise sum

```<code>colSums(df[, -1]/df[[1]], na.rm = TRUE)

#     V1      V2      V3      V4      V5      V6      V7
#0.00000 0.00000 9.82143 3.69048 0.00000 0.84848 0.91883
</code>```

If we want to keep the first element as NA

```<code>(NA^(colSums(is.na(df[, -1])) == nrow(df))) * colSums(df[,-1]/df[[1]], na.rm = TRUE)

#     V1      V2      V3      V4      V5      V6      V7
#     NA 0.00000 9.82143 3.69048 0.00000 0.84848 0.91883
</code>```

Body:
(I want to divide each element in a row by corresponding row value. Denominator should the value of "Ac" when row element is present.

Ac    V1  V2  V3   V4  V5  V6  V7
6.6  NA  NA  NA   NA   0  5.6  5.2
8.4  NA  0   82.5 31   0  0    1.1

Output:

V1 V2    V3        V4       V5                            V6               V7
NA 0/8.4 82.5/8.4 31/8.4  (0*6.6+0*6.6)/(6.6+8.4) (5.6*6.6+0*8.4)/(6.6+8.4) (5.2*6.6+1.1*8.4)/(6.6+8.4)

Body:
We could divide every row with the first value in the row and take column wise sum

colSums(df[, -1]/df[[1]], na.rm = TRUE)

#     V1      V2      V3      V4      V5      V6      V7
#0.00000 0.00000 9.82143 3.69048 0.00000 0.84848 0.91883

If we want to keep the first element as NA

(NA^(colSums(is.na(df[, -1])) == nrow(df))) * colSums(df[,-1]/df[[1]], na.rm = TRUE)

#     V1      V2      V3      V4      V5      V6      V7
#     NA 0.00000 9.82143 3.69048 0.00000 0.84848 0.91883


问:
How to add same values to different keys in dictionaries?
I have 2 JSON files. 1 file with the the student numbers and 1 file with the students.

I have a list of dictionaries with the name, e-mail, and student number of students.

What I want to do is if there are 60 students I want to give them a unique student number. That part is working in the elif statement. The part which I dont know how to implement is:

If there are 20 students, I want to give for example 2 students the same studentnumber(which sounds stupid but I need it). In this case the student is the key and studentnumber is the value.

What I have now:

```<code>
# student
[{"Student1":029182,"e-mail":"example@.com"},{"Student2":0591238,"e-mail":"example@.com"},{"Student3":9213189,"e-mail":"example@.com"}]

studentnumbers = [{"studentnumber":"029182","ID":0},{"studentnumber":"0591238","ID":1},{"studentnumber":"9213189","ID":2}]

students = [list(data.values())[0] for data in studentnumbers]

ID = 0
# students is a list of studentnumbers
if len(students) <= 20:
    # studentInfo is my dictionary with the key and values
    for data in studentnumbers:
        try:
            pass

        except IndexError:
            pass

elif len(students) <= 60:
    for data in studentnumbers:
        try:
            studentnumbers[ID] = students[ID]
            ID += 1
            break
        except IndexError:
            pass
    print("..")
else:
    print("...")

with open('Students.json','w') as instudent:
    json.dump(studentnumbers,instudent,indent=2)

</code>```

output what I have now:

```<code>[{"Student1":029182,"e-mail":"example@.com","studentnumber":029182},
{"Student2":0591238,"e-mail":"example@.com","studentnumber":9213189},
{"Student3":9213189,"e-mail":"example@.com","studentnumber":0591238},
{"Student4":9213189,"e-mail":"example@.com","studentnumber":0294832},
{"Student5":9213189,"e-mail":"example@.com","studentnumber":0591823},
{"Student6":9213189,"e-mail":"example@.com","studentnumber":0501852}]
</code>```

What I want:

```<code>[{"Student1":029182,"e-mail":"example@.com","studentnumber":029182},
{"Student2":0591238,"e-mail":"example@.com","studentnumber":029182},
{"Student3":9213189,"e-mail":"example@.com","studentnumber":029182},
{"Student4":9213189,"e-mail":"example@.com","studentnumber":9213189},
{"Student5":9213189,"e-mail":"example@.com","studentnumber":9213189},
{"Student6":9213189,"e-mail":"example@.com","studentnumber":9213189}]
</code>```

答:
It seems you want to conditionally update a list of dicts.

Given

```<code>import random

students = [
    {"Student1": "029182", "e-mail": "ex@mail.com"},
    {"Student2": "0591238", "e-mail": "ex@mail.com"},
    {"Student3": "9213189", "e-mail": "ex@mail.com"},
]
</code>```

Code

```<code>def get_unique_numbers(size=10):
    """Return an a list of unique random values."""
    return random.sample(range(10000, 99999), size)

def update(students):
    """Return a list of updated dicts."""
    n = len(students)

    # Conditionally, generate student numbers
    if n <= 20:
        student_numbers = [students[0]["Student1"]] * n
    elif 20 < n <= 60:
        student_numbers = get_unique_numbers(n)

    # Update dicts w/student numbers
    return [{**d, "student_num": n} for d, n in zip(students, student_numbers)]
</code>```

Demo

A small list of students (n <= 20) returns dicts with the same student number:

```<code>update(students)
# [{'Student1': '029182', 'e-mail': 'ex@mail.com', 'student_num': '029182'},
#  {'Student2': '0591238', 'e-mail': 'ex@mail.com', 'student_num': '029182'},
#  {'Student3': '9213189', 'e-mail': 'ex@mail.com', 'student_num': '029182'}]
</code>```

A larger list (n > 20) returns dicts with random student numbers*:

```<code>update(students * 7)
# {'Student1': '029182', 'e-mail': 'ex@mail.com', 'student_num': 28308},
# {'Student2': '0591238', 'e-mail': 'ex@mail.com', 'student_num': 21986},
# {'Student3': '9213189', 'e-mail': 'ex@mail.com', 'student_num': 36603},
# ...
# {'Student1': '029182', 'e-mail': 'ex@mail.com', 'student_num': 38362},
# {'Student2': '0591238', 'e-mail': 'ex@mail.com', 'student_num': 99305},
# {'Student3': '9213189', 'e-mail': 'ex@mail.com', 'student_num': 78360}
</code>```

*Note: implement the random number generator however you wish.  This one returns random integers from a sample population.

Body:
I have 2 JSON files. 1 file with the the student numbers and 1 file with the students.

I have a list of dictionaries with the name, e-mail, and student number of students.

What I want to do is if there are 60 students I want to give them a unique student number. That part is working in the elif statement. The part which I dont know how to implement is:

If there are 20 students, I want to give for example 2 students the same studentnumber(which sounds stupid but I need it). In this case the student is the key and studentnumber is the value.

What I have now:

# student
[{"Student1":029182,"e-mail":"example@.com"},{"Student2":0591238,"e-mail":"example@.com"},{"Student3":9213189,"e-mail":"example@.com"}]

studentnumbers = [{"studentnumber":"029182","ID":0},{"studentnumber":"0591238","ID":1},{"studentnumber":"9213189","ID":2}]

students = [list(data.values())[0] for data in studentnumbers]

ID = 0
# students is a list of studentnumbers
if len(students) <= 20:
    # studentInfo is my dictionary with the key and values
    for data in studentnumbers:
        try:
            pass

        except IndexError:
            pass

elif len(students) <= 60:
    for data in studentnumbers:
        try:
            studentnumbers[ID] = students[ID]
            ID += 1
            break
        except IndexError:
            pass
    print("..")
else:
    print("...")

with open('Students.json','w') as instudent:
    json.dump(studentnumbers,instudent,indent=2)

output what I have now:

[{"Student1":029182,"e-mail":"example@.com","studentnumber":029182},
{"Student2":0591238,"e-mail":"example@.com","studentnumber":9213189},
{"Student3":9213189,"e-mail":"example@.com","studentnumber":0591238},
{"Student4":9213189,"e-mail":"example@.com","studentnumber":0294832},
{"Student5":9213189,"e-mail":"example@.com","studentnumber":0591823},
{"Student6":9213189,"e-mail":"example@.com","studentnumber":0501852}]

What I want:

[{"Student1":029182,"e-mail":"example@.com","studentnumber":029182},
{"Student2":0591238,"e-mail":"example@.com","studentnumber":029182},
{"Student3":9213189,"e-mail":"example@.com","studentnumber":029182},
{"Student4":9213189,"e-mail":"example@.com","studentnumber":9213189},
{"Student5":9213189,"e-mail":"example@.com","studentnumber":9213189},
{"Student6":9213189,"e-mail":"example@.com","studentnumber":9213189}]

Body:
It seems you want to conditionally update a list of dicts.

Given

import random

students = [
    {"Student1": "029182", "e-mail": "ex@mail.com"},
    {"Student2": "0591238", "e-mail": "ex@mail.com"},
    {"Student3": "9213189", "e-mail": "ex@mail.com"},
]

Code

def get_unique_numbers(size=10):
    """Return an a list of unique random values."""
    return random.sample(range(10000, 99999), size)

def update(students):
    """Return a list of updated dicts."""
    n = len(students)

    # Conditionally, generate student numbers
    if n <= 20:
        student_numbers = [students[0]["Student1"]] * n
    elif 20 < n <= 60:
        student_numbers = get_unique_numbers(n)

    # Update dicts w/student numbers
    return [{**d, "student_num": n} for d, n in zip(students, student_numbers)]

Demo

A small list of students (n <= 20) returns dicts with the same student number:

update(students)
# [{'Student1': '029182', 'e-mail': 'ex@mail.com', 'student_num': '029182'},
#  {'Student2': '0591238', 'e-mail': 'ex@mail.com', 'student_num': '029182'},
#  {'Student3': '9213189', 'e-mail': 'ex@mail.com', 'student_num': '029182'}]

A larger list (n > 20) returns dicts with random student numbers*:

update(students * 7)
# {'Student1': '029182', 'e-mail': 'ex@mail.com', 'student_num': 28308},
# {'Student2': '0591238', 'e-mail': 'ex@mail.com', 'student_num': 21986},
# {'Student3': '9213189', 'e-mail': 'ex@mail.com', 'student_num': 36603},
# ...
# {'Student1': '029182', 'e-mail': 'ex@mail.com', 'student_num': 38362},
# {'Student2': '0591238', 'e-mail': 'ex@mail.com', 'student_num': 99305},
# {'Student3': '9213189', 'e-mail': 'ex@mail.com', 'student_num': 78360}

*Note: implement the random number generator however you wish.  This one returns random integers from a sample population.


问:
ASP.NET MVC Controller with multiple repositories?
I have a View where I am searching my db for an object(i.e. Books)..

My controller for this view depends on a BooksRepository that implements a search method.

Everything works fine. I also have the option to do an advanced search which presents a larger form in a Modal popup. This form has many fields including a Dropdown box to select an 'Author' to search by.

I would like to pass a list of authors in my viewmodel so in my conroller I instantiate an instance of my view model, I need to call a repository method to bring back the list of authors's...

My thinking is that this GetAuthors() method should be in an AuthorRepository...

Is it bad practice to inject multiple repo's into a controller?  or should I have an Author controller that gets injected with the author repo...and call a method in the Author controller from my BookSearch controller?

答:
Personally, I would think that books and authors are pretty specific entities.... unless you're planning on having an author write a song as well, and you want to have a music repository and a book repository, I would probably keep the authors and books in the same repository, as you're more than likely going to need them both at the same time.

Even then, you could have a music repository and a book repository that both pull from the same author table. There's nothing wrong with that. And no, having more than one repository in a controller is not a "no-no", but unless you're using dependency injection, it can start to get hairy as you add more repositories.

ContentLicense: CC BY-SA 3.0


问:
Converting column in data frame to class list
I am trying to convert a column in data frame into a list.

The data frame is in this format

```<code>State   combo
1   0,0,0,0,0,0
2   1,0,0,0,0,0
3   0,1,0,0,0,0
4   1,1,0,0,0,0
5   0,0,1,0,0,0
6   1,0,1,0,0,0
7   0,1,1,0,0,0
</code>```

What I need to do is change each row in the column 'combo' to a numeric list. So what I want to end up with is something where row 1 is equal to c(0,0,0,0,0) etc.

my code so far is...

```<code>list.combo<- read.csv("data")

rownames(list.combo) <- list.char$State

char.l <- list.char%>%
  select(combo)
</code>```

答:
Here's one way with tidyverse -

```<code>df %>%
  separate_rows(combo, sep = ",") %>%
  {split(as.numeric(.$combo), .$State)} %>%
  setNames(paste0("State", seq_along(.)))

$State1
[1] 0 0 0 0 0 0

$State2
[1] 1 0 0 0 0 0

$State3
[1] 0 1 0 0 0 0

$State4
[1] 1 1 0 0 0 0

$State5
[1] 0 0 1 0 0 0

$State6
[1] 1 0 1 0 0 0

$State7
[1] 0 1 1 0 0 0
</code>```

Here's a better way derived from @thelatemail comment -

```<code>strsplit(as.character(df$combo), ",") %>%
  lapply(as.numeric) %>%
  setNames(paste0("State", seq_along(.)))
</code>```

Data -

```<code>df <- read.table(text = "State   combo
1   0,0,0,0,0,0
2   1,0,0,0,0,0
3   0,1,0,0,0,0
4   1,1,0,0,0,0
5   0,0,1,0,0,0
6   1,0,1,0,0,0
7   0,1,1,0,0,0", header = T, stringsAsFactors = F)
</code>```

Body:
I am trying to convert a column in data frame into a list.

The data frame is in this format

State   combo
1   0,0,0,0,0,0
2   1,0,0,0,0,0
3   0,1,0,0,0,0
4   1,1,0,0,0,0
5   0,0,1,0,0,0
6   1,0,1,0,0,0
7   0,1,1,0,0,0

What I need to do is change each row in the column 'combo' to a numeric list. So what I want to end up with is something where row 1 is equal to c(0,0,0,0,0) etc.

my code so far is...

list.combo<- read.csv("data")

rownames(list.combo) <- list.char$State

char.l <- list.char%>%
  select(combo)

Body:
Here's one way with tidyverse -

df %>%
  separate_rows(combo, sep = ",") %>%
  {split(as.numeric(.$combo), .$State)} %>%
  setNames(paste0("State", seq_along(.)))

$State1
[1] 0 0 0 0 0 0

$State2
[1] 1 0 0 0 0 0

$State3
[1] 0 1 0 0 0 0

$State4
[1] 1 1 0 0 0 0

$State5
[1] 0 0 1 0 0 0

$State6
[1] 1 0 1 0 0 0

$State7
[1] 0 1 1 0 0 0

Here's a better way derived from @thelatemail comment -

strsplit(as.character(df$combo), ",") %>%
  lapply(as.numeric) %>%
  setNames(paste0("State", seq_along(.)))

Data -

df <- read.table(text = "State   combo
1   0,0,0,0,0,0
2   1,0,0,0,0,0
3   0,1,0,0,0,0
4   1,1,0,0,0,0
5   0,0,1,0,0,0
6   1,0,1,0,0,0
7   0,1,1,0,0,0", header = T, stringsAsFactors = F)


问:
Remove directory from Google Cloud Compute Engine using serial console
The storage on my Google Cloud Compute Engine Instance (inadvertently) got completely used up. I can no longer SSH into my instance. I have increased the space on my instance, but it still will not allow me to SSH. My VM operating system is Ubuntu.

I have tried two things:

1.) I have tried creating a start script to remove a large directory to clear up some space. Under "custom metadata" I have set the key as "startup-script" and the value as

#! /bin/bash
rm /home/myusername/dir-to-rm
```

<p>I save and reset the instance, click "connect to serial console", but I still cannot SSH.</p>

<p>2.) I have tried to use a startup script to set a login username and password for the serial console by using the same method, but with the following script:</p>

<pre class="lang-sh prettyprint-override"><code>#! /bin/bash
sudo useradd tmpuser
echo 'tmpuser:password' | chpasswd
</code>```

答:
I would suggest to create a snapshot from your VM instance [1] and then create a disk using the snapshot you created. After that, create a new instance using the newly created disk and try to ssh. Check if you can access all your files in the newly created instance via SSH.

[1] https://cloud.google.com/compute/docs/disks/create-snapshots

Hope this helps.

Body:
The storage on my Google Cloud Compute Engine Instance (inadvertently) got completely used up. I can no longer SSH into my instance. I have increased the space on my instance, but it still will not allow me to SSH. My VM operating system is Ubuntu.

I have tried two things:

1.) I have tried creating a start script to remove a large directory to clear up some space. Under "custom metadata" I have set the key as "startup-script" and the value as

#! /bin/bash
rm /home/myusername/dir-to-rm

I save and reset the instance, click "connect to serial console", but I still cannot SSH.

2.) I have tried to use a startup script to set a login username and password for the serial console by using the same method, but with the following script:

#! /bin/bash
sudo useradd tmpuser
echo 'tmpuser:password' | chpasswd


问:
Can't change emulated performance of AVD in Android Studio
I can't change the graphics to software as I'm sure this is the fix for my AVD not launching.
The option is greyed out (see screenshot). Has anyone has experience with this? I couldn't find anyone who had the same issue.

I'm running the latest version of Android Studio on Ubuntu 17.04.

答:
I am little late on this thread but following are my findings and solution. I am using Ubunut 18.04 and faced the same issue. The solution is to edit AVD and under Emulated Performance, change the grpahics to Software. The problem was that this option was disabled for me. I was unable to change graphics drop down.

I did some more research and found that while creating AVD if you choose default/existing device definition on first screen, you will not be able to edit graphics drop down.

The solution is to create a "New Hardward Profile" while creating AVD and use your new profile. Now, you will be able to edit "Grahics" drop down.

Hope this helps....


问:
Can't rename ... No such file or directory
I have some files need to rename recursively. So I execute the command find shop-bill -depth -type f -exec rename -v "s/shop/shop-bill/" {} +, but it gave me the following error. I was confused about the No such file or directory error and I can confirm that the files does exist.

```<code>liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ find shop-bill -depth -type f -exec rename -v "s/shop/shop-bill/" {} +
Can't rename shop-bill/dto/shop.dto.ts shop-bill-bill/dto/shop.dto.ts: No such file or directory
Can't rename shop-bill/shop.controller.ts shop-bill-bill/shop.controller.ts: No such file or directory
Can't rename shop-bill/shop.entity.ts shop-bill-bill/shop.entity.ts: No such file or directory
Can't rename shop-bill/shop.module.ts shop-bill-bill/shop.module.ts: No such file or directory
Can't rename shop-bill/shop.providers.ts shop-bill-bill/shop.providers.ts: No such file or directory
Can't rename shop-bill/shop.service.ts shop-bill-bill/shop.service.ts: No such file or directory
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ ll shop-bill/dto/shop.dto.ts
-rwxrwxrwx 1 liudonghua liudonghua 879 May 29 17:17 shop-bill/dto/shop.dto.ts*
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ tree shop-bill
shop-bill
├── dto
│   └── shop.dto.ts
├── shop.controller.ts
├── shop.entity.ts
├── shop.module.ts
├── shop.providers.ts
└── shop.service.ts

1 directory, 6 files
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
</code>```

The strange thing is that I can execute the similar command successfully like this.

```<code>liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ tree operator-bill
operator-bill
├── dto
│   └── shop.dto.ts
├── shop.controller.ts
├── shop.entity.ts
├── shop.module.ts
├── shop.providers.ts
└── shop.service.ts

1 directory, 6 files
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ find operator-bill -depth -type f -exec rename -v "s/shop/operator-bill/" {} +
operator-bill/dto/shop.dto.ts renamed as operator-bill/dto/operator-bill.dto.ts
operator-bill/shop.controller.ts renamed as operator-bill/operator-bill.controller.ts
operator-bill/shop.entity.ts renamed as operator-bill/operator-bill.entity.ts
operator-bill/shop.module.ts renamed as operator-bill/operator-bill.module.ts
operator-bill/shop.providers.ts renamed as operator-bill/operator-bill.providers.ts
operator-bill/shop.service.ts renamed as operator-bill/operator-bill.service.ts
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ rename -v
Usage:
    rename [ -h|-m|-V ] [ -v ] [ -n ] [ -f ] [ -e|-E perlexpr]*|perlexpr
    [ files ]

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ rename -V
/usr/bin/rename using File::Rename version 0.20

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
</code>```

答:
Finally, I found the problem, it was the parent directory also have renamed.</p>

```<code>liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ find shop-bill -depth -type f -exec rename -n "s/shop/shop-bill/" {} +
rename(shop-bill/dto/shop.dto.ts, shop-bill-bill/dto/shop.dto.ts)
rename(shop-bill/shop.controller.ts, shop-bill-bill/shop.controller.ts)
rename(shop-bill/shop.entity.ts, shop-bill-bill/shop.entity.ts)
rename(shop-bill/shop.module.ts, shop-bill-bill/shop.module.ts)
rename(shop-bill/shop.providers.ts, shop-bill-bill/shop.providers.ts)
rename(shop-bill/shop.service.ts, shop-bill-bill/shop.service.ts)
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ ll shop-bill-bill/dto/shop.dto.ts
ls: cannot access 'shop-bill-bill/dto/shop.dto.ts': No such file or directory
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ cd shop-bill
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$ find . -depth -type f -exec rename -n "s/shop/shop-bill/" {} +
rename(./dto/shop.dto.ts, ./dto/shop-bill.dto.ts)
rename(./shop.controller.ts, ./shop-bill.controller.ts)
rename(./shop.entity.ts, ./shop-bill.entity.ts)
rename(./shop.module.ts, ./shop-bill.module.ts)
rename(./shop.providers.ts, ./shop-bill.providers.ts)
rename(./shop.service.ts, ./shop-bill.service.ts)
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$ find . -depth -type f -exec rename -v "s/shop/shop-bill/" {} +
./dto/shop.dto.ts renamed as ./dto/shop-bill.dto.ts
./shop.controller.ts renamed as ./shop-bill.controller.ts
./shop.entity.ts renamed as ./shop-bill.entity.ts
./shop.module.ts renamed as ./shop-bill.module.ts
./shop.providers.ts renamed as ./shop-bill.providers.ts
./shop.service.ts renamed as ./shop-bill.service.ts
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$
</code>```

Body:
I have some files need to rename recursively. So I execute the command find shop-bill -depth -type f -exec rename -v "s/shop/shop-bill/" {} +, but it gave me the following error. I was confused about the No such file or directory error and I can confirm that the files does exist.

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ find shop-bill -depth -type f -exec rename -v "s/shop/shop-bill/" {} +
Can't rename shop-bill/dto/shop.dto.ts shop-bill-bill/dto/shop.dto.ts: No such file or directory
Can't rename shop-bill/shop.controller.ts shop-bill-bill/shop.controller.ts: No such file or directory
Can't rename shop-bill/shop.entity.ts shop-bill-bill/shop.entity.ts: No such file or directory
Can't rename shop-bill/shop.module.ts shop-bill-bill/shop.module.ts: No such file or directory
Can't rename shop-bill/shop.providers.ts shop-bill-bill/shop.providers.ts: No such file or directory
Can't rename shop-bill/shop.service.ts shop-bill-bill/shop.service.ts: No such file or directory
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ ll shop-bill/dto/shop.dto.ts
-rwxrwxrwx 1 liudonghua liudonghua 879 May 29 17:17 shop-bill/dto/shop.dto.ts*
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ tree shop-bill
shop-bill
├── dto
│   └── shop.dto.ts
├── shop.controller.ts
├── shop.entity.ts
├── shop.module.ts
├── shop.providers.ts
└── shop.service.ts

1 directory, 6 files
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$

The strange thing is that I can execute the similar command successfully like this.

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ tree operator-bill
operator-bill
├── dto
│   └── shop.dto.ts
├── shop.controller.ts
├── shop.entity.ts
├── shop.module.ts
├── shop.providers.ts
└── shop.service.ts

1 directory, 6 files
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ find operator-bill -depth -type f -exec rename -v "s/shop/operator-bill/" {} +
operator-bill/dto/shop.dto.ts renamed as operator-bill/dto/operator-bill.dto.ts
operator-bill/shop.controller.ts renamed as operator-bill/operator-bill.controller.ts
operator-bill/shop.entity.ts renamed as operator-bill/operator-bill.entity.ts
operator-bill/shop.module.ts renamed as operator-bill/operator-bill.module.ts
operator-bill/shop.providers.ts renamed as operator-bill/operator-bill.providers.ts
operator-bill/shop.service.ts renamed as operator-bill/operator-bill.service.ts
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ rename -v
Usage:
    rename [ -h|-m|-V ] [ -v ] [ -n ] [ -f ] [ -e|-E perlexpr]*|perlexpr
    [ files ]

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ rename -V
/usr/bin/rename using File::Rename version 0.20

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$

Body:
Finally, I found the problem, it was the parent directory also have renamed.

liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ find shop-bill -depth -type f -exec rename -n "s/shop/shop-bill/" {} +
rename(shop-bill/dto/shop.dto.ts, shop-bill-bill/dto/shop.dto.ts)
rename(shop-bill/shop.controller.ts, shop-bill-bill/shop.controller.ts)
rename(shop-bill/shop.entity.ts, shop-bill-bill/shop.entity.ts)
rename(shop-bill/shop.module.ts, shop-bill-bill/shop.module.ts)
rename(shop-bill/shop.providers.ts, shop-bill-bill/shop.providers.ts)
rename(shop-bill/shop.service.ts, shop-bill-bill/shop.service.ts)
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ ll shop-bill-bill/dto/shop.dto.ts
ls: cannot access 'shop-bill-bill/dto/shop.dto.ts': No such file or directory
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src$ cd shop-bill
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$ find . -depth -type f -exec rename -n "s/shop/shop-bill/" {} +
rename(./dto/shop.dto.ts, ./dto/shop-bill.dto.ts)
rename(./shop.controller.ts, ./shop-bill.controller.ts)
rename(./shop.entity.ts, ./shop-bill.entity.ts)
rename(./shop.module.ts, ./shop-bill.module.ts)
rename(./shop.providers.ts, ./shop-bill.providers.ts)
rename(./shop.service.ts, ./shop-bill.service.ts)
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$ find . -depth -type f -exec rename -v "s/shop/shop-bill/" {} +
./dto/shop.dto.ts renamed as ./dto/shop-bill.dto.ts
./shop.controller.ts renamed as ./shop-bill.controller.ts
./shop.entity.ts renamed as ./shop-bill.entity.ts
./shop.module.ts renamed as ./shop-bill.module.ts
./shop.providers.ts renamed as ./shop-bill.providers.ts
./shop.service.ts renamed as ./shop-bill.service.ts
liudonghua@desktop-ldh:/mnt/d/code/node/nestjs-sequelize-typescript/src/shop-bill$


问:
Copy/paste cell data from selected cells in row
My job requires that I copy/paste data from multiple cells in a row from one Excel worksheet to specific cells in another Excel worksheet.

I created a macro, but it is only selecting the specific cells I selected when recording the macro - these cells will always change depending on which row I'm needing the data from, so the recorded macro is useless. Also, the location of where this info will be pasted on the other worksheet will always be different (the macro copies the same exact data selected when recording and pastes it in the same exact location selected to paste when recording). I'm a noob at VBA, so I'm unsure on how to accomplish this.

I basically want to specify a specific row to start copying data from, and always select the same cells on that specific row as well as paste the data to specific cells on whatever row I have selected on the destination worksheet. Can someone help? This is for my job - any help would be appreciated. Ideally I'd like the macro to tab over to the specific cells needed and copy that info, from whatever row the macros starts on - and then paste that data to the cells selected via tabbing over on whatever row is selected in the other worksheet at the time of the macro being ran, if that makes sense.

答:
You need to come up with an internal logic of what cells get copied and where are they pasted to, after you do so, you can adapt the following code to suit your needs:</p>

```<code>Sub Test2()

    'Define variables

    Dim wkCopy As Workbook
    Dim wkDest As Workbook

    Dim wsCopy As Worksheet
    Dim wsDest As Worksheet

    ' Change names as required
    Set wsCopy = Workbooks("Joey's May FY19 Audit.xlsm").Worksheets("Sheet1")
    Set wsDest = Workbooks("Master Files - May.xlsm").Worksheets("Sheet1")

    ' Copy a range from the source sheet and paste in the destination one
    wsCopy.Range("A1:A10").Copy wsDest.Range("B11")

End Sub
</code>```

Body:
You need to come up with an internal logic of what cells get copied and where are they pasted to, after you do so, you can adapt the following code to suit your needs:

Sub Test2()

    'Define variables

    Dim wkCopy As Workbook
    Dim wkDest As Workbook

    Dim wsCopy As Worksheet
    Dim wsDest As Worksheet

    ' Change names as required
    Set wsCopy = Workbooks("Joey's May FY19 Audit.xlsm").Worksheets("Sheet1")
    Set wsDest = Workbooks("Master Files - May.xlsm").Worksheets("Sheet1")

    ' Copy a range from the source sheet and paste in the destination one
    wsCopy.Range("A1:A10").Copy wsDest.Range("B11")

End Sub


问:
Resource with a single attribute. Sign that something smells?
I have a book model and a notes model. Each book can have many notes.

```<code># note.rb
id | book_id | content | page_number | author_id |
</code>```

I want to run a lot of queries like

Get all the notes for page 43 of a certain book

Show all the noted pages of a certain book

These types of queries seem to favor making a separate noted_pages model so that a book can have many noted_pages and each noted_page can have many notes. This is fine but my noted_pages table would effectively just have an id column and a page_number column which doesn't sit right with me.

Is there a more standard way to implement this kind of setup or is my thinking ok?

答:
No design is bad ... it just need to be justified.

I see different solutions :

A BOOK {title, author, edited_date ...} has many PAGE {content} has_many NOTES {note_content}

A BOOK {content, title, author, edited_date ...} has_many NOTES {note_content, page_number}

It depends on how you work with the book. Do you plan on saving the content of the book by pages or not ? If not, then can you find the page, and therefore the notes ?

Regarding your questions :

A model with one attribute is not the sign that it "smells". You can even have a 1-to-1 relationship, if it's justifier.

There's no "standard" way of implementing stuff. Like I said, it depends on how you work, on how you plan your users to use it (UI-wised), how you would store, etc....

You definatly won't need a many-to-many in your case ... rails provide enough tools t fetch from a model to its associations, w/ w/o conditions, etc...

Let me know if it helps.

Body:
I have a book model and a notes model. Each book can have many notes.

# note.rb
id | book_id | content | page_number | author_id |

I want to run a lot of queries like

Get all the notes for page 43 of a certain book

Show all the noted pages of a certain book

These types of queries seem to favor making a separate noted_pages model so that a book can have many noted_pages and each noted_page can have many notes. This is fine but my noted_pages table would effectively just have an id column and a page_number column which doesn't sit right with me.

Is there a more standard way to implement this kind of setup or is my thinking ok?


问:
Handle NumericUpDown.ValueChanged event before ToolStripButton.Click event
I have a form with the NumericUpDown and the ToolStripButton.

In the NumericUpDowns ValueChanged event handler the value of some object instance is changed.

In the ToolStripButtons Click event handler the object instance is saved.

Now the problem is that if I rewrite the value in the NumericUpDown and then click on the ToolStripButton to save the state the ToolStripButtons Click event is fired before the NumericUpDowns ValueChanged event so I first save the instance and after that I changed it.

```<code>public partial class Form2 : Form
{
    private Foo _foo = new Foo();

    public Form2()
    {
        InitializeComponent();
    }

    private void NumericUpDown1_ValueChanged(object sender, EventArgs e)
    {
        _foo.Value = numericUpDown1.Value;
    }

    private void ToolStripButton1_Click(object sender, EventArgs e)
    {
        _foo.Save();
    }

    private class Foo
    {
        public decimal Value { get; set; }

        public void Save()
        {
            //Save the value...
        }
    }
}
</code>```

What is the best way to solve this?

Those events are fired in the correct order if I use the Button control, but not if I use the ToolStripButton control.

答:
As an option, instead of ValueChanged, handle Validated event of NumericUpDown and also in the Click event handler of ToolStripButton, call this.Validate() before save:

```<code>private void NumericUpDown1_Validated(object sender, EventArgs e)
{
    _foo.Value = numericUpDown1.Value;
}

private void ToolStripButton1_Click(object sender, EventArgs e)
{
    this.Validate();
    _foo.Save();
}
</code>```

Note: If there are other controls on the form which may have Validating event and you may set e.Cancel = true for them, you need to check the result of Validate method before calling Save, using if(this.Validate()){ /*...*/ }.

Body:
I have a form with the NumericUpDown and the ToolStripButton.

In the NumericUpDowns ValueChanged event handler the value of some object instance is changed.

In the ToolStripButtons Click event handler the object instance is saved.

Now the problem is that if I rewrite the value in the NumericUpDown and then click on the ToolStripButton to save the state the ToolStripButtons Click event is fired before the NumericUpDowns ValueChanged event so I first save the instance and after that I changed it.

public partial class Form2 : Form
{
    private Foo _foo = new Foo();

    public Form2()
    {
        InitializeComponent();
    }

    private void NumericUpDown1_ValueChanged(object sender, EventArgs e)
    {
        _foo.Value = numericUpDown1.Value;
    }

    private void ToolStripButton1_Click(object sender, EventArgs e)
    {
        _foo.Save();
    }

    private class Foo
    {
        public decimal Value { get; set; }

        public void Save()
        {
            //Save the value...
        }
    }
}

What is the best way to solve this?

Those events are fired in the correct order if I use the Button control, but not if I use the ToolStripButton control.

Body:
As an option, instead of ValueChanged, handle Validated event of NumericUpDown and also in the Click event handler of ToolStripButton, call this.Validate() before save:

private void NumericUpDown1_Validated(object sender, EventArgs e)
{
    _foo.Value = numericUpDown1.Value;
}

private void ToolStripButton1_Click(object sender, EventArgs e)
{
    this.Validate();
    _foo.Save();
}

Note: If there are other controls on the form which may have Validating event and you may set e.Cancel = true for them, you need to check the result of Validate method before calling Save, using if(this.Validate()){ /*...*/ }.


问:
Using Dictionary to Cut-Out Parts of Strings in a List
I have a long list that is generated using Beautiful Soup in Python 3.

Right now, the list is generated as so..

```<code>mylist = [a['href'] for a in soup.find_all('a', href=True) if a.text]
</code>```

It's a web scraping thing, but just know it returns a list.

And in the form of a list, it returns results such as these:

'catalogue/category/books/travel_2/index.html',

'catalogue/category/books/mystery_3/index.html',

'catalogue/category/books/historical-fiction_4/index.html'

Before I print my list, I'd like to remove various useless information (such as "catalogue/", "category/" and "books/", so that only the important information is displayed (travel, mystery or historical fiction).

I was able to replace one thing successfully using:

```<code>mylist = [item.replace("catalogue/category/", "") for item in mylist]
</code>```

Which worked great. But I don't believe .replace will take more than 2 arguments, which leaves me unable to remove additional things from my results such as "index.html" . I'd rather not write that line for everything I want to replace. That's why I'm trying to use keys and values from a dictionary as the .replace() arguments:

```<code>replacedict = {"catalogue/category/": "" , "index.html": ""}

mylist = [a['href'] for a in soup.find_all('a', href=True) if a.text]

def replace_all(mylist, replacedict):
     for k, v in replacedict.items():
         mylist = [item.replace(k, v) for item in mylist]
     return mylist

replace_all(mylist, replacedict)

print(mylist)
</code>```

Right now, the program isn't throwing any errors when it's run. But it's also simply NOT doing what i'm asking of it. It's just returning a large list of results shown above with nothing removed or replaced out of them.

Very confused, although I'm sure the answer is right in front of me.

Appreciate any and all help, couldn't find a question quite like this one anywhere.

答:
How about using regular expression?

```<code>import re

my_list = ['catalogue/category/books/travel_2/index.html', 'catalogue/category/books/mystery_3/index.html', 'catalogue/category/books/historical-fiction_4/index.html']

REGEX = r'(catalogue/|category/|books/|_\d+/index.html)'

my_list = [re.sub(REGEX, '', string) for string in my_list]

print(my_list)
</code>```

Output:

```<code>['travel', 'mystery', 'historical-fiction']
</code>```

Body:
I have a long list that is generated using Beautiful Soup in Python 3.

Right now, the list is generated as so..

mylist = [a['href'] for a in soup.find_all('a', href=True) if a.text]

It's a web scraping thing, but just know it returns a list.

And in the form of a list, it returns results such as these:

'catalogue/category/books/travel_2/index.html',

'catalogue/category/books/mystery_3/index.html',

'catalogue/category/books/historical-fiction_4/index.html'

Before I print my list, I'd like to remove various useless information (such as "catalogue/", "category/" and "books/", so that only the important information is displayed (travel, mystery or historical fiction).

I was able to replace one thing successfully using:

mylist = [item.replace("catalogue/category/", "") for item in mylist]

Which worked great. But I don't believe .replace will take more than 2 arguments, which leaves me unable to remove additional things from my results such as "index.html" . I'd rather not write that line for everything I want to replace. That's why I'm trying to use keys and values from a dictionary as the .replace() arguments:

replacedict = {"catalogue/category/": "" , "index.html": ""}

mylist = [a['href'] for a in soup.find_all('a', href=True) if a.text]

def replace_all(mylist, replacedict):
     for k, v in replacedict.items():
         mylist = [item.replace(k, v) for item in mylist]
     return mylist

replace_all(mylist, replacedict)

print(mylist)

Right now, the program isn't throwing any errors when it's run. But it's also simply NOT doing what i'm asking of it. It's just returning a large list of results shown above with nothing removed or replaced out of them.

Very confused, although I'm sure the answer is right in front of me.

Appreciate any and all help, couldn't find a question quite like this one anywhere.

Body:
How about using regular expression?

import re

my_list = ['catalogue/category/books/travel_2/index.html', 'catalogue/category/books/mystery_3/index.html', 'catalogue/category/books/historical-fiction_4/index.html']

REGEX = r'(catalogue/|category/|books/|_\d+/index.html)'

my_list = [re.sub(REGEX, '', string) for string in my_list]

print(my_list)

Output:

['travel', 'mystery', 'historical-fiction']