问:
How to create different dashboards for different users of a Shiny app? (on the same app code)
I need to create a Shiny App that will generate 6 different versions of the same dashboard layout, to 6 different users. Each user will see its own historical data during production, and it's all in the same database (I'm guessing I just need to filter the whole database for each specific user).

Specifically:

1 - How do I detect which user is which? I'm gonna use Authentication so I'm guessing I can probably retrieve the information from the user by how he logged. But how do I retrieve this information in code terms?

2 - Knowing which user is which, how do I create the 6 different versions on the same app code? They'll be the same layout, the only difference is the filtering of the dataset based on the user.

(optional) 3 - How does Shiny servers conciliate different users' displays? Thinking about a dashboard that has user interaction, different inputs don't interfere each others' displays? Do they have to replicate the code for each access so they're independent results?

I haven't made it yet, and even if I did I think it would be too complex to resolve here, so I'm posting the Hello World of Shiny. This way, imagine that the dataset used for plotting the Histogram has a column called 'user'. What would be the code used for discriminating the users?

```<code>library(shiny)

  output$distPlot <- renderPlot({

    dist <- dataset[1:obs,1] %>% filter(???)
    hist(dist)
  })

})

shinyUI(fluidPage(

  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for number of observations
  sidebarLayout(
    sidebarPanel(
      sliderInput("obs",
                  "Number of observations:",
                  min = 1,
                  max = 1000,
                  value = 500)
    ),

    mainPanel(
      plotOutput("distPlot")
    )
  )
))
</code>```

Thanks!

答:
```<code>login1 <- c("user1", "pw1")
login2 <- c("user2", "pw2")

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    uiOutput("ui")

    # Sidebar with a slider input for number of bins
)

# Define server logic required to draw a histogram
server <- function(input, output) {

    logged <- reactiveValues(logged = FALSE, user = NULL)

    observeEvent(input$signin, {
        if(input$name == "user1" & input$pw == "pw1") {
            logged$logged <- TRUE
            logged$user <- "user1"
        } else if (input$name == "user2" & input$pw == "pw2") {
            logged$logged <- TRUE
            logged$user <- "user2"
        } else {}
    })

    output$ui <- renderUI({

        if(logged$logged == FALSE) {
            return(
                tagList(
                    textInput("name", "Name"),
                    passwordInput("pw", "Password"),
                    actionButton("signin", "Sign In")
                )
            )
        } else if(logged$logged == TRUE & logged$user == "user1") {
            return(
                tagList(
                    titlePanel("This is user 1 Panel"),
                    tags$h1("User 1 is only able to see text, but no plots")
                )
            )
        } else if(logged$logged == TRUE & logged$user == "user2") {
            return(
                tagList(
                    titlePanel("This is user 2 Panel for Executetives"),
                    sidebarLayout(
                        sidebarPanel(
                            sliderInput("bins",
                                        "Number of bins:",
                                        min = 1,
                                        max = 50,
                                        value = 30)
                        ),

                        # Show a plot of the generated distribution
                        mainPanel(
                            plotOutput("distPlot")
                        )
                    )
                )
            )
        } else {}
    })

    output$distPlot <- renderPlot({
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
}

# Run the application
shinyApp(ui = ui, server = server)
</code>```

This is a SIMPLE way to make it work. You get reactiveValues passed as conditional inputs to the renderUI function.

However, this is a very dangerous solution, since passwords and users are not encrypted. For professional deployment with R Shiny, think about Shiny-Server or my personal favorite ShinyProxy (https://www.shinyproxy.io/)

Body:
I need to create a Shiny App that will generate 6 different versions of the same dashboard layout, to 6 different users. Each user will see its own historical data during production, and it's all in the same database (I'm guessing I just need to filter the whole database for each specific user).

Specifically:

1 - How do I detect which user is which? I'm gonna use Authentication so I'm guessing I can probably retrieve the information from the user by how he logged. But how do I retrieve this information in code terms?

2 - Knowing which user is which, how do I create the 6 different versions on the same app code? They'll be the same layout, the only difference is the filtering of the dataset based on the user.

(optional) 3 - How does Shiny servers conciliate different users' displays? Thinking about a dashboard that has user interaction, different inputs don't interfere each others' displays? Do they have to replicate the code for each access so they're independent results?

I haven't made it yet, and even if I did I think it would be too complex to resolve here, so I'm posting the Hello World of Shiny. This way, imagine that the dataset used for plotting the Histogram has a column called 'user'. What would be the code used for discriminating the users?

library(shiny)

  output$distPlot <- renderPlot({

    dist <- dataset[1:obs,1] %>% filter(???)
    hist(dist)
  })

})

shinyUI(fluidPage(

  titlePanel("Hello Shiny!"),

  # Sidebar with a slider input for number of observations
  sidebarLayout(
    sidebarPanel(
      sliderInput("obs",
                  "Number of observations:",
                  min = 1,
                  max = 1000,
                  value = 500)
    ),

    mainPanel(
      plotOutput("distPlot")
    )
  )
))

Thanks!

Body:
login1 <- c("user1", "pw1")
login2 <- c("user2", "pw2")

library(shiny)

# Define UI for application that draws a histogram
ui <- fluidPage(

    # Application title
    uiOutput("ui")

    # Sidebar with a slider input for number of bins
)

# Define server logic required to draw a histogram
server <- function(input, output) {

    logged <- reactiveValues(logged = FALSE, user = NULL)

    observeEvent(input$signin, {
        if(input$name == "user1" & input$pw == "pw1") {
            logged$logged <- TRUE
            logged$user <- "user1"
        } else if (input$name == "user2" & input$pw == "pw2") {
            logged$logged <- TRUE
            logged$user <- "user2"
        } else {}
    })

    output$ui <- renderUI({

        if(logged$logged == FALSE) {
            return(
                tagList(
                    textInput("name", "Name"),
                    passwordInput("pw", "Password"),
                    actionButton("signin", "Sign In")
                )
            )
        } else if(logged$logged == TRUE & logged$user == "user1") {
            return(
                tagList(
                    titlePanel("This is user 1 Panel"),
                    tags$h1("User 1 is only able to see text, but no plots")
                )
            )
        } else if(logged$logged == TRUE & logged$user == "user2") {
            return(
                tagList(
                    titlePanel("This is user 2 Panel for Executetives"),
                    sidebarLayout(
                        sidebarPanel(
                            sliderInput("bins",
                                        "Number of bins:",
                                        min = 1,
                                        max = 50,
                                        value = 30)
                        ),

                        # Show a plot of the generated distribution
                        mainPanel(
                            plotOutput("distPlot")
                        )
                    )
                )
            )
        } else {}
    })

    output$distPlot <- renderPlot({
        x    <- faithful[, 2]
        bins <- seq(min(x), max(x), length.out = input$bins + 1)
        hist(x, breaks = bins, col = 'darkgray', border = 'white')
    })
}

# Run the application
shinyApp(ui = ui, server = server)

This is a SIMPLE way to make it work. You get reactiveValues passed as conditional inputs to the renderUI function.

However, this is a very dangerous solution, since passwords and users are not encrypted. For professional deployment with R Shiny, think about Shiny-Server or my personal favorite ShinyProxy (https://www.shinyproxy.io/)


来源: stackexchange

问:
Is there a concise way to check if an int variable is equal to a series of ints? | C#
Rather than something like this:

```<code>switch (id) {
case 2:
case 5:
case 11:
case 15:
...
}
</code>```

Is there a concise way to check if an int variable is equal to any one of a series of integers? Maybe something like if (id == {2|5|11|15}) ...?

答:
You can do something like this:</p>

```<code>    bool exist = List.Init(6, 8, 2, 9, 12).Contains(8);

    foreach (int i in List.Init(6, 8, 2, 9, 12))
    {
        Console.WriteLine(i.ToString());
    }

    public class List : IEnumerable<int>
    {
        private int[] _values;

        public List(params int[] values)
        {
            _values = values;
        }

        public static List Init(params int[] values)
        {
            return new List(values);
        }

        public IEnumerator<int> GetEnumerator()
        {
            foreach (int value in _values)
            {
                yield return value;
            }
        }

        public bool Contains(int value)
        {
            return Array.IndexOf(_values, value) > -1;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
</code>```

ContentLicense: CC BY-SA 3.0

Body:
Rather than something like this:

switch (id) {
case 2:
case 5:
case 11:
case 15:
...
}

Is there a concise way to check if an int variable is equal to any one of a series of integers? Maybe something like if (id == {2|5|11|15}) ...?

Body:
You can do something like this:

    bool exist = List.Init(6, 8, 2, 9, 12).Contains(8);

    foreach (int i in List.Init(6, 8, 2, 9, 12))
    {
        Console.WriteLine(i.ToString());
    }

    public class List : IEnumerable<int>
    {
        private int[] _values;

        public List(params int[] values)
        {
            _values = values;
        }

        public static List Init(params int[] values)
        {
            return new List(values);
        }

        public IEnumerator<int> GetEnumerator()
        {
            foreach (int value in _values)
            {
                yield return value;
            }
        }

        public bool Contains(int value)
        {
            return Array.IndexOf(_values, value) > -1;
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }


问:
How can I add specific fields to a custom post type, outside of what's included in the default supports?
I've made a custom post type and registered it. I need some more fields for this post type, and would like to add 2 more with the specific keys that will load anytime a new post is made (IE like another excerpt field, but it will say Title/position). I'm not sure how to do this, and would like to avoid plugins. Any help would be greatly appreciated. </p>

```<code>    $labels = array(
      'name'                  => _x('Executive', 'post type general name '),
      'singular'              => _x('Executive', 'post type singular name'),
      'add_new'               => _x('Add new', 'text_domain'),
          'add_new_item'          => __( 'Add Executive', 'text_domain' ),
          'name_admin_bar'        => __( 'Staff', 'text_domain' ),
          'archives'              => __( 'Staff Archives', 'text_domain' ),
          'parent_item_colon'     => __( 'Parent Item:', 'text_domain' ),
          'all_items'             => __( 'All Exectives', 'text_domain' ),
          'new_item'              => __( 'New Item', 'text_domain' ),
          'edit_item'             => __( 'Edit Item', 'text_domain' ),
          'update_item'           => __( 'Update Item', 'text_domain' ),
          'view_item'             => __( 'View Item', 'text_domain' ),
          'search_items'          => __( 'Search Item', 'text_domain' ),
          'not_found'             => __( 'Not found', 'text_domain' ),
          'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
          'featured_image'        => __( 'Featured Image', 'text_domain' ),
          'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
          'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
          'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
          'insert_into_item'      => __( 'Insert into item', 'text_domain' ),
          'uploaded_to_this_item' => __( 'Uploaded to this item', 'text_domain' ),
          'items_list'            => __( 'Items list', 'text_domain' ),
          'items_list_navigation' => __( 'Items list navigation', 'text_domain' ),
      'filter_items_list'     => __( 'Filter items list', 'text_domain' ),
      'menu_name'             => __( 'Executives', 'text_domain' ),
    );
    $args = array(
      'label'                 => __( 'Executive', 'text_domain' ),
      'description'           => __( 'Executive Team', 'text_domain' ),
      'labels'                => $labels,
      'supports'              => array( 'title', 'author','name','excerpt','thumbnail', ),
      'hierarchical'          => false,
      'public'                => true,
      'show_ui'               => true,
      'show_in_menu'          => true,
      'menu_position'         => 5,
      'show_in_admin_bar'     => true,
      'show_in_nav_menus'     => false,
      'can_export'            => true,
      'has_archive'           => true,
      'exclude_from_search'   => false,
      'publicly_queryable'    => true,
      'rewrite'               => false,
      'capability_type'       => 'page',
    );
    register_post_type('Executives', $args);
  }

  add_action('init', 'custom_post_executive');
</code>```

答:
You need to register a custom meta box with a callback that will render the HTML. You can read more about it here: https://developer.wordpress.org/plugins/metadata/custom-meta-boxes/

I would also recommend looking at the plugin Advanced Custom Fields (ACF) as they make creating meta fields trivial.

```<code>function wporg_add_custom_box()
{
    $screens = ['post', 'wporg_cpt'];
    foreach ($screens as $screen) {
        add_meta_box(
            'wporg_box_id',           // Unique ID
            'Custom Meta Box Title',  // Box title
            'wporg_custom_box_html',  // Content callback, must be of type callable
            $screen                   // Post type
        );
    }
}
add_action('add_meta_boxes', 'wporg_add_custom_box');

function wporg_custom_box_html($post)
{
    ?>
    <label for="wporg_field">Description for this field</label>
    <select name="wporg_field" id="wporg_field" class="postbox">
        <option value="">Select something...</option>
        <option value="something">Something</option>
        <option value="else">Else</option>
    </select>
    <?php
}
</code>```

ContentLicense: CC BY-SA 4.0

Body:
I've made a custom post type and registered it. I need some more fields for this post type, and would like to add 2 more with the specific keys that will load anytime a new post is made (IE like another excerpt field, but it will say Title/position). I'm not sure how to do this, and would like to avoid plugins. Any help would be greatly appreciated.

    $labels = array(
      'name'                  => _x('Executive', 'post type general name '),
      'singular'              => _x('Executive', 'post type singular name'),
      'add_new'               => _x('Add new', 'text_domain'),
          'add_new_item'          => __( 'Add Executive', 'text_domain' ),
          'name_admin_bar'        => __( 'Staff', 'text_domain' ),
          'archives'              => __( 'Staff Archives', 'text_domain' ),
          'parent_item_colon'     => __( 'Parent Item:', 'text_domain' ),
          'all_items'             => __( 'All Exectives', 'text_domain' ),
          'new_item'              => __( 'New Item', 'text_domain' ),
          'edit_item'             => __( 'Edit Item', 'text_domain' ),
          'update_item'           => __( 'Update Item', 'text_domain' ),
          'view_item'             => __( 'View Item', 'text_domain' ),
          'search_items'          => __( 'Search Item', 'text_domain' ),
          'not_found'             => __( 'Not found', 'text_domain' ),
          'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
          'featured_image'        => __( 'Featured Image', 'text_domain' ),
          'set_featured_image'    => __( 'Set featured image', 'text_domain' ),
          'remove_featured_image' => __( 'Remove featured image', 'text_domain' ),
          'use_featured_image'    => __( 'Use as featured image', 'text_domain' ),
          'insert_into_item'      => __( 'Insert into item', 'text_domain' ),
          'uploaded_to_this_item' => __( 'Uploaded to this item', 'text_domain' ),
          'items_list'            => __( 'Items list', 'text_domain' ),
          'items_list_navigation' => __( 'Items list navigation', 'text_domain' ),
      'filter_items_list'     => __( 'Filter items list', 'text_domain' ),
      'menu_name'             => __( 'Executives', 'text_domain' ),
    );
    $args = array(
      'label'                 => __( 'Executive', 'text_domain' ),
      'description'           => __( 'Executive Team', 'text_domain' ),
      'labels'                => $labels,
      'supports'              => array( 'title', 'author','name','excerpt','thumbnail', ),
      'hierarchical'          => false,
      'public'                => true,
      'show_ui'               => true,
      'show_in_menu'          => true,
      'menu_position'         => 5,
      'show_in_admin_bar'     => true,
      'show_in_nav_menus'     => false,
      'can_export'            => true,
      'has_archive'           => true,
      'exclude_from_search'   => false,
      'publicly_queryable'    => true,
      'rewrite'               => false,
      'capability_type'       => 'page',
    );
    register_post_type('Executives', $args);
  }

  add_action('init', 'custom_post_executive');

Body:
You need to register a custom meta box with a callback that will render the HTML. You can read more about it here: https://developer.wordpress.org/plugins/metadata/custom-meta-boxes/

I would also recommend looking at the plugin Advanced Custom Fields (ACF) as they make creating meta fields trivial.

function wporg_add_custom_box()
{
    $screens = ['post', 'wporg_cpt'];
    foreach ($screens as $screen) {
        add_meta_box(
            'wporg_box_id',           // Unique ID
            'Custom Meta Box Title',  // Box title
            'wporg_custom_box_html',  // Content callback, must be of type callable
            $screen                   // Post type
        );
    }
}
add_action('add_meta_boxes', 'wporg_add_custom_box');

function wporg_custom_box_html($post)
{
    ?>
    <label for="wporg_field">Description for this field</label>
    <select name="wporg_field" id="wporg_field" class="postbox">
        <option value="">Select something...</option>
        <option value="something">Something</option>
        <option value="else">Else</option>
    </select>
    <?php
}


问:
Can you stream and batch from the same delta table?
I tried to stream and batch from the same delta table but ran into small files problem on the batch side. But if you optimize the delta table, the streaming size will lose track of the files it reads because the compaction results of the optimization.</p>

答:
When the OPTIMIZE command removes small files and adds back in compacted ones, these operations are flagged with the dataChange flag set to false. This flag tells streams that are following the transaction log that it is safe to ignore this transaction to avoid processing duplicate data.

I'll also note that DBR 5.3 contains a private preview features called Auto-Optimize, that can perform this compaction before small files even make it into the table. This feature will be GA-ed in the next release of DBR.


问:
Expo - Local Notifications not working on devices
I'm using EXPO to create an app for Android and iOS, with React Native.
There is a weird behavior in this code: It's working properly on the Expo App, but it's not working in the real devices (standalone build) (happening on iOS AND Android).

The logic of these Local notifications is the following:
The idea is to show to the user 3 local notifications:

The first one, 1 week after the last time the user opened the app

The second one, 1 month after the last time the user opened the app

The last one, 2 months after the last time the user opened the app

How do I do it?

The first time the app is opened, I ask the user if she wants to see notifications. If the user says YES, I write that info in the local storage, and then I request the USER_FACING_NOTIFICATIONS permission to show local notifications.

I'm using USER_FACING_NOTIFICATIONS because I don't send remote notifications.

Then, the second time the user opens the app, I do the following:

I remove all the previous notifications

I check if the user WANTS to see notifications

I check if the user/device GAVE US permissions to show notifications

I schedule the 3 notifications.

Here, part of the code:

componentDidMount() {
    cancelAllScheduled()
      .then(() => {
        getUserNotificationsPermission().then(userWants => {
          if (userWants) {
            getDeviceNotificationsPermission().then(grantedByDevice => {
              if (grantedByDevice) {
                scheduleNotifications();
              }
            });
          }
        });
      })
      .catch(() => {
        // :shrug:
      });
}
```

<p>Here, all those <code>utils</code> functions:</p>

<pre class="lang-js prettyprint-override"><code>// Cancel all the notifications
const cancelAllScheduled = () => {
  return ExpoNotifications.cancelAllScheduledNotificationsAsync();
}

// Check in local storage if the user WANTS to see notifications
const getUserNotificationsPermission = () => {
  return AsyncStorage.getItem('userNotificationPermission').then(data => {
    let isEnabled;

    try {
      isEnabled = JSON.parse(data);
    } catch (error) {
      isEnabled = false;
    }

    return isEnabled;
  });
};

// Check if user/device ALLOW US to show notifications
const getDeviceNotificationsPermission = () => {
  return Permissions.getAsync(Permissions.USER_FACING_NOTIFICATIONS).then(({ status }) => {
    return status === 'granted';
  });
};

// Add days
// https://stackoverflow.com/a/19691491/1815449
const _addDays = (date, days) => {
  var result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
};

// Schedule all the notifications
// One notification is going to be shown on 1 week
// Other notification in 1 month
// Other notification in 2 month
const scheduleNotifications = () => {
  const now = new Date();

  const oneWeek = {
    title: 'We miss you!',
    body: "Come to see what we've been up to and share your latest adventures with us!",
    data: {
      type: 'WEEKLY',
    },
  };
  const oneWeekOptions = { time: _addDays(now, 7) };
  ExpoNotifications.scheduleLocalNotificationAsync(oneWeek, oneWeekOptions);

  const oneMonth = {
    title: 'We miss you!',
    body: "Come to see what we've been up to and share your latest adventures with us!",
    data: {
      type: 'MONTHLY',
    },
  };
  const oneMonthOptions = { time: _addDays(now, 30) };
  ExpoNotifications.scheduleLocalNotificationAsync(oneMonth, oneMonthOptions);

  const twoMonth = {
    title: 'We miss you!',
    body: "Come to see what we've been up to and share your latest adventures with us!",
    data: {
      type: 'MONTHLY 2',
    },
  };
  const twoMonthOptions = { time: _addDays(now, 60) };
  ExpoNotifications.scheduleLocalNotificationAsync(twoMonth, twoMonthOptions);
};
</code>```

Do you see any clue about why this could not be working?
I already opened the app and granted all the permissions and killed and opened the app again close to 1.000 times hehehe. The last months I didn't open the app for 9 days (I did it 3 times) and I never saw any notification. But, the notifications are properly shown in the Expo Dev App.

Ps.: I do the cancelAllScheduled every time the user opens the app because these notifications need to be reset every time the user opens the app, due to I want to show then weeks after "the last time app was opened"

Ps2.: This is the documentation I followed to implement it:

https://docs.expo.io/versions/latest/sdk/notifications/

https://docs.expo.io/versions/v32.0.0/sdk/permissions/

答:
Seems like this was the problem: https://github.com/expo/expo/issues/4121
The notifications work, but due to I was scheduling them for 1 week, 1 month, and more, the notifications were not shown due to most of those devices were restarted after scheduling the notifications.

I have been waiting for 1 week with no opening the app again in iOS, and with no restarting the device or even upgrading the SO, and I can see the notification.
I didn't test it in Android yet. I may have to leave the Android phone connected for 1 week and see what happens.

Body:
I'm using EXPO to create an app for Android and iOS, with React Native.
There is a weird behavior in this code: It's working properly on the Expo App, but it's not working in the real devices (standalone build) (happening on iOS AND Android).

The logic of these Local notifications is the following:
The idea is to show to the user 3 local notifications:

The first one, 1 week after the last time the user opened the app

The second one, 1 month after the last time the user opened the app

The last one, 2 months after the last time the user opened the app

How do I do it?

The first time the app is opened, I ask the user if she wants to see notifications. If the user says YES, I write that info in the local storage, and then I request the USER_FACING_NOTIFICATIONS permission to show local notifications.

I'm using USER_FACING_NOTIFICATIONS because I don't send remote notifications.

Then, the second time the user opens the app, I do the following:

I remove all the previous notifications

I check if the user WANTS to see notifications

I check if the user/device GAVE US permissions to show notifications

I schedule the 3 notifications.

Here, part of the code:

componentDidMount() {
    cancelAllScheduled()
      .then(() => {
        getUserNotificationsPermission().then(userWants => {
          if (userWants) {
            getDeviceNotificationsPermission().then(grantedByDevice => {
              if (grantedByDevice) {
                scheduleNotifications();
              }
            });
          }
        });
      })
      .catch(() => {
        // :shrug:
      });
}

Here, all those utils functions:

// Cancel all the notifications
const cancelAllScheduled = () => {
  return ExpoNotifications.cancelAllScheduledNotificationsAsync();
}

// Check in local storage if the user WANTS to see notifications
const getUserNotificationsPermission = () => {
  return AsyncStorage.getItem('userNotificationPermission').then(data => {
    let isEnabled;

    try {
      isEnabled = JSON.parse(data);
    } catch (error) {
      isEnabled = false;
    }

    return isEnabled;
  });
};

// Check if user/device ALLOW US to show notifications
const getDeviceNotificationsPermission = () => {
  return Permissions.getAsync(Permissions.USER_FACING_NOTIFICATIONS).then(({ status }) => {
    return status === 'granted';
  });
};

// Add days
// https://stackoverflow.com/a/19691491/1815449
const _addDays = (date, days) => {
  var result = new Date(date);
  result.setDate(result.getDate() + days);
  return result;
};

// Schedule all the notifications
// One notification is going to be shown on 1 week
// Other notification in 1 month
// Other notification in 2 month
const scheduleNotifications = () => {
  const now = new Date();

  const oneWeek = {
    title: 'We miss you!',
    body: "Come to see what we've been up to and share your latest adventures with us!",
    data: {
      type: 'WEEKLY',
    },
  };
  const oneWeekOptions = { time: _addDays(now, 7) };
  ExpoNotifications.scheduleLocalNotificationAsync(oneWeek, oneWeekOptions);

  const oneMonth = {
    title: 'We miss you!',
    body: "Come to see what we've been up to and share your latest adventures with us!",
    data: {
      type: 'MONTHLY',
    },
  };
  const oneMonthOptions = { time: _addDays(now, 30) };
  ExpoNotifications.scheduleLocalNotificationAsync(oneMonth, oneMonthOptions);

  const twoMonth = {
    title: 'We miss you!',
    body: "Come to see what we've been up to and share your latest adventures with us!",
    data: {
      type: 'MONTHLY 2',
    },
  };
  const twoMonthOptions = { time: _addDays(now, 60) };
  ExpoNotifications.scheduleLocalNotificationAsync(twoMonth, twoMonthOptions);
};

Do you see any clue about why this could not be working?
I already opened the app and granted all the permissions and killed and opened the app again close to 1.000 times hehehe. The last months I didn't open the app for 9 days (I did it 3 times) and I never saw any notification. But, the notifications are properly shown in the Expo Dev App.

Ps.: I do the cancelAllScheduled every time the user opens the app because these notifications need to be reset every time the user opens the app, due to I want to show then weeks after "the last time app was opened"

Ps2.: This is the documentation I followed to implement it:

https://docs.expo.io/versions/latest/sdk/notifications/

https://docs.expo.io/versions/v32.0.0/sdk/permissions/


问:
Problem with function to determine the winner of multiple rounds in a dice game
We have an assignment to determine the ultimately winner in a dice game. Here's the complete rules:

You will be pitted against two other computer players in this game. There are three rounds. At the beginning of each round a player rolls two dice. The total of your dice roll for that round is added to your points. Your points always start at zero. Each consecutive round the points are added to the total. At the end of the third round, whoever has the most points wins the game.

REQUIREMENTS
————————
Each player has two dice
The player rolls each die once per round
Display each players score at the end of each round
Display the leader of the round at the end of each round
Prompt the user to roll to begin the next around
After three rounds the game is over
The players score persists until the end of the game
Once the game ends, a winner is declared
Once a winner is declared you have the option to restart or quit

I've gotten everything to work, except how to determine the ultimate winner of the game. I've tried making a new method called "gameWinner", using if/elsif statements, grabbing the total scores from each round and adding each up respectively. However, the program breaks once it reaches that. I can't think of how else to solve this problems, but nothing I type seems to function right.

```<code>def welcome
    puts ""
    puts "Let's roll some die! You will be competing against 2 computers in 3 rounds, each player having 2 die."
    puts "Please enter your name and press 'Enter'"
    puts ""
    @userName = gets.chomp
    puts ("Welcome, " + @userName + ". Let's roll those die!")
    puts ""
end

def round(round)
    result_1 = Random.new.rand(1..6)
    result_2 = Random.new.rand(1..6)
    total_1 = result_1 + result_2

    result_3 = Random.new.rand(1..6)
    result_4 = Random.new.rand(1..6)
    total_2 = result_3 + result_4

    result_5 = Random.new.rand(1..6)
    result_6 = Random.new.rand(1..6)
    total_3 = result_5 + result_6

    winner = [total_1, total_2, total_3].max
    players = {total_1 => @userName, total_2 => "Computer 1", total_3 => "Computer 2"}.max

    puts "Round #{round}"
    puts "#{@userName}, your die are a #{result_1} and a #{result_2}, totaling #{total_1}"
    puts "Computer 1's die are a #{result_3} and a #{result_4}, totaling #{total_2}"
    puts "Computer 2's die are a #{result_5} and a #{result_6}, totaling #{total_3}"
    puts "Round #{round} highest score is: #{winner}"
        if total_1> total_2 && total_3
            puts "#{@userName} is the winner!"
        elsif total_2 > total_1 && total_3
            puts "Computer 1 is the winner!"
        elsif total_3 > total_1 && total_2
            puts "Computer 2 is the winner!"
        else
            puts "It was a tie, there are no winners."
        end
    puts ""
end

def gameWinner(rounds)
    if total_1> total_2 && total_3
        roundWinner1 = 1
    elsif total_2 > total_1 && total_3
        roundWinner2 = 1
    else total_3 > total_1 && total_2
        roundWinner3 = 1
    end

    gameSummary1 = roundWinner1 + roundWinner1 + roundWinner1
    gameSummary2 = roundWinner2 + roundWinner2 + roundWinner2
    gameSummary3 = roundWinner3 + roundWinner3 + roundWinner3
    winnerOA = [gameSummary1, gameSummary2, gameSummary3].max

    puts "The winner of the game is #{winnerOA}"
end

def playAgain
    puts "Would you like to start over? (Y/N)\n"
    answer = gets.chomp.upcase
    if answer == "Y"
        play
    elsif answer == "N"
        puts "Thank you for playing.\n"
    else
        playAgain
    end
  end

def play
    welcome
    round(1)
    round_1 = round(1)
    round(2)
    round(3)
    gameWinner
    playAgain
end

play
</code>```

I've expected the program to report the overall winner, but I'm just blanking on how to grab it.

Here is the error thrown by the gameWinner function:

Traceback (most recent call last): 2: from rollEm2.rb:83:in ' 1: from rollEm2.rb:79:in play' rollEm2.rb:44:in `gameWinner': wrong number of arguments (given 0, expected 1) (ArgumentError)

答:
Here's a more Ruby-like way to think of the problem, using a Player class. Note that the numbers of players and rounds are not fixed. I have omitted prompts to ask players to roll the dice. If the first two lines of the definition of the class are head-scratchers, not to worry--see the explanation at the end of the answer.

```<code>class Player
  @players = []
  singleton_class.send(:attr_reader, :players)

  attr_reader :name, :cum_score

  def initialize(name)
     @name = name
     @cum_score = 0
     self.class.players << self
  end

  def blow_on_dice
    # Come to papa!
  end

  def throw
    score = rand(1..6) + rand(1..6)
    @cum_score += score
    score
  end
end
</code>```

```<code>def show_winners(scores)
  max_score = scores.values.max
  winners = scores.select { |_,v| v == max_score }.keys
  if winners.size == 1
    puts "Winner with a score of #{max_score} is #{winners.first}"
  else
    print "Winners of round with a score of #{max_score} are "
    winners.each_with_index do |name,i|
      print name
      print case i
            when winners.size-1 then ''
            when winners.size-2 then ' and '
            else                ', '
            end
    end
    puts
  end
end
</code>```

```<code>Player.new('Cary')
  #=> #<Player:0x000059a79738b768 @name="Cary", @cum_score=0>
Player.new('Hal')
  #=> #<Player:0x000059a7973d7690 @name="Hal", @cum_score=0>
Player.new('Deep Thought')
  #=> #<Player:0x000059a79756f318 @name="Deep Thought", @cum_score
nbr_rounds = 3
</code>```

```<code>players = Player.players
  #=> [#<Player:0x000059a79738b768 @name="Cary", @cum_score=0>,
  #    #<Player:0x000059a7973d7690 @name="Hal", @cum_score=0>,
  #    #<Player:0x000059a79756f318 @name="Deep Thought", @cum_score=0>]

(1..nbr_rounds).each do |round|
  puts "\nResults for round #{round}"
  scores = players.each_with_object({}) do |p,h|
    p.blow_on_dice
    score = p.throw
    puts "#{p.name} throws #{score}"
    h[p.name] = score
  end
  show_winners(scores)
end
</code>```

```<code>Results for round 1
Cary throws 8
Hal throws 9
Deep Thought throws 9
Winners of round with a score of 9 are Hal and Deep Thought
</code>```

```<code>Results for round 2
Cary throws 7
Hal throws 9
Deep Thought throws 9
Winners of round with a score of 9 are Hal and Deep Thought
</code>```

```<code>Results for round 3
Cary throws 7
Hal throws 11
Deep Thought throws 6
Winner with a score of 11 is Hal
</code>```

```<code>puts "\nResults for all rounds"
scores = players.each_with_object({}) do |p,h|
  h[p.name] = p.cum_score
  puts "#{p.name} had a total score of #{p.cum_score}"
end
</code>```

```<code>Results for all rounds
Cary had a total score of 22
Hal had a total score of 29
Deep Thought had a total score of 24
</code>```

```<code>show_winners(scores)
</code>```

```<code>Winner with a score of 29 is Hal
</code>```

If the line

```<code>puts "scores = #{scores}"
</code>```

is inserted before the first line in show_winners, the following is displayed for the three each-round calculations:

```<code>scores = {"Cary"=>7, "Hal"=>5, "Deep Thought"=>7}
scores = {"Cary"=>4, "Hal"=>7, "Deep Thought"=>3}
scores = {"Cary"=>10, "Hal"=>11, "Deep Thought"=>8}
</code>```

For the totals calculation the following is displayed:

```<code>scores = {"Cary"=>21, "Hal"=>23, "Deep Thought"=>18}
</code>```

Note that @players is an instance_variable for the class (as opposed to instances of the class). The line singleton_class.send(:attr_reader, :players) creates a getter for that variable, allowing us to write Player.players to obtain an array of the instances of Players that have been created. One of several alternatives to that line is the following:

```<code>class << self
  attr_reader :players
end
</code>```

Alternatively, the collection of instances of Players that have been created would be maintained outside the class, but that is prone to error (if, for example, a player is later added):

```<code>players = [Player.new('Cary'), Player.new('Hal'), Player.new('Deep Thought')]
</code>```

Were that done the class definition would be simplified to the following.

```<code>class Player
  attr_reader :name, :cum_score

  def initialize(name)
     @name = name
     @cum_score = 0
  end

  def throw
    ...
  end
end
</code>```

This design, however, prone to error (if, for example, a player were later added) and players were not updated.

Body:
We have an assignment to determine the ultimately winner in a dice game. Here's the complete rules:

You will be pitted against two other computer players in this game. There are three rounds. At the beginning of each round a player rolls two dice. The total of your dice roll for that round is added to your points. Your points always start at zero. Each consecutive round the points are added to the total. At the end of the third round, whoever has the most points wins the game.

REQUIREMENTS
————————
Each player has two dice
The player rolls each die once per round
Display each players score at the end of each round
Display the leader of the round at the end of each round
Prompt the user to roll to begin the next around
After three rounds the game is over
The players score persists until the end of the game
Once the game ends, a winner is declared
Once a winner is declared you have the option to restart or quit

I've gotten everything to work, except how to determine the ultimate winner of the game. I've tried making a new method called "gameWinner", using if/elsif statements, grabbing the total scores from each round and adding each up respectively. However, the program breaks once it reaches that. I can't think of how else to solve this problems, but nothing I type seems to function right.

def welcome
    puts ""
    puts "Let's roll some die! You will be competing against 2 computers in 3 rounds, each player having 2 die."
    puts "Please enter your name and press 'Enter'"
    puts ""
    @userName = gets.chomp
    puts ("Welcome, " + @userName + ". Let's roll those die!")
    puts ""
end

def round(round)
    result_1 = Random.new.rand(1..6)
    result_2 = Random.new.rand(1..6)
    total_1 = result_1 + result_2

    result_3 = Random.new.rand(1..6)
    result_4 = Random.new.rand(1..6)
    total_2 = result_3 + result_4

    result_5 = Random.new.rand(1..6)
    result_6 = Random.new.rand(1..6)
    total_3 = result_5 + result_6

    winner = [total_1, total_2, total_3].max
    players = {total_1 => @userName, total_2 => "Computer 1", total_3 => "Computer 2"}.max

    puts "Round #{round}"
    puts "#{@userName}, your die are a #{result_1} and a #{result_2}, totaling #{total_1}"
    puts "Computer 1's die are a #{result_3} and a #{result_4}, totaling #{total_2}"
    puts "Computer 2's die are a #{result_5} and a #{result_6}, totaling #{total_3}"
    puts "Round #{round} highest score is: #{winner}"
        if total_1> total_2 && total_3
            puts "#{@userName} is the winner!"
        elsif total_2 > total_1 && total_3
            puts "Computer 1 is the winner!"
        elsif total_3 > total_1 && total_2
            puts "Computer 2 is the winner!"
        else
            puts "It was a tie, there are no winners."
        end
    puts ""
end

def gameWinner(rounds)
    if total_1> total_2 && total_3
        roundWinner1 = 1
    elsif total_2 > total_1 && total_3
        roundWinner2 = 1
    else total_3 > total_1 && total_2
        roundWinner3 = 1
    end

    gameSummary1 = roundWinner1 + roundWinner1 + roundWinner1
    gameSummary2 = roundWinner2 + roundWinner2 + roundWinner2
    gameSummary3 = roundWinner3 + roundWinner3 + roundWinner3
    winnerOA = [gameSummary1, gameSummary2, gameSummary3].max

    puts "The winner of the game is #{winnerOA}"
end

def playAgain
    puts "Would you like to start over? (Y/N)\n"
    answer = gets.chomp.upcase
    if answer == "Y"
        play
    elsif answer == "N"
        puts "Thank you for playing.\n"
    else
        playAgain
    end
  end

def play
    welcome
    round(1)
    round_1 = round(1)
    round(2)
    round(3)
    gameWinner
    playAgain
end

play

I've expected the program to report the overall winner, but I'm just blanking on how to grab it.

Here is the error thrown by the gameWinner function:

Traceback (most recent call last): 2: from rollEm2.rb:83:in ' 1: from rollEm2.rb:79:in play' rollEm2.rb:44:in `gameWinner': wrong number of arguments (given 0, expected 1) (ArgumentError)

Body:
Here's a more Ruby-like way to think of the problem, using a Player class. Note that the numbers of players and rounds are not fixed. I have omitted prompts to ask players to roll the dice. If the first two lines of the definition of the class are head-scratchers, not to worry--see the explanation at the end of the answer.

class Player
  @players = []
  singleton_class.send(:attr_reader, :players)

  attr_reader :name, :cum_score

  def initialize(name)
     @name = name
     @cum_score = 0
     self.class.players << self
  end

  def blow_on_dice
    # Come to papa!
  end

  def throw
    score = rand(1..6) + rand(1..6)
    @cum_score += score
    score
  end
end

def show_winners(scores)
  max_score = scores.values.max
  winners = scores.select { |_,v| v == max_score }.keys
  if winners.size == 1
    puts "Winner with a score of #{max_score} is #{winners.first}"
  else
    print "Winners of round with a score of #{max_score} are "
    winners.each_with_index do |name,i|
      print name
      print case i
            when winners.size-1 then ''
            when winners.size-2 then ' and '
            else                ', '
            end
    end
    puts
  end
end

Player.new('Cary')
  #=> #<Player:0x000059a79738b768 @name="Cary", @cum_score=0>
Player.new('Hal')
  #=> #<Player:0x000059a7973d7690 @name="Hal", @cum_score=0>
Player.new('Deep Thought')
  #=> #<Player:0x000059a79756f318 @name="Deep Thought", @cum_score
nbr_rounds = 3

players = Player.players
  #=> [#<Player:0x000059a79738b768 @name="Cary", @cum_score=0>,
  #    #<Player:0x000059a7973d7690 @name="Hal", @cum_score=0>,
  #    #<Player:0x000059a79756f318 @name="Deep Thought", @cum_score=0>]

(1..nbr_rounds).each do |round|
  puts "\nResults for round #{round}"
  scores = players.each_with_object({}) do |p,h|
    p.blow_on_dice
    score = p.throw
    puts "#{p.name} throws #{score}"
    h[p.name] = score
  end
  show_winners(scores)
end

Results for round 1
Cary throws 8
Hal throws 9
Deep Thought throws 9
Winners of round with a score of 9 are Hal and Deep Thought

Results for round 2
Cary throws 7
Hal throws 9
Deep Thought throws 9
Winners of round with a score of 9 are Hal and Deep Thought

Results for round 3
Cary throws 7
Hal throws 11
Deep Thought throws 6
Winner with a score of 11 is Hal

puts "\nResults for all rounds"
scores = players.each_with_object({}) do |p,h|
  h[p.name] = p.cum_score
  puts "#{p.name} had a total score of #{p.cum_score}"
end

Results for all rounds
Cary had a total score of 22
Hal had a total score of 29
Deep Thought had a total score of 24

show_winners(scores)

Winner with a score of 29 is Hal

If the line

puts "scores = #{scores}"

is inserted before the first line in show_winners, the following is displayed for the three each-round calculations:

scores = {"Cary"=>7, "Hal"=>5, "Deep Thought"=>7}
scores = {"Cary"=>4, "Hal"=>7, "Deep Thought"=>3}
scores = {"Cary"=>10, "Hal"=>11, "Deep Thought"=>8}

For the totals calculation the following is displayed:

scores = {"Cary"=>21, "Hal"=>23, "Deep Thought"=>18}

Note that @players is an instance_variable for the class (as opposed to instances of the class). The line singleton_class.send(:attr_reader, :players) creates a getter for that variable, allowing us to write Player.players to obtain an array of the instances of Players that have been created. One of several alternatives to that line is the following:

class << self
  attr_reader :players
end

Alternatively, the collection of instances of Players that have been created would be maintained outside the class, but that is prone to error (if, for example, a player is later added):

players = [Player.new('Cary'), Player.new('Hal'), Player.new('Deep Thought')]

Were that done the class definition would be simplified to the following.

class Player
  attr_reader :name, :cum_score

  def initialize(name)
     @name = name
     @cum_score = 0
  end

  def throw
    ...
  end
end

This design, however, prone to error (if, for example, a player were later added) and players were not updated.


问:
How to push and consume a message from Spring boot to standalone JBoss Wildfly 10 Artemis Activemq?
I have written a Spring Boot application which aims to push and consume a message from JBoss Wildfly 10 ActiveMQ Artemis (NOTE: not Apache ActiveMQ 5.x). I am running this code through Spring Tool Suite.

I have also setup JBoss Wildfly 10 on my local system (on 8080 port) and have run the same in standalone-full.xml profile in order to create a queue called TestQ in the messaging subsystems of Wildfly.

Next I used JMSTemplate in the Spring Boot code for pushing and consuming the message in the above mentioned queue with the following things in application.properties:

```<code>spring.activemq.username=admin
spring.activemq.username=admin
spring.activemq.broker-url=http://localhost:8080
</code>```

However, I am getting Could not send message error while running my code.

Can you please suggest what changes would be required?

My basic aim is to push and consume message from this external queue using Spring Boot.

I have tried alternatives on the net, but every example I get is for Apache ActiveMQ and not ActiveMQ Artemis embedded into JBoss Wildfly which is required.

I have the below 2 classes:

1.

@SpringBootApplication
@EnableJms
public class App  {

    @Bean
    public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    public static void main(String[] args) {
        // Launch the application
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);

        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);

        System.out.println("Sending a JMS message.");
        jmsTemplate.convertAndSend("sampleQueue", "Hello world!");
    }
}
```

<p>2.</p>

<pre class="lang-java prettyprint-override"><code>@Component
public class ReceiveMessage {

    @JmsListener(destination = "sampleQueue")
    public void receiveMessage(String msg) {
        System.out.println("Received :" + msg);
    }
}
</code>```

答:
It looks to me like the properties in application.properties are for an ActiveMQ 5.x client rather than an ActiveMQ Artemis client. As the Spring Boot documentation says:

Artemis configuration is controlled by external configuration properties in spring.artemis.*.

Also, you should to expose a port on Wildfly directly to the ActiveMQ Artemis broker rather than using the consolidated port 8080 as this requires httpUpgradeEnabled to be set to true on the Artemis client's URL and there is no way to do that using the Spring Boot integration for some reason.

Body:
I have written a Spring Boot application which aims to push and consume a message from JBoss Wildfly 10 ActiveMQ Artemis (NOTE: not Apache ActiveMQ 5.x). I am running this code through Spring Tool Suite.

I have also setup JBoss Wildfly 10 on my local system (on 8080 port) and have run the same in standalone-full.xml profile in order to create a queue called TestQ in the messaging subsystems of Wildfly.

Next I used JMSTemplate in the Spring Boot code for pushing and consuming the message in the above mentioned queue with the following things in application.properties:

spring.activemq.username=admin
spring.activemq.username=admin
spring.activemq.broker-url=http://localhost:8080

However, I am getting Could not send message error while running my code.

Can you please suggest what changes would be required?

My basic aim is to push and consume message from this external queue using Spring Boot.

I have tried alternatives on the net, but every example I get is for Apache ActiveMQ and not ActiveMQ Artemis embedded into JBoss Wildfly which is required.

I have the below 2 classes:

1.

@SpringBootApplication
@EnableJms
public class App  {

    @Bean
    public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
                                                    DefaultJmsListenerContainerFactoryConfigurer configurer) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        return factory;
    }

    public static void main(String[] args) {
        // Launch the application
        ConfigurableApplicationContext context = SpringApplication.run(App.class, args);

        JmsTemplate jmsTemplate = context.getBean(JmsTemplate.class);

        System.out.println("Sending a JMS message.");
        jmsTemplate.convertAndSend("sampleQueue", "Hello world!");
    }
}

2.

@Component
public class ReceiveMessage {

    @JmsListener(destination = "sampleQueue")
    public void receiveMessage(String msg) {
        System.out.println("Received :" + msg);
    }
}


问:
Can one create an Interactive web app with GAS?
Broken down to its most elemental, what I want to do from a web app context is:

Ask for some data from user.

Display some data to user.

Ask for some more data from user.

Use all that data in a web app.

More specifically, I am trying to build a Google Script web app that does the following:

Presents an html page where the user can input a user ID number.

Takes that number and finds the last line on a spreadsheet belonging
to that user.

Displays that last line number to the user (this is
the first point at which I am stumped—see below for what I have
tried).

Presents a 2nd html input page where the user can either
accept the last line info displayed to them, or enter an alternate
number (and some other info).

All of that info is then used to
create a Google Doc and add info about that Google Doc on a new row
in a Google spreadsheet.

I have tried:

(a) Class PromptResponse [ui.prompt]

 (b) alert(Prompt)

 (c) showModalDialog

 (d) show ModelessDialog

All of these failed as they apparently must be triggered from a bound app.

I considered the concept of having two doGet statements in a single webApp which led me to
Linking to another HTML page in Google Apps Script, but that seems to deal with a two-page SINGLE html rather than two separate html pages (which is what I think I need).

I also considered using the Browser.msgBox in the Class CacheService but that produced the same context error as (a) thru (d) above.

Lastly, I thought about—rather than displaying the user ID number from (1) above—saving the variable and inserting it later in the script (i.e., loading it in (4) above). That led me to the CacheService. But I could not see how to make that work and in any event, it’s not really what I want to do.

GS

```<code>function doGet() {
  return HtmlService
  .createTemplateFromFile('Index')
      .evaluate();
}
function getSongId(objArgs){
  // Get User's Catalog SS URL from Master Users List
  var userId = objArgs.user;
  var masterSSId = "ID";//This is the ID to the master users list SS.
  var userSS = SpreadsheetApp.openById(masterSSId);//Open
  var userSheet = userSS.getActiveSheet();
  var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
      Logger.log("nameOfUserRange = " + nameOfUserRange);
  var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
  var cell = userNamedRange.activate(); //activates range and first cell in range
  var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
  var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
      Logger.log("userCol = " + userCol);
  var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
      Logger.log("userSsUrl = " + userSsUrl);
  var ss = SpreadsheetApp.openByUrl(userSsUrl);
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var songId = lastRow+1;
  Logger.log("songId = " + songId);
  //some code here that displays songID to user
</code>```

HTML "Index"

```<code><!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
<center>    Enter your User ID below.
    <input id="userId" type="text" placeholder="User ID"><br><br>
    <button onclick="saveUserInput()">Continue</button>
    </center>

    <script>
      window.saveUserInput = function() {
        var user = document.getElementById('userId').value;

        console.log('userId: ' + userId)

        google.script.run

          .withSuccessHandler(openPrompt)
          .getSongId({user:user})

      }

       function openPrompt(results){
           window.open(results.url, '_blank').focus();
       }
    </script>
  </body>
</html>
</code>```

songId Code

```<code>function getSongId() {
    var masterSSId = "ID";//This is the ID to the master users list SS.
    var userSS = SpreadsheetApp.openById(masterSSId);//Open
    var userSheet = userSS.getActiveSheet();
    var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
    var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
    var cell = userNamedRange.activate(); //activates range and first cell in range
    var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
    var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
    var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
    var ss = SpreadsheetApp.openByUrl(userSsUrl);
    var sheet = ss.getActiveSheet();
    var lastRow = sheet.getLastRow();
    var songId = lastRow+1;
}
</code>```

As noted, I got "context" errors with everything I tried. BTW, I also created a web app that had 2 GS pages and 2 Index pages, and that just displayed both html pages on one page, and I still couldn't figure out how to display the User ID.

Finally, I spent a lot of hours, and used a lot of search terms, both at SO and the web in general trying to find someone else that has tackled this problem—and came up goose eggs.

Note: To respect "minimal, and verifiable," I have not included the script that asks for the 2nd set of info, but it is written and works.

Update: The following SO Question/Answer showed up to the right of this question: "Web apps+ remotely using script" after I posted it

It seems to in part solve my problem. At least it does display the user's User ID input, but I need it to display info I pull from a Google sheet based on the User ID (i.e., the songId). Using the doGet(e) approach, I still don't know where to put the getSongIdcode that gets the songId. I have added that code above.

Revised Code

gs

```<code>function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function getSongId(uObj) {
  var userId = uObj.user;
  var masterSSId = "ID";//This is the ID to the master users list SS.
  var userSS = SpreadsheetApp.openById(masterSSId);//Open
  var userSheet = userSS.getActiveSheet();
  var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
    Logger.log("nameOfUserRange = " + nameOfUserRange);
  var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
  var cell = userNamedRange.activate(); //activates range and first cell in range
  var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
  var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
  var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
  var ss = SpreadsheetApp.openByUrl(userSsUrl);
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var songId = lastRow+1;
    Logger.log("songId = " + songId);
  return songId;
}
</code>```

html

```<code><!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
  <center>
Enter your User ID below.
<input id="userId" type="text" placeholder="User ID"><br>
<input type="button" value="Continue" onclick="saveUserInput()">
<div  id="results"></div>
</center>
<script>
      function saveUserInput() {
        var user = document.getElementById('userId').value;
        google.script.run
          .withSuccessHandler(function(hl){
            document.getElementById('results').innerHTML=hl;
          })
          .getSongId({user:user})
        }

    </script>
  </body>
</html>
</code>```

答:
Try something simple first.  Just to see that you can get the client and the server communicating:

html:

```<code><!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
Enter your User ID below.
<input id="userId" type="text" placeholder="User ID"><br>
<input type="button" value="Continue" onclick="saveUserInput()">
<div  id="results"></div>
<script>
      function saveUserInput() {
        var user = document.getElementById('userId').value;
        google.script.run
          .withSuccessHandler(function(hl){
            document.getElementById('results').innerHTML=hl;
          })
          .getSongId({user:user})
        }

    </script>
  </body>
</html>
</code>```

Then use a simple getSongId() function:

```<code>function getSongId(uObj) {
  return uObj.user
}
</code>```

I would use this sort of doGet()

```<code>function doGet() {return HtmlService.createHtmlOutputFromFile('Index');
}
</code>```

You html doesn't have any scriptlets that need to be evaluated.  It's not really a template.

Then test the getSongId by itself and once that works you can return it to the div and later if you wish you can create another page.

Body:
Broken down to its most elemental, what I want to do from a web app context is:

Ask for some data from user.

Display some data to user.

Ask for some more data from user.

Use all that data in a web app.

More specifically, I am trying to build a Google Script web app that does the following:

Presents an html page where the user can input a user ID number.

Takes that number and finds the last line on a spreadsheet belonging
to that user.

Displays that last line number to the user (this is
the first point at which I am stumped—see below for what I have
tried).

Presents a 2nd html input page where the user can either
accept the last line info displayed to them, or enter an alternate
number (and some other info).

All of that info is then used to
create a Google Doc and add info about that Google Doc on a new row
in a Google spreadsheet.

I have tried:

(a) Class PromptResponse [ui.prompt]

 (b) alert(Prompt)

 (c) showModalDialog

 (d) show ModelessDialog

All of these failed as they apparently must be triggered from a bound app.

I considered the concept of having two doGet statements in a single webApp which led me to
Linking to another HTML page in Google Apps Script, but that seems to deal with a two-page SINGLE html rather than two separate html pages (which is what I think I need).

I also considered using the Browser.msgBox in the Class CacheService but that produced the same context error as (a) thru (d) above.

Lastly, I thought about—rather than displaying the user ID number from (1) above—saving the variable and inserting it later in the script (i.e., loading it in (4) above). That led me to the CacheService. But I could not see how to make that work and in any event, it’s not really what I want to do.

GS

function doGet() {
  return HtmlService
  .createTemplateFromFile('Index')
      .evaluate();
}
function getSongId(objArgs){
  // Get User's Catalog SS URL from Master Users List
  var userId = objArgs.user;
  var masterSSId = "ID";//This is the ID to the master users list SS.
  var userSS = SpreadsheetApp.openById(masterSSId);//Open
  var userSheet = userSS.getActiveSheet();
  var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
      Logger.log("nameOfUserRange = " + nameOfUserRange);
  var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
  var cell = userNamedRange.activate(); //activates range and first cell in range
  var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
  var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
      Logger.log("userCol = " + userCol);
  var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
      Logger.log("userSsUrl = " + userSsUrl);
  var ss = SpreadsheetApp.openByUrl(userSsUrl);
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var songId = lastRow+1;
  Logger.log("songId = " + songId);
  //some code here that displays songID to user

HTML "Index"

<!DOCTYPE html>

    <base target="_top">

    Enter your User ID below.
    <input id="userId" type="text" placeholder="User ID">

    <button onclick="saveUserInput()">Continue</button>

songId Code

function getSongId() {
    var masterSSId = "ID";//This is the ID to the master users list SS.
    var userSS = SpreadsheetApp.openById(masterSSId);//Open
    var userSheet = userSS.getActiveSheet();
    var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
    var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
    var cell = userNamedRange.activate(); //activates range and first cell in range
    var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
    var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
    var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
    var ss = SpreadsheetApp.openByUrl(userSsUrl);
    var sheet = ss.getActiveSheet();
    var lastRow = sheet.getLastRow();
    var songId = lastRow+1;
}

As noted, I got "context" errors with everything I tried. BTW, I also created a web app that had 2 GS pages and 2 Index pages, and that just displayed both html pages on one page, and I still couldn't figure out how to display the User ID.

Finally, I spent a lot of hours, and used a lot of search terms, both at SO and the web in general trying to find someone else that has tackled this problem—and came up goose eggs.

Note: To respect "minimal, and verifiable," I have not included the script that asks for the 2nd set of info, but it is written and works.

Update: The following SO Question/Answer showed up to the right of this question: "Web apps+ remotely using script" after I posted it

It seems to in part solve my problem. At least it does display the user's User ID input, but I need it to display info I pull from a Google sheet based on the User ID (i.e., the songId). Using the doGet(e) approach, I still don't know where to put the getSongIdcode that gets the songId. I have added that code above.

Revised Code

gs

function doGet() {
  return HtmlService.createHtmlOutputFromFile('Index');
}

function getSongId(uObj) {
  var userId = uObj.user;
  var masterSSId = "ID";//This is the ID to the master users list SS.
  var userSS = SpreadsheetApp.openById(masterSSId);//Open
  var userSheet = userSS.getActiveSheet();
  var nameOfUserRange = "User" + userId; //this constructs the user ID, like "user101"
    Logger.log("nameOfUserRange = " + nameOfUserRange);
  var userNamedRange = userSS.getRangeByName(nameOfUserRange); //this returns "Range" to pass its value on to future code lines
  var cell = userNamedRange.activate(); //activates range and first cell in range
  var namedUrlRange = userSS.getRange('SongsSheetUrl'); //this gets the SongSheetUrl named range
  var userCol = namedUrlRange.getColumn(); //this gets col # of namedUrlRange
  var userSsUrl = cell.offset(0, userCol-1, 1, 1). getValue(); //this gets the user's Catalog SS URL
  var ss = SpreadsheetApp.openByUrl(userSsUrl);
  var sheet = ss.getActiveSheet();
  var lastRow = sheet.getLastRow();
  var songId = lastRow+1;
    Logger.log("songId = " + songId);
  return songId;
}

html

<!DOCTYPE html>

    <base target="_top">

Enter your User ID below.
<input id="userId" type="text" placeholder="User ID">

<input type="button" value="Continue" onclick="saveUserInput()">

Body:
Try something simple first.  Just to see that you can get the client and the server communicating:

html:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
  </head>
  <body>
Enter your User ID below.
<input id="userId" type="text" placeholder="User ID"><br>
<input type="button" value="Continue" onclick="saveUserInput()">
<div  id="results"></div>
<script>
      function saveUserInput() {
        var user = document.getElementById('userId').value;
        google.script.run
          .withSuccessHandler(function(hl){
            document.getElementById('results').innerHTML=hl;
          })
          .getSongId({user:user})
        }

    </script>
  </body>
</html>

Then use a simple getSongId() function:

function getSongId(uObj) {
  return uObj.user
}

I would use this sort of doGet()

function doGet() {return HtmlService.createHtmlOutputFromFile('Index');
}

You html doesn't have any scriptlets that need to be evaluated.  It's not really a template.

Then test the getSongId by itself and once that works you can return it to the div and later if you wish you can create another page.


问:
How do I display a single item using a DataTemplate in Silverlight?
I am trying to display a single item (not contained in a collection) using a DataTemplate. Here's what I've got so far, which is displaying nothing. Replacing ItemsControl with ListBox displays an empty listbox (so I know the element is there).

```<code>        <ItemsControl
            ItemsSource="{Binding Session}"
            ItemTemplate="{StaticResource SessionHeaderDataTemplate}"
            />
</code>```

Session is a single object. I want to use a DataTemplate because I am displaying the same information elsewhere in my app and wanted the presentation style defined as a resource so I can update it in one place.

Any ideas, or should I create a 1-element collection in my ViewModel and bind to that?

Edit: This is what I ended up doing, although the answer below is also a solution. I'm quite attached to my DataTemplates so didnt feel comfortable having something like this pushed out to another XAML file.

XAML:

```<code>        <ItemsControl
            DataContext="{Binding}"
            ItemsSource="{Binding Session_ListSource}"
            ItemTemplate="{StaticResource SessionHeaderDataTemplate}" />
</code>```

ViewModel:

```<code>    private Session m_Session;
    public Session Session
    {
        get { return m_Session; }
        set
        {
            if (m_Session != value)
            {
                m_Session = value;
                OnPropertyChanged("Session");

                // Added these two lines
                Session_ListSource.Clear();
                Session_ListSource.Add(this.Session);
            }
        }
    }

    // Added this property.
    private ObservableCollection<Session> m_Session_ListSource = new ObservableCollection<Session>();
    public ObservableCollection<Session> Session_ListSource
    {
        get { return m_Session_ListSource; }
        set
        {
            if (m_Session_ListSource != value)
            {
                m_Session_ListSource = value;
                OnPropertyChanged("Session_ListSource");
            }
        }
    }
</code>```

答:
You don't need to use an ItemsControl to do that, just create a custom user control, then bind to that, e.g.

```<code><TestProject:myControl DataContext="{Binding Session}" />
</code>```

The custom control can have it's own xaml file so it can look however you want it to.

OwnerDisplayName: geofftnz

ContentLicense: CC BY-SA 2.5

Body:
I am trying to display a single item (not contained in a collection) using a DataTemplate. Here's what I've got so far, which is displaying nothing. Replacing ItemsControl with ListBox displays an empty listbox (so I know the element is there).

        <ItemsControl
            ItemsSource="{Binding Session}"
            ItemTemplate="{StaticResource SessionHeaderDataTemplate}"
            />

Session is a single object. I want to use a DataTemplate because I am displaying the same information elsewhere in my app and wanted the presentation style defined as a resource so I can update it in one place.

Any ideas, or should I create a 1-element collection in my ViewModel and bind to that?

Edit: This is what I ended up doing, although the answer below is also a solution. I'm quite attached to my DataTemplates so didnt feel comfortable having something like this pushed out to another XAML file.

XAML:

        <ItemsControl
            DataContext="{Binding}"
            ItemsSource="{Binding Session_ListSource}"
            ItemTemplate="{StaticResource SessionHeaderDataTemplate}" />

ViewModel:

    private Session m_Session;
    public Session Session
    {
        get { return m_Session; }
        set
        {
            if (m_Session != value)
            {
                m_Session = value;
                OnPropertyChanged("Session");

                // Added these two lines
                Session_ListSource.Clear();
                Session_ListSource.Add(this.Session);
            }
        }
    }

    // Added this property.
    private ObservableCollection<Session> m_Session_ListSource = new ObservableCollection<Session>();
    public ObservableCollection<Session> Session_ListSource
    {
        get { return m_Session_ListSource; }
        set
        {
            if (m_Session_ListSource != value)
            {
                m_Session_ListSource = value;
                OnPropertyChanged("Session_ListSource");
            }
        }
    }

LastEditorDisplayName: geofftnz

Body:
You don't need to use an ItemsControl to do that, just create a custom user control, then bind to that, e.g.

<TestProject:myControl DataContext="{Binding Session}" />

The custom control can have it's own xaml file so it can look however you want it to.


问:
How to prevent the user from repetitively inputting same number
I am creating a program in java where the user has to guess a random number generated by the computer, The user gets 20 tries in total to guess the number,if the user enters the same number repeatedly it should show an error message and no count as one of their guesses but am unsure how to do this. For example if the users first guess is 5 and they guess 5 again an error message should appear saying "You have already entered this number </p>

```<code>package guessinggame2;
import java.util.Scanner;

public class GuessingGame2 {

  static Scanner kboard = new Scanner(System.in);

  public static void main(String args[]) // start of main
  {
    System.out.println("Welcome to the guessing game, the computer will
    generate a random number that you have to guess, good luck!");

    int secret_number = 0;
    int number_of_guesses = 0;
    Scanner input = new Scanner(System.in);
    int user_guess;
    int used_number = 0;

    secret_number = (int)(Math.random()*100) + 1;
    System.out.println("The computer has generated it's number");

    for(int i=0; i<20;i++) {

      System.out.println("Please make your guess");
      user_guess = kboard.nextInt();
      number_of_guesses++;

      if (user_guess == secret_number)
      {
        System.out.println("Your guess is correct it took you " +
        number_of_guesses + " guesses");
      }

      else if  (user_guess < secret_number)
      {
        System.out.println("Your guess is too low try again");
      }

      else if (user_guess > secret_number)
      {
        System.out.println("Your guess is too high try again");
      }

      System.out.println (20 - number_of_guesses + " Guesses remaining");
    }
  }
}
</code>```

答:
The keyword to research: arrays.

Simply store all numbers from your user into such an array. Then you can iterate that array each time when a new number is given. When you find that number in that array you can print the error message.

Alternatively, you can use a HashSet to store previously entered numbers. Sets have a nice method contains() which avoids the repeated looping of an array. But the collection classes such as HashSet are a bit advanced, and the normal practice for newbies would be a solution based on arrays.

Body:
I am creating a program in java where the user has to guess a random number generated by the computer, The user gets 20 tries in total to guess the number,if the user enters the same number repeatedly it should show an error message and no count as one of their guesses but am unsure how to do this. For example if the users first guess is 5 and they guess 5 again an error message should appear saying "You have already entered this number

package guessinggame2;
import java.util.Scanner;

public class GuessingGame2 {

  static Scanner kboard = new Scanner(System.in);

  public static void main(String args[]) // start of main
  {
    System.out.println("Welcome to the guessing game, the computer will
    generate a random number that you have to guess, good luck!");

    int secret_number = 0;
    int number_of_guesses = 0;
    Scanner input = new Scanner(System.in);
    int user_guess;
    int used_number = 0;

    secret_number = (int)(Math.random()*100) + 1;
    System.out.println("The computer has generated it's number");

    for(int i=0; i<20;i++) {

      System.out.println("Please make your guess");
      user_guess = kboard.nextInt();
      number_of_guesses++;

      if (user_guess == secret_number)
      {
        System.out.println("Your guess is correct it took you " +
        number_of_guesses + " guesses");
      }

      else if  (user_guess < secret_number)
      {
        System.out.println("Your guess is too low try again");
      }

      else if (user_guess > secret_number)
      {
        System.out.println("Your guess is too high try again");
      }

      System.out.println (20 - number_of_guesses + " Guesses remaining");
    }
  }
}


问:
How do I access outer column in subquery in kusto / Azure application insights?
I am trying to simply run a subquery in Azure application insights, using Kusto, so that I can get some information from two tables displayed as one.

The query I'm trying is

```<code>table1
| extend progressLog = toscalar(
    table2
    | where common_Id == table1.common_Id // errors saying Ensure that expression: table1.common_Id is indeed a simple name
    | summarize makelist(stringColumn)
)
</code>```

I have attempted to alias this id, and even join the two tables, as such:

```<code>requests
| extend aliased_id = common_Id
| join traces on operation_Id, $left.operation_Id == $right.operation_Id
| extend test_id = operation_Id
| extend progressLog = toscalar(
    traces
    | where operation_Id == aliased_id // Failed to resolve column or scalar expression named 'aliased_id'
    | summarize makelist(message)
)
</code>```

Failed to resolve column or scalar expression named 'aliased_id'.

I am simply trying to do the equivalent of the T-SQL query:

```<code>SELECT
    ... ,
    STRING_AGG(table2.stringColumn, ',')
FROM
    table1
INNER JOIN
    table2
    ON table1.common_Id = table2.common_Id
GROUP BY
    table.<props>
</code>```

My main question is - how do I reference "common_Id" in the kusto language inside a subquery

答:
Please see if the next query provides what you're looking for. If not, please share sample input using datatable, as I did below, and expected output: </p>

```<code>let requests = datatable(common_Id:string, operation_Id:string)
[
    "A", "X",
    "B", "Y",
    "C", "Z"
];
let traces = datatable(operation_Id:string, message:string)
[
    "X", "m1",
    "X", "m2",
    "Y", "m3"
];
let messagesByOperationId = traces | summarize makelist(message) by operation_Id;
requests
| join kind=leftouter messagesByOperationId on operation_Id
| project common_Id, operation_Id, progressLog = list_message
</code>```

Body:
I am trying to simply run a subquery in Azure application insights, using Kusto, so that I can get some information from two tables displayed as one.

The query I'm trying is

table1
| extend progressLog = toscalar(
    table2
    | where common_Id == table1.common_Id // errors saying Ensure that expression: table1.common_Id is indeed a simple name
    | summarize makelist(stringColumn)
)

I have attempted to alias this id, and even join the two tables, as such:

requests
| extend aliased_id = common_Id
| join traces on operation_Id, $left.operation_Id == $right.operation_Id
| extend test_id = operation_Id
| extend progressLog = toscalar(
    traces
    | where operation_Id == aliased_id // Failed to resolve column or scalar expression named 'aliased_id'
    | summarize makelist(message)
)

Failed to resolve column or scalar expression named 'aliased_id'.

I am simply trying to do the equivalent of the T-SQL query:

SELECT
    ... ,
    STRING_AGG(table2.stringColumn, ',')
FROM
    table1
INNER JOIN
    table2
    ON table1.common_Id = table2.common_Id
GROUP BY
    table.<props>

My main question is - how do I reference "common_Id" in the kusto language inside a subquery

Body:
Please see if the next query provides what you're looking for. If not, please share sample input using datatable, as I did below, and expected output:

let requests = datatable(common_Id:string, operation_Id:string)
[
    "A", "X",
    "B", "Y",
    "C", "Z"
];
let traces = datatable(operation_Id:string, message:string)
[
    "X", "m1",
    "X", "m2",
    "Y", "m3"
];
let messagesByOperationId = traces | summarize makelist(message) by operation_Id;
requests
| join kind=leftouter messagesByOperationId on operation_Id
| project common_Id, operation_Id, progressLog = list_message


问:
get trace ID of sent request
I'm using the Open Tracing Python library for GRPC and am trying to build off of the example script here: https://github.com/opentracing-contrib/python-grpc/blob/master/examples/trivial/trivial_client.py.

Once I have sent a request through the intercepted channel, how do I find the trace-id value for the request? I want to use this to look at the traced data in the Jaeger UI.

答: Correct me, if I'm wrong. If you mean how to find the trace-id on the server side, you can try to access the OpenTracing span by get_active_span. The trace-id, I suppose, should be one of the tags in it.</p>

Title: get trace ID of sent request


问:
How can I implement a promise in my calculator function?
I've written a calculator-like application in JavaScript, mainly so that it will run in any browser. It has a number of input fields. When I press the calculate button, it gathers data from these fields, calls various functions on it, and displays the result. There's no asynchronous stuff to do, no web or disc fetches that could delay or fail, the user triggers an event and then has to wait until the answer has been produced.

The fragment below is more or less a Hello World for this sort of process.

```<code><script type="text/javascript">
function transformer(instring)
{
    var outstring = instring + instring;
    return outstring;
}

function calculate()
{
    var srcStr = document.mainform.src.value;
    var transformed = transformer(srcStr);
    document.mainform.dst.value = transformed;
}
</script>

<form name="mainform">
Input data <input type="text" name="src" value="abc"/><br>
<button type="button" onclick="javascript:calculate();">Calculate</button><br>
Output data <input type="text" name="dst"  />
</form>
</code>```

I would like to replace the transformer() function with a function from a library that returns a promise. What's the minimum change in code I need to make to accomplish this. I've searched a lot for promises, async functions, thens etc, but not found a simple 'here is how to use a promise in a simple event driven program', and I have not yet managed to write a working equivalent of the program above. Once I have a working hello world, I can build from there.

Assume that the promise will always resolve, reject never needs to be handled. By 'minimum change', I don't necessarily mean fewest characters, but easiest to understand, or with fewest new concepts.

答:
Assuming that transformer returns a promise, that resolves with the transformed string:

```<code>function calculate() {
    var srcStr = document.mainform.src.value;
    transformer(srcStr).then(function (transformed) {
        document.mainform.dst.value = transformed;
    });
}
</code>```

Body:
I've written a calculator-like application in JavaScript, mainly so that it will run in any browser. It has a number of input fields. When I press the calculate button, it gathers data from these fields, calls various functions on it, and displays the result. There's no asynchronous stuff to do, no web or disc fetches that could delay or fail, the user triggers an event and then has to wait until the answer has been produced.

The fragment below is more or less a Hello World for this sort of process.

<form name="mainform">
Input data <input type="text" name="src" value="abc"/>

<button type="button" onclick="javascript:calculate();">Calculate</button>

Output data <input type="text" name="dst"  />
</form>

I would like to replace the transformer() function with a function from a library that returns a promise. What's the minimum change in code I need to make to accomplish this. I've searched a lot for promises, async functions, thens etc, but not found a simple 'here is how to use a promise in a simple event driven program', and I have not yet managed to write a working equivalent of the program above. Once I have a working hello world, I can build from there.

Assume that the promise will always resolve, reject never needs to be handled. By 'minimum change', I don't necessarily mean fewest characters, but easiest to understand, or with fewest new concepts.

Body:
Assuming that transformer returns a promise, that resolves with the transformed string:

function calculate() {
    var srcStr = document.mainform.src.value;
    transformer(srcStr).then(function (transformed) {
        document.mainform.dst.value = transformed;
    });
}


问:
Dynamically Copy Range of Cells from Closed Workbook?
I would like to copy a range of cells in a closed notebook that does not have a static set of rows. I would like to copy it into an active workbook.

I am trying to dynamically copy all entries under the column of F from file 'test.xlsx' from the 'exception' worksheet. The macro runs without issue if there I use static referencing instead. Here is the code that I am running, it gives me a runtime error for the line that copies the data.

```<code>Sub GetClassID()

Dim App As New Excel.Application

Dim wsActive As Worksheet
Set wsActive = ThisWorkbook.ActiveSheet

Dim wbImport As Workbook
Set wbImport = App.Workbooks.Open(Filename:="C:\Test.xlsx",
UpdateLinks:=True, ReadOnly:=True)

wbImport.Worksheets("Exception").Range("F2",Range("F2").end(xldown)).Copy
wsActive.Range("A2").PasteSpecial Paste:=xlPasteFormats
wsActive.Range("A2").PasteSpecial Paste:=xlPasteValues

App.CutCopyMode = False
wbImport.Close SaveChanges:=False
App.Quit

End Sub
</code>```

Error I get is runtime erorr '1004': Interface not registered

答:
In my experience, the most effective way to copy a dynamic range is to create a variable as an integer and assign the row of the last cell to be copied (or column if needing to select a row of data across to a certain point. I usually accomplish it with something like this:

```<code>Dim R as Integer
With ThisWorkbook.Worksheets
   R = .Cells(.Rows.Count, 1).End(xlUp).Row
End With
</code>```

Then you can plug in 'R' for the row number in a range to make it dynamic each time the macro is ran. For instance: .Range("A1:A" & R).Copy would copy the used range in Column A. It also makes it really easy to reference the last row for loops and such continuously throughout your code. Hope this helps!

Body:
I would like to copy a range of cells in a closed notebook that does not have a static set of rows. I would like to copy it into an active workbook.

I am trying to dynamically copy all entries under the column of F from file 'test.xlsx' from the 'exception' worksheet. The macro runs without issue if there I use static referencing instead. Here is the code that I am running, it gives me a runtime error for the line that copies the data.

Sub GetClassID()

Dim App As New Excel.Application

Dim wsActive As Worksheet
Set wsActive = ThisWorkbook.ActiveSheet

Dim wbImport As Workbook
Set wbImport = App.Workbooks.Open(Filename:="C:\Test.xlsx",
UpdateLinks:=True, ReadOnly:=True)

wbImport.Worksheets("Exception").Range("F2",Range("F2").end(xldown)).Copy
wsActive.Range("A2").PasteSpecial Paste:=xlPasteFormats
wsActive.Range("A2").PasteSpecial Paste:=xlPasteValues

App.CutCopyMode = False
wbImport.Close SaveChanges:=False
App.Quit

End Sub

Error I get is runtime erorr '1004': Interface not registered

Body:
In my experience, the most effective way to copy a dynamic range is to create a variable as an integer and assign the row of the last cell to be copied (or column if needing to select a row of data across to a certain point. I usually accomplish it with something like this:

Dim R as Integer
With ThisWorkbook.Worksheets
   R = .Cells(.Rows.Count, 1).End(xlUp).Row
End With

Then you can plug in 'R' for the row number in a range to make it dynamic each time the macro is ran. For instance: .Range("A1:A" & R).Copy would copy the used range in Column A. It also makes it really easy to reference the last row for loops and such continuously throughout your code. Hope this helps!


问:
Code snippet or shortcut to create a constructor in Visual Studio
What is the code snippet or shortcut for creating a constructor in Visual Studio?

Visual Studio 2010 and C#.

答:
I have created some handy code snippets that'll create overloaded constructors as well. You're welcome to use them: https://github.com/ejbeaty/Power-Snippets

For example: 'ctor2' would create a constructor with two arguments and allow you to tab through them one by one like this:

```<code>public MyClass(ArgType argName, ArgType argName)
{

}
</code>```

Body:
I have created some handy code snippets that'll create overloaded constructors as well. You're welcome to use them: https://github.com/ejbeaty/Power-Snippets

For example: 'ctor2' would create a constructor with two arguments and allow you to tab through them one by one like this:

public MyClass(ArgType argName, ArgType argName)
{

}


答:
To use a promise, you call .then on it and specify what code you want to run once the value is available:

```<code>function transformer(instring)
{
  var outstring = instring + instring;
  return Promise.resolve(outstring);
}

function calculate()
{
  var srcStr = document.mainform.src.value;
  transformer(srcStr)
    .then(transformed => {
      document.mainform.dst.value = transformed;
    });
}
</code>```

Alternatively, if async/await is an option you can use the await keyword in an async function. The await keyword will pause your function and wait until the promise resolves, and then resume your code. This can make for cleaner syntax, but promises are still involved.

```<code>async function calculate()
{
    var srcStr = document.mainform.src.value;
    var transformed = await transformer(srcStr);
    document.mainform.dst.value = transformed;
}
</code>```

Title: How can I implement a promise in my calculator function?

Body:
To use a promise, you call .then on it and specify what code you want to run once the value is available:

function transformer(instring)
{
  var outstring = instring + instring;
  return Promise.resolve(outstring);
}

function calculate()
{
  var srcStr = document.mainform.src.value;
  transformer(srcStr)
    .then(transformed => {
      document.mainform.dst.value = transformed;
    });
}

Alternatively, if async/await is an option you can use the await keyword in an async function. The await keyword will pause your function and wait until the promise resolves, and then resume your code. This can make for cleaner syntax, but promises are still involved.

async function calculate()
{
    var srcStr = document.mainform.src.value;
    var transformed = await transformer(srcStr);
    document.mainform.dst.value = transformed;
}


问:
create a macro variable to store all variable names of a dataset
I'm a beginner in sas.
I have a data set work.data2 with variables that include all variables from another dataset work.data1.

here is what I want to do:

```<code>data temp;
    set data2 (keep = [list of all variables in data1] key2 key3);
run;
</code>```

First I need to create a macro variable to store all variable names in data1.
if it's in python i can just do

```<code>List=list(data1)
</code>```

but it seems much harder to realize in sas...Please help. Thank you very much!

答:
There are a few ways to skin this cat.  Here's one method:

Assuming all of the variables names are stored in a variable (column) called Data2Var in work.data2, then this should work:

```<code>proc sql noprint;
select Data2Var into: VarList separated by " "
from
work.data1;
quit;

data work.temp;
set work.data2(KEEP = &VarList key1 key2);
run;
</code>```

Basically what this is doing is that the first proc sql block of code creates a macro variable that consists of every value in the column Data2Var from your work.data1 dataset and separates the values by spaces.  This macro variable (&Data2Var) is then called on your keep statement when reading in the data2 dataset.  The resulting dataset, work.temp then consists only of those values from the work.data1 column Data2Var and key1 and key2.

Body:
I'm a beginner in sas.
I have a data set work.data2 with variables that include all variables from another dataset work.data1.

here is what I want to do:

data temp;
    set data2 (keep = [list of all variables in data1] key2 key3);
run;

First I need to create a macro variable to store all variable names in data1.
if it's in python i can just do

List=list(data1)

but it seems much harder to realize in sas...Please help. Thank you very much!

Body:
There are a few ways to skin this cat.  Here's one method:

Assuming all of the variables names are stored in a variable (column) called Data2Var in work.data2, then this should work:

proc sql noprint;
select Data2Var into: VarList separated by " "
from
work.data1;
quit;

data work.temp;
set work.data2(KEEP = &VarList key1 key2);
run;

Basically what this is doing is that the first proc sql block of code creates a macro variable that consists of every value in the column Data2Var from your work.data1 dataset and separates the values by spaces.  This macro variable (&Data2Var) is then called on your keep statement when reading in the data2 dataset.  The resulting dataset, work.temp then consists only of those values from the work.data1 column Data2Var and key1 and key2.